
    VhY                       U d Z ddlmZ ddlmZ ddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlmZmZmZmZ ddlmZmZ ddlmZmZmZmZmZmZ ddlmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z- dd	l.m/Z/ dd
l0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6m7Z7m8Z8m9Z9 ddl:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZA ddlBmCZC ddlDmEZE i ZFdeGd<    ej                         ZI G d d      ZJ	 	 	 	 	 	 	 d1	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d2dZK	 	 d3	 	 	 	 	 	 	 	 	 	 	 	 	 d4dZLd5dZMd6dZNeEd7d       ZOd8dZPeEd9d       ZQ G d d      ZR G d d      ZSd:dZTd;d ZUd9d!ZV G d" d#      ZWej                  	 	 	 	 	 	 d<d$       ZY	 	 	 	 	 	 	 	 d=d%ZZ G d& d'      Z[ G d( d)      Z\	 d>	 	 	 	 	 	 	 	 	 	 	 	 	 d?d*Z]d@d+Z^dAd,Z_	 	 	 	 	 	 	 	 dBd-Z`dCd.Za	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dDd/Zb	 	 	 	 	 	 	 	 	 	 	 	 	 	 dEd0Zcy)Fz1High level functions for working with containers.    )annotationsN   )ApplicationErrorSubprocessErrordisplaysanitize_host_name)ExitHandlernamed_temporary_file)EnvironmentConfigIntegrationConfigSanityConfigShellConfigUnitsConfigWindowsIntegrationConfig)ContainerNotFoundErrorDockerInspectdocker_createdocker_execdocker_inspectdocker_network_inspectdocker_pull	docker_rm
docker_rundocker_startget_docker_container_idget_docker_host_ipget_podman_host_ipget_session_container_namerequire_dockerdetect_host_properties)run_playbook)SshKey)IntegrationTarget)SshConnectionDetail
SshProcesscreate_ssh_port_forwardscreate_ssh_port_redirectsgenerate_ssh_inventory)ControllerConfigDockerConfigOriginConfigPosixSshConfigPythonConfigRemoteConfigWindowsInventoryConfig)SshConnection)mutexzdict[str, ContainerDescriptor]support_containersc                      e Zd ZdZdZdZdZy)HostTypez?Enum representing the types of hosts involved in running tests.origincontrolmanagedN)__name__
__module____qualname____doc__r5   r6   r7        Q/home/dcms/DCMS/lib/python3.12/site-packages/ansible_test/_internal/containers.pyr4   r4   `   s    IFGGr=   r4   c                X   t        | |      }| j                  rt        | |       yt        |        |xs t	        |      g}t               j                  }t               }|dk(  r<t        | j                  t              rt        d | j                  D              rd}|rd}|
xs g }
|r|
j                  d       |r#|D ]  }|
j                  dt        |      g         |	r0|	j!                         D ]  \  }}|
j                  d|d|g        t#        |       j$                  }|
j                  d	d
|z  g       | j&                  r|
j                  d       t)        j*                  d|z         t        | |       t-        | |||
| |      }|}t/        ||||||||||	
      }t0        5  |t2        v rt5        d|       t2        st7        j8                  t:        |        |t2        |<   ddd       t)        j*                  d| d       |r|j9                  |        |S # 1 sw Y   7xY w)z
    Start a container used to support tests, but not run them.
    Containers created this way will be accessible from tests.
    Ndockerc              3  H   K   | ]  }t        |t        t        f        y wN)
isinstancer)   r*   ).0targets     r>   	<genexpr>z(run_support_container.<locals>.<genexpr>   s%       =Nv|ZQacoPp=q  =N    "Fz-dtz-p--env=z--ulimitz	nofile=%s)rH   zSYSTEMD_LOG_LEVEL=debugzStarting new "%s" container.)create_onlycmdzContainer already defined: zAdding "z" to container database.)r   prime_containersr   r"   r   r   commandr   rC   
controllerr*   alltargetsappendextendstritemsr    max_open_filesdev_systemd_debugr   inforun_containerContainerDescriptorsupport_containers_mutexr2   	Exceptionr	   registercleanup_containers)argscontextimagenameportsaliasesstartcleanuprK   envoptionspublish_portsdocker_commandcurrent_container_idportkeyvaluerU   support_container_idrunning
descriptors                        r>   run_support_containerrq   h   s=   $ &dD1DD%  4L3,T23G#%--N24!doo|4  =N  AE  AM  AM  =N  :N!M!MmGu 	.DNND#d),-	. ))+ 	>JCNNGU%;<=	> ,D1@@NNNJn <=>;<LL/$67e(udGUZQZ`cdG$J 
" .%%9$@AA!  !3T:#-4 . LL8D6!9:;D!. .s   *A H  H)c                   t        |xs g       }t        |xs g       }|j                  d|g       t        |       }t        |      r|j                  d|g       t	        dd      D ]f  }	 |rt        | |||      d   }nt        | |||      d   }| j                  r!dj                  d t	        d      D              }|j                         c S  t%        d	| d      # t        $ rc}	t        j                  |	j                         t        j                  d	| d
       t        | |       t!        j"                  d       Y d}	~	d}	~	ww xY w)z-Run a container using the given docker image.z--namez	--networkr      r    c              3  F   K   | ]  }t        j                  d         yw)0123456789abcdefN)randomchoice)rD   
