@@ -1432,8 +1432,9 @@ class OMCSessionPort(OMCSessionABC):
14321432 def __init__ (
14331433 self ,
14341434 omc_port : str ,
1435+ timeout : float = 10.0 ,
14351436 ) -> None :
1436- super ().__init__ ()
1437+ super ().__init__ (timeout = timeout )
14371438 self ._omc_port = omc_port
14381439
14391440
@@ -1596,7 +1597,9 @@ class OMCSessionDockerABC(OMCSessionABC, metaclass=abc.ABCMeta):
15961597
15971598 def __init__ (
15981599 self ,
1599- timeout : float = 10.00 ,
1600+ timeout : float = 10.0 ,
1601+ docker : Optional [str ] = None ,
1602+ dockerContainer : Optional [str ] = None ,
16001603 dockerExtraArgs : Optional [list ] = None ,
16011604 dockerOpenModelicaPath : str | os .PathLike = "omc" ,
16021605 dockerNetwork : Optional [str ] = None ,
@@ -1610,11 +1613,21 @@ def __init__(
16101613 self ._docker_extra_args = dockerExtraArgs
16111614 self ._docker_open_modelica_path = pathlib .PurePosixPath (dockerOpenModelicaPath )
16121615 self ._docker_network = dockerNetwork
1616+ self ._docker_container_id : str
1617+ self ._docker_process : Optional [DockerPopen ]
16131618
1614- self ._interactive_port = port
1619+ # start up omc executable in docker container waiting for the ZMQ connection
1620+ self ._omc_process , self ._docker_process , self ._docker_container_id = self ._docker_omc_start (
1621+ docker_image = docker ,
1622+ docker_cid = dockerContainer ,
1623+ omc_port = port ,
1624+ )
1625+ # connect to the running omc instance using ZMQ
1626+ self ._omc_port = self ._omc_port_get (docker_cid = self ._docker_container_id )
1627+ if port is not None and not self ._omc_port .endswith (f":{ port } " ):
1628+ raise OMCSessionException (f"Port mismatch: { self ._omc_port } is not using the defined port { port } !" )
16151629
1616- self ._docker_container_id : Optional [str ] = None
1617- self ._docker_process : Optional [DockerPopen ] = None
1630+ self ._cmd_prefix = self .model_execution_prefix ()
16181631
16191632 def _docker_process_get (self , docker_cid : str ) -> Optional [DockerPopen ]:
16201633 if sys .platform == 'win32' :
@@ -1640,6 +1653,15 @@ def _docker_process_get(self, docker_cid: str) -> Optional[DockerPopen]:
16401653
16411654 return docker_process
16421655
1656+ @abc .abstractmethod
1657+ def _docker_omc_start (
1658+ self ,
1659+ docker_image : Optional [str ] = None ,
1660+ docker_cid : Optional [str ] = None ,
1661+ omc_port : Optional [int ] = None ,
1662+ ) -> Tuple [subprocess .Popen , DockerPopen , str ]:
1663+ pass
1664+
16431665 @staticmethod
16441666 def _getuid () -> int :
16451667 """
@@ -1651,11 +1673,14 @@ def _getuid() -> int:
16511673 # Windows, hence the type: ignore comment.
16521674 return 1000 if sys .platform == 'win32' else os .getuid () # type: ignore
16531675
1654- def _omc_port_get (self ) -> str :
1676+ def _omc_port_get (
1677+ self ,
1678+ docker_cid : str ,
1679+ ) -> str :
16551680 port = None
16561681
1657- if not isinstance (self . _docker_container_id , str ):
1658- raise OMCSessionException (f"Invalid docker container ID: { self . _docker_container_id } " )
1682+ if not isinstance (docker_cid , str ):
1683+ raise OMCSessionException (f"Invalid docker container ID: { docker_cid } " )
16591684
16601685 # See if the omc server is running
16611686 loop = self ._timeout_loop (timestep = 0.1 )
@@ -1664,7 +1689,7 @@ def _omc_port_get(self) -> str:
16641689 if omc_portfile_path is not None :
16651690 try :
16661691 output = subprocess .check_output (args = ["docker" ,
1667- "exec" , self . _docker_container_id ,
1692+ "exec" , docker_cid ,
16681693 "cat" , omc_portfile_path .as_posix ()],
16691694 stderr = subprocess .DEVNULL )
16701695 port = output .decode ().strip ()
@@ -1687,7 +1712,10 @@ def get_server_address(self) -> Optional[str]:
16871712 """
16881713 if self ._docker_network == "separate" and isinstance (self ._docker_container_id , str ):
16891714 output = subprocess .check_output (["docker" , "inspect" , self ._docker_container_id ]).decode ().strip ()
1690- return json .loads (output )[0 ]["NetworkSettings" ]["IPAddress" ]
1715+ address = json .loads (output )[0 ]["NetworkSettings" ]["IPAddress" ]
1716+ if not isinstance (address , str ):
1717+ raise OMCSessionException (f"Invalid docker server address: { address } !" )
1718+ return address
16911719
16921720 return None
16931721
@@ -1734,27 +1762,16 @@ def __init__(
17341762
17351763 super ().__init__ (
17361764 timeout = timeout ,
1765+ docker = docker ,
17371766 dockerExtraArgs = dockerExtraArgs ,
17381767 dockerOpenModelicaPath = dockerOpenModelicaPath ,
17391768 dockerNetwork = dockerNetwork ,
17401769 port = port ,
17411770 )
17421771
1743- if docker is None :
1744- raise OMCSessionException ("Argument docker must be set!" )
1745-
1746- self ._docker = docker
1747-
1748- # start up omc executable in docker container waiting for the ZMQ connection
1749- self ._omc_process , self ._docker_process , self ._docker_container_id = self ._docker_omc_start ()
1750- # connect to the running omc instance using ZMQ
1751- self ._omc_port = self ._omc_port_get ()
1752-
17531772 def __del__ (self ) -> None :
17541773
1755- super ().__del__ ()
1756-
1757- if isinstance (self ._docker_process , DockerPopen ):
1774+ if hasattr (self , '_docker_process' ) and isinstance (self ._docker_process , DockerPopen ):
17581775 try :
17591776 self ._docker_process .wait (timeout = 2.0 )
17601777 except subprocess .TimeoutExpired :
@@ -1766,29 +1783,37 @@ def __del__(self) -> None:
17661783 finally :
17671784 self ._docker_process = None
17681785
1786+ super ().__del__ ()
1787+
17691788 def _docker_omc_cmd (
17701789 self ,
1771- omc_path_and_args_list : list [ str ] ,
1790+ docker_image : str ,
17721791 docker_cid_file : pathlib .Path ,
1792+ omc_path_and_args_list : list [str ],
1793+ omc_port : Optional [int | str ] = None ,
17731794 ) -> list :
17741795 """
17751796 Define the command that will be called by the subprocess module.
17761797 """
1798+
17771799 extra_flags = []
17781800
17791801 if sys .platform == "win32" :
17801802 extra_flags = ["-d=zmqDangerousAcceptConnectionsFromAnywhere" ]
1781- if not self ._interactive_port :
1782- raise OMCSessionException ("docker on Windows requires knowing which port to connect to - "
1803+ if not self ._omc_port :
1804+ raise OMCSessionException ("Docker on Windows requires knowing which port to connect to - "
17831805 "please set the interactivePort argument" )
17841806
1807+ port : Optional [int ] = None
1808+ if isinstance (omc_port , str ):
1809+ port = int (omc_port )
1810+ elif isinstance (omc_port , int ):
1811+ port = omc_port
1812+
17851813 if sys .platform == "win32" :
1786- if isinstance (self ._interactive_port , str ):
1787- port = int (self ._interactive_port )
1788- elif isinstance (self ._interactive_port , int ):
1789- port = self ._interactive_port
1790- else :
1791- raise OMCSessionException ("Missing or invalid interactive port!" )
1814+ if not isinstance (port , int ):
1815+ raise OMCSessionException ("OMC on Windows needs the interactive port - "
1816+ f"missing or invalid value: { repr (omc_port )} !" )
17921817 docker_network_str = ["-p" , f"127.0.0.1:{ port } :{ port } " ]
17931818 elif self ._docker_network == "host" or self ._docker_network is None :
17941819 docker_network_str = ["--network=host" ]
@@ -1799,8 +1824,8 @@ def _docker_omc_cmd(
17991824 raise OMCSessionException (f'dockerNetwork was set to { self ._docker_network } , '
18001825 'but only \" host\" or \" separate\" is allowed' )
18011826
1802- if isinstance (self . _interactive_port , int ):
1803- extra_flags = extra_flags + [f"--interactivePort={ int ( self . _interactive_port ) } " ]
1827+ if isinstance (port , int ):
1828+ extra_flags = extra_flags + [f"--interactivePort={ port } " ]
18041829
18051830 omc_command = ([
18061831 "docker" , "run" ,
@@ -1810,22 +1835,33 @@ def _docker_omc_cmd(
18101835 ]
18111836 + self ._docker_extra_args
18121837 + docker_network_str
1813- + [self . _docker , self ._docker_open_modelica_path .as_posix ()]
1838+ + [docker_image , self ._docker_open_modelica_path .as_posix ()]
18141839 + omc_path_and_args_list
18151840 + extra_flags )
18161841
18171842 return omc_command
18181843
1819- def _docker_omc_start (self ) -> Tuple [subprocess .Popen , DockerPopen , str ]:
1844+ def _docker_omc_start (
1845+ self ,
1846+ docker_image : Optional [str ] = None ,
1847+ docker_cid : Optional [str ] = None ,
1848+ omc_port : Optional [int ] = None ,
1849+ ) -> Tuple [subprocess .Popen , DockerPopen , str ]:
1850+
1851+ if not isinstance (docker_image , str ):
1852+ raise OMCSessionException ("A docker image name must be provided!" )
1853+
18201854 my_env = os .environ .copy ()
18211855
18221856 docker_cid_file = self ._temp_dir / (self ._omc_filebase + ".docker.cid" )
18231857
18241858 omc_command = self ._docker_omc_cmd (
1859+ docker_image = docker_image ,
1860+ docker_cid_file = docker_cid_file ,
18251861 omc_path_and_args_list = ["--locale=C" ,
18261862 "--interactive=zmq" ,
18271863 f"-z={ self ._random_string } " ],
1828- docker_cid_file = docker_cid_file ,
1864+ omc_port = omc_port ,
18291865 )
18301866
18311867 omc_process = subprocess .Popen (omc_command ,
@@ -1836,6 +1872,7 @@ def _docker_omc_start(self) -> Tuple[subprocess.Popen, DockerPopen, str]:
18361872 if not isinstance (docker_cid_file , pathlib .Path ):
18371873 raise OMCSessionException (f"Invalid content for docker container ID file path: { docker_cid_file } " )
18381874
1875+ # the provided value for docker_cid is not used
18391876 docker_cid = None
18401877 loop = self ._timeout_loop (timestep = 0.1 )
18411878 while next (loop ):
@@ -1846,10 +1883,12 @@ def _docker_omc_start(self) -> Tuple[subprocess.Popen, DockerPopen, str]:
18461883 pass
18471884 if docker_cid is not None :
18481885 break
1849- else :
1850- logger .error (f"Docker did not start. Log-file says:\n { self .get_log ()} " )
1886+ time .sleep (self ._timeout / 40.0 )
1887+
1888+ if docker_cid is None :
18511889 raise OMCSessionException (f"Docker did not start (timeout={ self ._timeout } might be too short "
1852- "especially if you did not docker pull the image before this command)." )
1890+ "especially if you did not docker pull the image before this command). "
1891+ f"Log-file says:\n { self .get_log ()} " )
18531892
18541893 docker_process = self ._docker_process_get (docker_cid = docker_cid )
18551894 if docker_process is None :
@@ -1876,64 +1915,71 @@ def __init__(
18761915
18771916 super ().__init__ (
18781917 timeout = timeout ,
1918+ dockerContainer = dockerContainer ,
18791919 dockerExtraArgs = dockerExtraArgs ,
18801920 dockerOpenModelicaPath = dockerOpenModelicaPath ,
18811921 dockerNetwork = dockerNetwork ,
18821922 port = port ,
18831923 )
18841924
1885- if not isinstance (dockerContainer , str ):
1886- raise OMCSessionException ("Argument dockerContainer must be set!" )
1887-
1888- self ._docker_container_id = dockerContainer
1889-
1890- # start up omc executable in docker container waiting for the ZMQ connection
1891- self ._omc_process , self ._docker_process = self ._docker_omc_start ()
1892- # connect to the running omc instance using ZMQ
1893- self ._omc_port = self ._omc_port_get ()
1894-
18951925 def __del__ (self ) -> None :
18961926
18971927 super ().__del__ ()
18981928
18991929 # docker container ID was provided - do NOT kill the docker process!
19001930 self ._docker_process = None
19011931
1902- def _docker_omc_cmd (self , omc_path_and_args_list ) -> list :
1932+ def _docker_omc_cmd (
1933+ self ,
1934+ docker_cid : str ,
1935+ omc_path_and_args_list : list [str ],
1936+ omc_port : Optional [int ] = None ,
1937+ ) -> list :
19031938 """
19041939 Define the command that will be called by the subprocess module.
19051940 """
19061941 extra_flags : list [str ] = []
19071942
19081943 if sys .platform == "win32" :
19091944 extra_flags = ["-d=zmqDangerousAcceptConnectionsFromAnywhere" ]
1910- if not self . _interactive_port :
1945+ if not isinstance ( omc_port , int ) :
19111946 raise OMCSessionException ("Docker on Windows requires knowing which port to connect to - "
19121947 "Please set the interactivePort argument. Furthermore, the container needs "
19131948 "to have already manually exposed this port when it was started "
19141949 "(-p 127.0.0.1:n:n) or you get an error later." )
19151950
1916- if isinstance (self . _interactive_port , int ):
1917- extra_flags = extra_flags + [f"--interactivePort={ int ( self . _interactive_port ) } " ]
1951+ if isinstance (omc_port , int ):
1952+ extra_flags = extra_flags + [f"--interactivePort={ omc_port } " ]
19181953
19191954 omc_command = ([
19201955 "docker" , "exec" ,
19211956 "--user" , str (self ._getuid ()),
19221957 ]
19231958 + self ._docker_extra_args
1924- + [self . _docker_container_id , self ._docker_open_modelica_path .as_posix ()]
1959+ + [docker_cid , self ._docker_open_modelica_path .as_posix ()]
19251960 + omc_path_and_args_list
19261961 + extra_flags )
19271962
19281963 return omc_command
19291964
1930- def _docker_omc_start (self ) -> Tuple [subprocess .Popen , DockerPopen ]:
1965+ def _docker_omc_start (
1966+ self ,
1967+ docker_image : Optional [str ] = None ,
1968+ docker_cid : Optional [str ] = None ,
1969+ omc_port : Optional [int ] = None ,
1970+ ) -> Tuple [subprocess .Popen , DockerPopen , str ]:
1971+
1972+ if not isinstance (docker_cid , str ):
1973+ raise OMCSessionException ("A docker container ID must be provided!" )
1974+
19311975 my_env = os .environ .copy ()
19321976
19331977 omc_command = self ._docker_omc_cmd (
1978+ docker_cid = docker_cid ,
19341979 omc_path_and_args_list = ["--locale=C" ,
19351980 "--interactive=zmq" ,
19361981 f"-z={ self ._random_string } " ],
1982+ omc_port = omc_port ,
19371983 )
19381984
19391985 omc_process = subprocess .Popen (omc_command ,
@@ -1942,14 +1988,14 @@ def _docker_omc_start(self) -> Tuple[subprocess.Popen, DockerPopen]:
19421988 env = my_env )
19431989
19441990 docker_process = None
1945- if isinstance (self . _docker_container_id , str ):
1946- docker_process = self ._docker_process_get (docker_cid = self . _docker_container_id )
1991+ if isinstance (docker_cid , str ):
1992+ docker_process = self ._docker_process_get (docker_cid = docker_cid )
19471993
19481994 if docker_process is None :
19491995 raise OMCSessionException (f"Docker top did not contain omc process { self ._random_string } "
1950- f"/ { self . _docker_container_id } . Log-file says:\n { self .get_log ()} " )
1996+ f"/ { docker_cid } . Log-file says:\n { self .get_log ()} " )
19511997
1952- return omc_process , docker_process
1998+ return omc_process , docker_process , docker_cid
19531999
19542000
19552001class OMCSessionWSL (OMCSessionABC ):
@@ -1977,6 +2023,8 @@ def __init__(
19772023 # connect to the running omc instance using ZMQ
19782024 self ._omc_port = self ._omc_port_get ()
19792025
2026+ self ._cmd_prefix = self .model_execution_prefix ()
2027+
19802028 def model_execution_prefix (self , cwd : Optional [OMPathABC ] = None ) -> list [str ]:
19812029 """
19822030 Helper function which returns a command prefix needed for docker and WSL. It defaults to an empty list.
@@ -2000,7 +2048,8 @@ def _omc_process_get(self) -> subprocess.Popen:
20002048 self ._wsl_omc ,
20012049 "--locale=C" ,
20022050 "--interactive=zmq" ,
2003- f"-z={ self ._random_string } " ]
2051+ f"-z={ self ._random_string } " ,
2052+ ]
20042053
20052054 omc_process = subprocess .Popen (omc_command ,
20062055 stdout = self ._omc_loghandle ,
0 commit comments