_iterations     r>   rF   z run_container.<locals>.<genexpr>   s      _z/A!B _   !@   zFailed to run docker image "-". Waiting a few seconds before trying again.N".)listrR   !get_docker_preferred_network_nameis_docker_user_defined_networkranger   r   explainjoinstripr   r   errormessagewarningr   timesleepr   )
r^   r`   ra   rg   rK   rJ   networkry   stdoutexs
             r>   rX   rX      s1    7=b!G
syb/CNNHd#$/5G%g.W-.Aqk "
	"&tUGSA!D#D%#>qA || _UZ[]U^ __<<>!"" 9%C
DD  	MM"**%OO:5'AnopdD!JJqMM		s   +%C	E(AEEc                *   g }t        dd      D ]  }	 t        | ||      c S  t        d| d      # t        $ rW}t        j                  |j
                         t        j                  d| d       t        j                  d       Y d}~~d}~ww xY w)z'Start a docker container by name or ID.r   rs   z"Failed to start docker container "r|   Nr}   )
r   r   r   r   r   r   r   r   r   r   )r^   container_idrg   ry   r   s        r>   start_containerr      s    GAqk 
	lG<< ?~RP
QQ  	MM"**%OO@N{|}JJqMM	s   2	BABBc                    |j                   rRt        |       }|s2t        |j                   j                               j	                  d      }|j                   |   d   }n|j
                  d   }|sy|S )zHReturn the IP address of the container for the preferred docker network.r   	IPAddressN)networksr   sortedkeyspopnetwork_settings)r^   	containernetwork_name	ipaddresss       r>   get_container_ip_addressr      so    8> ")"4"4"9"9";<@@CL&&|4[A	..{;	r=   c                   	 t         j                  S # t        $ r Y nw xY wd}| j                  r| j                  }nPt	               }|rD	 t        | |d      }|j                         }n$# t        $ r t        j                  d       Y nw xY w|'t               j                  dk(  rt        | dd      rd}|t         _        |S )a  
    Return the preferred network name for use with Docker. The selection logic is:
    - the network selected by the user with `--docker-network`
    - the network of the currently running docker container (if any)
    - the default docker network (returns None)
    NT)alwayszxUnable to detect the network for the current container. Use the `--docker-network` option if containers are unreachable.podman)r   r   AttributeErrordocker_networkr   r   get_network_namer   r   r   r   rM   r   )r^   r   rj   r   s       r>   r   r     s    0888  G%%68\ +41EdS	#446) \  ![  \\ >+33x?DZ[_airvDw07%-Ns    		A( (B	B	c                &    t        |       xr | dk7  S )z@Return True if the network being used is a user-defined network.bridge)bool)r   s    r>   r   r   <  s    =0W00r=   ContainerDatabasec                   	 t         j                  S # t        $ r Y nw xY w| j                  rJt	        j
                  dd       t        j                  t        j                  | j                              }n"t	        j
                  dd       t        |       }t	        j
                  dt        j                  |j                         dd      z  d	       |t         _        |S )
zReturn the current container database, creating it as needed, or returning the one provided on the command line through delegation.zParsing container database.r   	verbosityzCreating container database.z>>> Container Database
%s   Tindent	sort_keysrs   )get_container_databasedatabaser   
containersr   rW   r   	from_dictjsonloadscreate_container_databasedumpsto_dict)r^   r   s     r>   r   r   A  s    %...  2a@$..tzz$///JK3qA,T2LL-

8;K;K;MVWcg0hhtuv&.#Os    	c                  :    e Zd ZdZddZddZed	d       Zd
dZy)ContainerAccesszSInformation needed for one test host to access a single container supporting tests.c                <    || _         || _        || _        || _        y rB   host_ipnamesrb   forwards)selfr   r   rb   r   s        r>   __init__zContainerAccess.__init__Z  s&      
 
 !r=   c                    | j                   r%t        | j                   j                               }|S | j                  D cg c]  }||f }}|S c c}w )z/Return a port map for accessing this container.)r   r~   rT   rb   )r   rb   rk   s      r>   port_mapzContainerAccess.port_mapk  sN    ==,,./E  /3jj9ddD\9E9 :s    Ac                    | j                  d      }|r t        d |j                         D              }t        | d   | d   | j                  d      |      S )z6Return a ContainerAccess instance from the given dict.r   c              3  <   K   | ]  \  }}t        |      |f  y wrB   intrD   rl   rm   s      r>   rF   z,ContainerAccess.from_dict.<locals>.<genexpr>z  s     Q*#uSXu-Qs   r   r   rb   r   )getdictrT   r   )datar   s     r>   r   zContainerAccess.from_dictt  sV     88J'Q@PQQHOw-((7#	
 	
r=   c                    t        | j                  | j                        }| j                  r|j	                  | j                         | j
                  r|j	                  | j
                         |S )&Return a dict of the current instance.)r   r   )rb   )r   )r   r   r   rb   updater   )r   rm   s     r>   r   zContainerAccess.to_dict  sS    "&LL**#

 ::LLtzzL*==LL$--L0r=   N)
r   rS   r   	list[str]rb   zt.Optional[list[int]]r   zt.Optional[dict[int, int]]returnNone)r   zlist[tuple[int, int]])r   dict[str, t.Any]r   r   r   r   )	r8   r9   r:   r;   r   r   staticmethodr   r   r<   r=   r>   r   r   W  s(    ]!" 
 
r=   r   c                  2    e Zd ZdZddZedd       ZddZy)	r   z5Database of running containers used to support tests.c                    || _         y rB   r   )r   r   s     r>   r   zContainerDatabase.__init__  s	    	r=   c                T    t        t        d | j                         D                    S )z8Return a ContainerDatabase instance from the given dict.c              3  f   K   | ])  \  }}|t        d  |j                         D              f + yw)c              3  f   K   | ])  \  }}|t        d  |j                         D              f + yw)c              3  P   K   | ]  \  }}|t         j                  |      f   y wrB   )r   r   rD   container_namer   s      r>   rF   zBContainerDatabase.from_dict.<locals>.<genexpr>.<genexpr>.<genexpr>  s0      2g6Oni 4B?C\C\]fCg2h 2gs   $&Nr   rT   rD   context_namer   s      r>   rF   z8ContainerDatabase.from_dict.<locals>.<genexpr>.<genexpr>  sH      ,^ 1Ij .:-1 2gS]ScScSe2g .g-h ,^   /1Nr   rD   access_namecontextss      r>   rF   z.ContainerDatabase.from_dict.<locals>.<genexpr>  sJ      &Q
 +@+x (3'+ ,^ MUNNL\,^ (^'_ &Qr   )r   r   rT   r   s    r>   r   zContainerDatabase.from_dict  s4     ! &Q
 DH::<&Q "Q R 	Rr=   c                V    t        d | j                  j                         D              S )r   c              3  f   K   | ])  \  }}|t        d  |j                         D              f + yw)c              3  f   K   | ])  \  }}|t        d  |j                         D              f + yw)c              3  F   K   | ]  \  }}||j                         f  y wrB   )r   r   s      r>   rF   z@ContainerDatabase.to_dict.<locals>.<genexpr>.<genexpr>.<genexpr>  s,       U$=NI "01B1B1D E  Urz   Nr   r   s      r>   rF   z6ContainerDatabase.to_dict.<locals>.<genexpr>.<genexpr>  sG      L 7lJ (  UAKAQAQAS U UV Lr   Nr   r   s      r>   rF   z,ContainerDatabase.to_dict.<locals>.<genexpr>  sH      D
 .X ! L ;C..:JL LM Dr   )r   r   rT   r   s    r>   r   zContainerDatabase.to_dict  s-     D
 261BD D 	Dr=   N)r   z0dict[str, dict[str, dict[str, ContainerAccess]]]r   r   )r   r   r   r   r   )r8   r9   r:   r;   r   r   r   r   r<   r=   r>   r   r     s&    ? R RDr=   c           	     \    t        ddddt        |       j                  |j                        S )zXReturn SSH connection details for localhost, connecting as root to the default SSH port.	localhostNroot)r$   r"   rl   path)r^   pythons     r>   	local_sshr     s(    {Kvvd|GWGWY_YdYdeer=   c                    | j                   j                  j                         }| j                  r|j	                  d       t        di |S )z}Return the SSH connection details from the given SSH connection. If become was specified, the user will be changed to `root`.r   )userr<   )settings__dict__copybecomer   r$   )sshr   s     r>   root_sshr     sE    ||$$))+H
zz 	 	
 ***r=   c                |   i }i }i }t         j                         D ]B  \  }}|j                  j                  rut	               j
                  dk(  rt        }nt        }t         |       |j                  dt        d |j                  j                  j                         D                    }nd}|j                  j                  r8t        |j                  j                  |j                  |j                  d      }nmt	               j
                  dk(  rTt        t               |j                  dt        d |j                  j                  j                         D                    }nd}t               r2|st        d|z        |j                  |j                   i       }	||	|<   n$|sn!|j                  |j                   i       }	||	|<   t#        | j$                  t&              rnd|v rnt#        | j$                  t(              s$t#        | j$                  t*              r<t               r2|r"|j                  |j                   i       }
||
|<   n?t        d|z        |st        d|z        |j                  |j                   i       }
||
|<   t-        | j.                  t&        t0        t2        f      rd|v sd	|v rt-        | j.                  t(              s$t-        | j.                  t*              r=t               r3|r#|j                  |j                   i       }|||<   t        d|z        |st        d|z        |j                  |j                   i       }|||<   E t4        j6                  |t4        j8                  |t4        j:                  |i}t        d
 |j                         D              }t=        |      S )zCreate and return a container database with information necessary for all test hosts to make use of relevant support containers.r   Nc              3  *   K   | ]  \  }}||f  y wrB   r<   rD   rk   published_ports      r>   rF   z,create_container_database.<locals>.<genexpr>       {9M~t^4{   r   c              3  *   K   | ]  \  }}||f  y wrB   r<   r   s      r>   rF   z,create_container_database.<locals>.<genexpr>  r   r   z$Missing IP address for container: %s-controller-z)Missing published ports for container: %sz-target-c              3  0   K   | ]  \  }}|s	||f  y wrB   r<   r   s      r>   rF   z,create_container_database.<locals>.<genexpr>  s     EeueEs   
	)r2   rT   detailspublished_portsr   rM   r   r   r   rc   r   container_iprb   r   r[   
setdefaultr_   rC   rN   r.   r*   r+   
issubclasstarget_typer/   r,   r4   r5   r6   r7   r   )r^   r5   r6   r7   ra   r   host_ip_funcpublished_accesscontainer_accessorigin_contextcontrol_contextmanaged_contextr   s                r>   r   r     sc   46F57G57G-335 N5i,,''8311.$''{QZQbQbQrQrQxQxQz{{	   $)).!))66''oo	  %%1.*,''{QZQbQbQrQrQxQxQz{{	   $"$# F MNN#..y/@/@"EN#3N4 !#..y/@/@"EN#3N4 doo|4t#6:dooWc;d  jA  jC")"4"4Y5F5F"K(8% F MNN# Kd RSS%001B1BBGO$4OD!d&&7M~(^_t#zT'9((,7JtGWGWYe<f  lC  lE")"4"4Y5F5F"K(8% F MNN# Kd RSS%001B1BBGO$4OD!]N5b 	''D Etzz|EEDT""r=   c                       e Zd ZdZddZddZy)SupportContainerContextzQContext object for tracking information relating to access of support containers.c                     || _         || _        y rB   )r   process)r   r   r  s      r>   r   z SupportContainerContext.__init__"  s    $r=   c                    | j                   sy| j                   j                          t        j                  dd       | j                   j	                          y)z0Close the process maintaining the port forwards.NzAWaiting for the session SSH port forwarding process to terminate.r   r   )r  	terminater   rW   waitr   s    r>   closezSupportContainerContext.close&  s<    || Xdefr=   N)r   r   r  zt.Optional[SshProcess]r   r   )r   r   )r8   r9   r:   r;   r   r  r<   r=   r>   r
  r
    s    [	r=   r
  c              #  "  K   t        | t        t        t        t        f      sd yt        |       }|j                  st        i        yt        | ||      }	 |j                   |j                          y# |j                          w xY ww)zKCreate a context manager for integration tests that use support containers.N)rC   r   r   r   r   r   r   r    create_support_container_contextr   r  )r^   r   r   r_   s       r>   support_container_contextr  2  st      d.\;WX
'-J??##.tS*EG   s   ABA: )B:BBc           
        t         j                  }t        |j                  j	                               }|j                  j                  t         j                  d      }i }||j                  vrn|st        d      |j                         D ]N  \  }}|j                         D ]6  \  }	}
d|	v r|
j                         D ]  \  }}||	|f||
j                  |f<    8 P |st        |d      S |st        d|z        t        |j                               }t        | ||      }t        ||      }	 |j                         }i }|j                         D ]  \  }}|\  }}|||f   \  }}	}||   |	   }
|j!                  |i       }|j!                  |	t#        d|
j$                  di             }||j&                  |<   t)        j*                  d|	||||fz  d        ||j                  |<   |S # t        $ r |j-                           w xY w)	zTContext manager that provides SSH port forwards. Returns updated container metadata.Nz!Missing origin container details.r   \The %s host was not pre-configured for container access and SSH forwarding is not available.	127.0.0.1zKContainer "%s" port %d available at %s:%d is forwarded over SSH as port %d.r   r   )r4   r6   r   r   r   r   r5   r[   rT   r   r   r
  r~   r   r&   collect_port_forwardsr   r   r   r   r   rW   r  )r^   r   r   	host_typerevisedsourcecontainer_mapr   r_   r   r   rk   access_portr   r  resultport_forwardsr   forwardforwarded_portaccess_hostcontainer_portforwarded_containers                          r>   r  r  J  sI      I
 4 4 67G\\hoot4FACM$?@@%+\\^ 	k!L'-4]]_ k)	!^3)2););)= k%D+GSUceiFjM9#4#4k"BCk	k	k &w55v  zC  C  D  	DM&&()H&tS(;G$Wg6F557:<'4':':'< 	#G^'.$K;H+WbIc;d8L..|,^<I)),;G")"4"4^_U`bkbqbqswy{E|"};I((8LLf[.j 	 #+Y s   -B:G( (Hc                  T    e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZddZy)	rY   z&Information about a support container.c                    || _         || _        || _        || _        || _        || _        || _        || _        |	| _        |
| _	        d | _
        y rB   )r`   r_   ra   r   rb   rc   rh   ro   re   rf   r   )r   r`   r_   ra   r   rb   rc   rh   ro   re   rf   s              r>   r   zContainerDescriptor.__init__  sS     
	(
*59r=   c                R    t        || j                         | j                  |       y)zLStart the container. Used for containers which are created, but not started.N)r   ra   r\   )r   r^   s     r>   rd   zContainerDescriptor.start  s    dii(dr=   c                \     j                   rt        d j                  z        	 t        | j                        t        |      } j                  rt        fd j                  D              }t        d	 |j                         D              r$t!        d
t#        j$                  |dd      z        t        d |j                         D              }ni }t'        ||       _          j                   S # t        $ r |j
                  s t        |t         j                  t        dt         fd j                  D                    t         j                  r9 j                  j                         D cg c]  \  }}|d| nc c}}w c}}ng                   Y lw xY w)zZRecord the container's runtime details. Must be used after the container has been started.z Container already registered: %sr  c              3     K   | ]8  }d |z  t        j                  rt        j                  dd      n|      gf : yw)z%d/tcpi0u  i@  )HostPortN)r   rh   rw   randint)rD   rk   r   s     r>   rF   z/ContainerDescriptor.register.<locals>.<genexpr>  sE       X  EI4$`d`r`ruV[@\x|2}1~  Xs   >A)r   PortsrI   )Env)IdNetworkSettingsConfigc              3  D   K   | ]  }|j                  |      f  y wrB   )get_tcp_port)rD   rk   r   s     r>   rF   z/ContainerDescriptor.register.<locals>.<genexpr>  s!     YddI$:$:4$@AYs    c              3  b   K   | ]'  }| xs t        t        d  |D                    dk7   ) yw)c              3  &   K   | ]	  }|d      yw)r)  Nr<   )rD   confs     r>   rF   z9ContainerDescriptor.register.<locals>.<genexpr>.<genexpr>  s     (Mdj)9(Ms   r   N)lenset)rD   configs     r>   rF   z/ContainerDescriptor.register.<locals>.<genexpr>  s1     uX^v:SS(Mf(M%M!NRS!SSus   -/z?Unexpected `docker inspect` results for published TCP ports:
%sr   Tr   c              3  H   K   | ]  \  }}|t        |d    d         f  yw)r   r)  Nr   )rD   rk   r7  s      r>   rF   z/ContainerDescriptor.register.<locals>.<genexpr>  s(     "l,$PVD#fQi
.C*D#E"lrG   )r   r[   ra   r   r   r   r   r   r   rb   rf   rT   r   rh   anyvaluesr   r   r   SupportContainer)r   r^   rl   rm   support_container_ip	tcp_portsr   r   s   `      @r>   r\   zContainerDescriptor.register  s   <<>JKK	&tTYY7I"  8iHYdjjYYIubkbrbrbtuu&'ilplvlv  xA  JK  W[  m\  (\  ]  ]""lZcZiZiZk"llO O' 
 ||G & 	<< &dD$$ $)  X  MQ  MW  MW  X  X! W[W_W_$((..BRSJCC/SSeg	- 	I	s   C9 9BF+;FF+*F+N)r`   rS   r_   rS   ra   rS   r   rS   rb   	list[int]rc   r   rh   r   ro   r   re   r   rf   t.Optional[dict[str, str]]r   r   r^   r   r   r   )r^   r   r   r;  )r8   r9   r:   r;   r   rd   r\   r<   r=   r>   rY   rY     s    0:: : 	:
 : : : : : : (: 
:2*r=   rY   c                  (    e Zd ZdZ	 	 	 	 	 	 	 	 ddZy)r;  zIInformation about a running support container available for use by tests.c                .    || _         || _        || _        y rB   )r   r   r   )r   r   r   r   s       r>   r   zSupportContainer.__init__  s     #(.r=   N)r   r   r   rS   r   zdict[int, int]r   r   )r8   r9   r:   r;   r   r<   r=   r>   r;  r;    s0    S/ / / (	/
 
/r=   r;  c                   t        j                  d|d|       t        d|      D ]B  }|dkD  rt        j                  |       	 t        | |dd|z  gd      d   }|r	 ||      s@|c S  t        d	|d|      # t        $ r Y aw xY w)
zcWait for the specified file to become available in the requested container and return its contents.zWaiting for container "z" to provide file: r   ddzif=%sT)capturer   zTimeout waiting for container ")r   rW   r   r   r   r   r   r   )r^   r   r   r   triescheckry   r   s           r>   wait_for_filerH    s     LL^UYZ[Auo 

>JJu	 ~gn7MW[\]^_F fM
 Wegkl
mm  		s   A>>	B
	B
c                |    t         j                         D ]%  }|j                  st        | |j                         ' y)zClean up containers.N)r2   r:  re   r   ra   )r^   r   s     r>   r]   r]     s1    '..0 ,	dINN+,r=   c                    g }t        j                         }| j                         D ]O  }|j                  rd}n|j                  }|j                  |ddj                  |j                        d|       Q |S )z/Return hosts entries for the specified context.r   z # ansible-test )uuiduuid4r:  r   r   rQ   r   r   )r_   entries	unique_idr   r   s        r>   create_hosts_entriesrP    sk    G

I^^% d	!G''GGSXXioo=VXabcd Nr=   c           
     p   	
 t               }|j                  j                  t        j                        ro|j                  j                  t        j
                        		st              	dt         t              rdndi i 
d 	
f	d}d 
fd}||fS d\  }}||fS )zfReturn pre and post target callbacks for enabling and disabling container access for each test target.posixwindowsc           	        	 t        dz  | t        j                         t        d	z  | t        j                         y)zIConfigure hosts for SSH port forwarding required by the specified target.z%s_hosts_prepare.ymlN)forward_ssh_portsr4   r6   r7   )
rE   r^   control_connectionscontrol_contextscontrol_statecontrol_typemanaged_connectionsmanaged_contextsmanaged_statemanaged_types
    r>   
pre_targetz*create_container_hooks.<locals>.pre_target/  sm    d$79OR^9^`mouw  xH  xH  JZ  [d$79OR^9^`mouw  xH  xH  JZ  [r=   c                    t        dz  | t        j                         t        dz  | t        j                         y)z^Clean up previously configured SSH port forwarding which was required by the specified target.z%s_hosts_restore.ymlN)cleanup_ssh_portsr4   r6   r7   )rE   r^   rV  rX  rY  rZ  r\  r]  s    r>   post_targetz+create_container_hooks.<locals>.post_target4  s_    d$79OR^9^`mouw  xH  xH  Id$79OR^9^`mouw  xH  xH  Ir=   )NN)rE   r#   r   r   )	r   r   r   r4   r6   r7   create_managed_contextsrC   r   )r^   rV  rZ  r   r^  ra  rW  rX  rY  r[  r\  r]  s   ```   @@@@@@r>   create_container_hooksrc    s     (-J!**8+;+;<%??..x/?/?@67GHd45$L"LGIGI	[ 	[
	I 	I {"" #-
K{""r=   c                    i }| j                         D ]`  \  }}i x}||<   |j                         D ]A  \  }}t        |j                  |j                  dt	        |j                                     ||<   C b |S )z8Create managed contexts from the given control contexts.N)rT   r   r   r   r   r   )rW  r[  r   r  r  r   control_containers          r>   rb  rb  ?  s    >@)9)?)?)A \%o;==*<81@1F1F1H 	\-N-.=>O>W>WYjYpYprvx|  ~O  ~X  ~X  ~Z  y[  /\ON+	\\ r=   c           
        |yd}|j                         D ]  \  }}	d|z  }
|
|j                  v s|	} n |sy|s| j                  ryt        d|z        g }g }|j                         D ]  \  }}g }|j	                         D ]q  \  }}|j
                  r@|j                  ||j                  |f       |j                  d||j                  |fz         R|j                  d|j                  |fz         s |s|j
                  r
d|d|d}n	d	|d
|d}|j                  |ddj                  |              t        |      }t        |      }t        | ddd|      5 }t        | ||dt        |             ddd       g }|r#|D ]  }|j                  t        | ||               ||f||j                  <   |D ]  }t!        j"                  |d        y# 1 sw Y   `xY w)zAConfigure port forwarding using SSH and write hosts file entries.Nz	cloud/%s/r  z%d -> %s:%dz%s:%dzPort forwards for the "z)" container have been established on the z hostzPorts for the "z!" container are available on the z host asz:

ssh-inventory-.jsonFhosts_entriesrE  	variablesr   r   )rT   rc   r   r[   r   r   rQ   r   r   rP  r(   r
   r!   r   r'   ra   r   rW   )r^   ssh_connectionsplaybooktarget_staterE   r  r   test_contextr   r_   context_alias	redirectsmessagesr   r   r   r"  r  r   rk  	inventoryinventory_pathssh_processesr   s                           r>   rU  rU  L  s7    L!)!1 g#l2FNN*"L <<v  zC  C  D  	D,.IH%1%7%7%9 G!	+4+=+=+? 	N'NK!!  .)2C2C[!QR}	@Q@QS^/__`w)*;*;^)LLM	N !!iw  zC  D " ]kluvOO$))G2DEF#G& )6M&7I	d$4gtY	O qSaT>8UdanNopq ')M" 	RC  !:4i!PQ	R "/ >L +W*+q qs   #GG&c           
     t   |j                  |j                  d      }|sy|\  }}t        |      }	t        | ddd|	      5 }
t	        | |
|dt        |             ddd       |rI|D ]  }|j                           t        j                  d|z  d	       |D ]  }|j                           yy# 1 sw Y   UxY w)
z`Stop previously configured SSH port forwarding and remove previously written hosts file entries.Nrh  ri  Frj  rl  zEWaiting for the %s host SSH port forwarding process(es) to terminate.r   r   )
r   ra   r(   r
   r!   r   r  r   rW   r  )r^   rn  ro  rp  rE   r  staterk  rw  ru  rv  r  s               r>   r`  r`    s     V[[$/E%*"]M&7I	d$4gtY	O qSaT>8UdanNopq $ 	 G	  	\_hhtuv$ 	GLLN	 q qs   B..B7)NTTNNNT)r^   r   r_   rS   r`   rS   ra   rS   rb   r>  rc   t.Optional[list[str]]rd   r   re   r   rK   rz  rf   r?  rg   rz  rh   r   r   zt.Optional[ContainerDescriptor])NF)r^   r   r`   rS   ra   rS   rg   rz  rK   rz  rJ   r   r   rS   )r^   r   r   rS   r   z'tuple[t.Optional[str], t.Optional[str]])r^   r   r   r   r   t.Optional[str])r^   r   r   r{  )r   rS   r   r   )r^   r   r   r   )r^   r   r   r-   r   r$   )r   r0   r   r$   )r^   r   r   t.Optional[SshConnectionDetail]r   z)c.Iterator[t.Optional[ContainerDatabase]])r^   r   r   r|  r   r   r   r
  rB   )r^   r   r   rS   r   rS   r   r   rF  r   rG  z#t.Optional[c.Callable[[str], bool]]r   rS   r@  )r_   zdict[str, ContainerAccess]r   r   )r^   r   rV  list[SshConnectionDetail]rZ  %t.Optional[list[SshConnectionDetail]]r   zktuple[t.Optional[c.Callable[[IntegrationTarget], None]], t.Optional[c.Callable[[IntegrationTarget], None]]])rW  %dict[str, dict[str, ContainerAccess]]r   r  )r^   r   rn  r~  ro  rS   rp  -dict[str, tuple[list[str], list[SshProcess]]]rE   r#   r  rS   r   r  r   r   )r^   r   rn  r}  ro  rS   rp  r  rE   r#   r  rS   r   r   )dr;   
__future__r   collections.abcabcc
contextlibr   rw   r   rL  	threadingtypingtutilr   r   r   r   util_commonr	   r
   r7  r   r   r   r   r   r   docker_utilr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    ansible_utilr!   core_cir"   rE   r#   r   r$   r%   r&   r'   r(   host_configsr)   r*   r+   r,   r-   r.   r/   connectionsr0   threadr1   r2   __annotations__LockrZ   r4   rq   rX   r   r   r   r   r   r   r   r   r   r   r
  contextmanagerr  r  rY   r;  rH  r]   rP  rc  rb  rU  r`  r<   r=   r>   <module>r     s   7 "         
     &   
 68 2 7)9>>+   &*!%&*%)\
\\ \ 	\
 \ #\ \ \ 
\ 
$\ #\ \ %\H "&%E
%E%E %E #	%E
 
%E %E 	%EPR( & &R1
  *9 9xD D4f
	+^#B & 
	( / .9
9	(9 "9 	9xL L^/ /( 26n
nn n 	n
 n /n 	n4,"'#
'#2'# ?'# q	'#T
D+
D+:D+ D+ @	D+
 D+ D+ 4D+ 
D+N
.  @	
   
r=   