U
    ]w                     @   s
  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mZ d dl	m
Z
 d dlZd dlZd dlmZ d dlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl m!Z! ddl m"Z" ddl m#Z# ddl$m%Z% ddl$m&Z& ddl$m'Z' ddl$m(Z( ddl$m)Z) ddl$m*Z* ddl$m+Z+ ddl$m,Z, ddl$m-Z- ddl$m.Z. ddl/m0Z0 dd l/m1Z1 dd!l2m3Z3 e4e5Z6ej7G d"d# d#ej8Z9G d$d% d%e:Z;d&d' Z<d(d) Z=G d*d+ d+e>Z?G d,d- d-e>Z@dS ).    )absolute_import)unicode_literalsN)reduce)path)APIError)
version_lt   )parallel)ConfigurationError)V1)$get_container_name_from_network_mode)"get_service_name_from_network_mode)LABEL_ONE_OFF)LABEL_PROJECT)LABEL_SERVICE)	Container)build_networks)get_networks)ProjectNetworks)BuildAction)ContainerNetworkMode)ContainerPidMode)ConvergenceStrategy)NetworkMode)parse_repository_tag)PidMode)Service)ServiceNetworkMode)ServicePidMode)microseconds_from_time_nano)truncate_string)ProjectVolumesc                   @   s$   e Zd ZdZdZdZedd ZdS )OneOffFilterr   r      c                 C   s^   || j kr|dtd n<|| jkr<|dtd n|| jkrHntdt|d S )N{0}={1}TrueFalsezInvalid value for one_off: {})onlyappendformatr   excludeinclude
ValueErrorrepr)clsvaluelabels r1   1/usr/lib/python3/dist-packages/compose/project.pyupdate_labels4   s    


zOneOffFilter.update_labelsN)__name__
__module____qualname__r+   r*   r'   classmethodr3   r1   r1   r1   r2   r"   .   s
   r"   c                   @   s  e Zd ZdZdIddZejdfddZedg fdd	Z	e
d
d Zdd Zdd ZdJddZdKddZdd Zdd Zdd ZdLddZdejfddZdMddZdNd d!ZdOd"d#Zdejfd$d%ZdPd&d'Zd(d) ZdQd*d+ZdRd-d.Zdejej fd/d0Z!d1d2 Z"dSd3d4Z#dd,ejej dddddd,d,dddddfd5d6Z$d7d8 Z%dTd9d:Z&dUd;d<Z'dVd=d>Z(dejfd?d@Z)ddejfdAdBZ*dCdD Z+dEdF Z,dGdH Z-dS )WProjectz#
    A collection of services.
    Nc                 C   s:   || _ || _|| _|pti | _|p,ti d| _|| _d S )NF)nameservicesclientr!   volumesr   networksconfig_version)selfr9   r:   r;   r=   r<   r>   r1   r1   r2   __init__D   s    zProject.__init__Fc                 C   s6   | j }|rtdd|}dt|g}t|| |S )Nz[_-] r$   )r9   resubr)   r   r"   r3   )r?   one_offlegacyr9   r0   r1   r1   r2   r0   L   s    zProject.labelsc                    s>  |j o|j tk}t|||}t|j||}t||| | |g || |j }	|jD ]}
t|
}
|rpt	|
|}ni }|

dd |	|
}|	|
t| }|	|
}t|	|
}|j tkrڇ fdd|
dg D |
d< t|
d |

ddpg |j}|	jt|

df||||||||||

dd||d	|
 qT|	S )
zB
        Construct a Project from a config.Config object.
        r=   Nc                    s   g | ]}  |qS r1   )Znamespace_spec).0Zvolume_specr<   r1   r2   
<listcomp>s   s   z'Project.from_config.<locals>.<listcomp>r<   r9   secretsplatform)r;   projectuse_networkingr=   linksnetwork_modevolumes_fromrI   pid_moderJ   default_platformextra_labels)versionr   r   r   Zfrom_servicesr:   r!   from_configdictr   pop	get_linksget_network_modelistkeysget_pid_modeget_volumes_fromgetget_secretsrI   r(   r   )r.   r9   Zconfig_datar;   rQ   rR   rL   r=   Zproject_networksrK   service_dictZservice_networksrM   rN   rP   rO   rI   r1   rG   r2   rT   U   sh    

 







zProject.from_configc                 C   s   dd | j D S )Nc                 S   s   g | ]
}|j qS r1   )r9   rF   servicer1   r1   r2   rH      s     z)Project.service_names.<locals>.<listcomp>)r:   r?   r1   r1   r2   service_names   s    zProject.service_namesc                 C   s*   | j D ]}|j|kr|  S qt|dS )zo
        Retrieve a service by name. Raises NoSuchService
        if the named service does not exist.
        N)r:   r9   NoSuchService)r?   r9   ra   r1   r1   r2   get_service   s    


zProject.get_servicec                 C   s$   | j }|D ]}||kr
t|q
dS )z
        Validate that the given list of service names only contains valid
        services. Raises NoSuchService if one of the names is invalid.
        N)rc   rd   )r?   rc   Zvalid_namesr9   r1   r1   r2   validate_service_names   s    zProject.validate_service_namesc                    sl   |dkst |dkr j} fdd|D fdd jD }|rRt j|g }g fdd|D  S )a  
        Returns a list of this project's services filtered
        by the provided list of names, or all services if service_names is None
        or [].

        If include_deps is specified, returns a list including the dependencies for
        service_names, in order of dependency.

        Preserves the original order of self.services where possible,
        reordering as needed to resolve dependencies.

        Raises NoSuchService if any of the named services do not exist.
        Nr   c                    s   g | ]}  |qS r1   re   rF   r9   rb   r1   r2   rH      s     z(Project.get_services.<locals>.<listcomp>c                    s   g | ]}| kr|qS r1   r1   rF   s)unsortedr1   r2   rH      s      c                    s   g | ]}| kr  |qS r1   )r(   ri   )uniquesr1   r2   rH      s      )lenrc   r:   r   _inject_deps)r?   rc   include_depsr:   r1   )r?   rl   rk   r2   get_services   s    zProject.get_servicesc                 C   s"   |  ||}|D ]}|  q|S N)rp   Zremove_duplicate_containers)r?   rc   ro   r:   ra   r1   r1   r2   get_services_without_duplicate   s    
z&Project.get_services_without_duplicatec              	   C   s   g }d|kr| dg D ]j}d|kr6|dd\}}n
|d  }}z|| ||f W q tk
r   td|d |f Y qX q|d= |S )NrM   :r   z=Service "%s" has a link to service "%s" which does not exist.r9   )r]   splitr(   re   rd   r
   )r?   r_   rM   linkservice_nameZ	link_namer1   r1   r2   rW      s     

zProject.get_linksc                 C   s   | dd }|s8| jjr0|r(t|d S tdS td S t|}|rRt| |S t|}|rztt	
| j|W S  tk
r   tdj|d |dY nX t|S )NrN   r   nonezRService '{name}' uses the network stack of container '{dep}' which does not exist.r9   r9   dep)rV   r=   rL   r   r   r   re   r   r   r   from_idr;   r   r
   r)   )r?   r_   r=   rN   rv   container_namer1   r1   r2   rX      s(     
zProject.get_network_modec                 C   s   | dd }|std S t|}|r2t| |S t|}|r~ztt| j	|W S  t
k
r|   tdj|d |dY nX t|S )NpidzRService '{name}' uses the PID namespace of container '{dep}' which does not exist.r9   rx   )rV   r   r   r   re   r   r   r   rz   r;   r   r
   r)   )r?   r_   rP   rv   r{   r1   r1   r2   r[      s$     
zProject.get_pid_modec                    sL   g   fdd} |}fdd}tj||tdd|dd d	  S )
Nc                    s"   | j f ddi} | d S )NquietT)startextend)ra   Zservice_containers)
containersoptionsr1   r2   start_service  s    z$Project.start.<locals>.start_servicec                    s    fdd|    D S )Nc                    s   h | ]\}}  ||fqS r1   rg   rF   ry   configrb   r1   r2   	<setcomp>  s   z2Project.start.<locals>.get_deps.<locals>.<setcomp>Zget_dependency_configsitemsra   rb   r1   r2   get_deps  s    

zProject.start.<locals>.get_depsr9   ZStartingc                 S   s
   |    S rq   )r   )objr1   r1   r2   <lambda>      zProject.start.<locals>.<lambda>)Z
fail_check)rp   r	   parallel_executeoperator
attrgetter)r?   rc   r   r   r:   r   r1   )r   r   r?   r2   r~     s    
	zProject.startc                    s@   j ||d  fdd}t d|tdd| d S )NrD   c                    s    fddD S )Nc                    s*   h | ]"} j |j  kr|d fqS rq   )ra   re   get_dependency_names)rF   other)	containerr?   r1   r2   r   '  s
    z1Project.stop.<locals>.get_deps.<locals>.<setcomp>r1   r   r   r?   r   r2   r   %  s    zProject.stop.<locals>.get_depsstopr9   ZStoppingr   r	   r   +build_container_operation_with_timeout_funcr   r   )r?   rc   rD   r   r   r1   r   r2   r   "  s    
zProject.stopc                 K   s   |  |}tt|| |S rq   )r   r	   Zparallel_pausereversedr?   rc   r   r   r1   r1   r2   pause3  s    
zProject.pausec                 K   s   |  |}t|| |S rq   )r   r	   Zparallel_unpauser   r1   r1   r2   unpause8  s    
zProject.unpausec                 K   s   t | || d S rq   )r	   Zparallel_killr   )r?   rc   r   r1   r1   r2   kill=  s    zProject.killc                 K   s   t | j|d|d| d S )NT)stoppedrD   )r	   Zparallel_remover   )r?   rc   rD   r   r1   r1   r2   remove_stopped@  s      zProject.remove_stoppedc                 C   sT   | j tj|d |s| | | j|tjd | j  |rF| j  | | d S )N)rD   timeout)vrD   )	r   r"   r+   find_orphan_containersr   r=   remover<   remove_images)r?   remove_image_typeZinclude_volumesremove_orphansr   ignore_orphansr1   r1   r2   downE  s    


zProject.downc                 C   s   |   D ]}|| qd S rq   )rp   Zremove_image)r?   r   ra   r1   r1   r2   r   X  s    zProject.remove_imagesc                 K   s0   | j |dd}t|| d|tdd |S )NTr   restartr9   Z
Restartingr   r   r1   r1   r2   r   \  s    
zProject.restartTc              
      s   g }|  |D ],}| r&|| q	std|j  qrftd |rXtd rftd  	f
dd}|rtj||t	
ddd	d
\}}t|rddd | D }t|n|D ]}|| qd S )Nz%s uses an image, skippingDNative build is an experimental feature and could change at any timezJFlag '--parallel' is ignored when building with COMPOSE_DOCKER_CLI_BUILD=1zJFlag '--compress' is ignored when building with COMPOSE_DOCKER_CLI_BUILD=1c                    s    |   	
 d S rq   )buildr   

build_argscliforce_rmgzipmemoryno_cacheprogresspullrmsilentr1   r2   build_service{  s    z$Project.build.<locals>.build_servicer9   ZBuilding   limit
c                 S   s&   g | ]}t |tjr|d n|qS utf-8
isinstancesixbinary_typedecoderF   er1   r1   r2   rH     s    z!Project.build.<locals>.<listcomp>)rp   can_be_builtr(   loginfor9   warningr	   r   r   r   rm   joinvaluesProjectError)r?   rc   r   r   r   r   r   r   Zparallel_buildr   r   r   r   r:   ra   r   _errorscombined_errorsr1   r   r2   r   g  s8    





zProject.buildc                 C   sT   | j |dd}|D ]}|j|d q| ||}|D ]}|j||j ddd q4d S )NTro   )do_buildF)detachedr~   )rr   ensure_image_exists_get_convergence_plansexecute_convergence_planr9   )r?   rc   strategyr   r:   svcplansra   r1   r1   r2   create  s    zProject.createc              	   c   s   dd }t |p| j}| jjd|  iddD ]V}d|kr<q.zt| j|d }W n tk
rj   Y q.Y nX |j|krxq.|||V  q.d S )Nc                 S   sL   t j | d }|jt| d d}|d| d |j|j|j| d d|dS )	NtimetimeNanoZmicrosecondr   statusfrom)r9   Zimager   typeactionidra   Z
attributesr   )datetimefromtimestampreplacer   r   ra   r9   )eventr   r   r1   r1   r2   build_container_event  s    
z>Project._legacy_event_processor.<locals>.build_container_eventlabelTfiltersr   r   r   )	setrc   r;   eventsr0   r   rz   r   ra   )r?   rc   r   r   r   r1   r1   r2   _legacy_event_processor  s    



zProject._legacy_event_processorc                    sH   t jjdr|S fdd  fdd}||r@t|njS )Nz1.22c              	      s   | d d }t j | d }|jt| d d}d }zt j| d }W n tk
r^   Y nX |d| d | d d	 |t	t
d
d | D |dS )NActor
Attributesr   r   r   r   r   r   ZIDc                 S   s"   g | ]\}}| d s||fqS )zcom.docker.compose.)
startswith)rF   kr   r1   r1   r2   rH     s   
zAProject.events.<locals>.build_container_event.<locals>.<listcomp>r   )r   r   r   r   r   rz   r;   r   r]   r   rU   r   )r   Zcontainer_attrsr   r   rb   r1   r2   r     s(    

z-Project.events.<locals>.build_container_eventc              	   3   sr   j jd iddD ]T}|ddkr,qz|d d t | krFW qW n tk
r`   Y qY nX  |V  qd S )Nr   Tr   ZTyper   r   r   )r;   r   r0   r]   r   KeyError)rc   r   r   r?   r1   r2   
yield_loop  s    


z"Project.events.<locals>.yield_loop)r   r;   api_versionr   r   rc   )r?   rc   r   r1   r   r2   r     s
    
zProject.eventsc                    s   |rt d   |s$| d kr0i j||d}|D ]}|j|||d qBj|||d fdd}fdd}t||t	
d	d |\}}|rtd
dd |D S )Nr   r   )r   r   r   )always_recreate_depsc              
      s(   | j | j  | jdS )N)r   r   scale_overriderescaler~   reset_container_imagerenew_anonymous_volumes)r   r9   r]   r   )r   r   r   r   r   r   r~   r   r1   r2   do"  s    
zProject.up.<locals>.doc                    s    fdd|    D S )Nc                    s   h | ]\}}  ||fqS r1   rg   r   rb   r1   r2   r   0  s   z/Project.up.<locals>.get_deps.<locals>.<setcomp>r   r   rb   r1   r2   r   /  s    

zProject.up.<locals>.get_depsr9   z1Encountered errors while bringing up the project.c                 S   s"   g | ]}|d k	r|D ]}|qqS rq   r1   )rF   Zsvc_containersr   r1   r1   r2   rH   A  s
    zProject.up.<locals>.<listcomp>)r   r   
initializer   rr   r   r   r	   r   r   r   r   )r?   rc   Z
start_depsr   r   r   r   r   r   r   r   r~   r   r   r   r   r   r:   r   r   r   Zresultsr   r1   )	r   r   r   r   r   r   r?   r~   r   r2   up  sD    

  z
Project.upc                 C   s   | j   | j  d S rq   )r=   r   r<   rb   r1   r1   r2   r   H  s    
zProject.initializec                    s   i  |D ]} fdd|  D }|r|jrtd|jd| t|jddddgid	}t| }td
d | D }||A }	|s|s|	r|	t
j}
q|	|}
n
|	|}
|
 |j< q S )Nc                    s&   g | ]}| kr | j d kr|qS ))Zrecreater   )r   rh   r   r1   r2   rH   P  s   z2Project._get_convergence_plans.<locals>.<listcomp>z%s has upstream changes (%s), Tr   ZcreatedZexited)r   r   c                 s   s   | ]}| d V  qdS )zHostConfig.LinksN)r]   rF   cr1   r1   r2   	<genexpr>^  s     z1Project._get_convergence_plans.<locals>.<genexpr>)r   Zallows_recreater   debugr9   r   anyr   Zget_link_namesZconvergence_planr   always)r?   r:   r   r   ra   Zupdated_dependenciesZcontainers_stoppedZservice_has_linksZcontainer_has_linksZshould_recreate_for_linksZplanr1   r   r2   r   L  s,    


zProject._get_convergence_plansc                    s   |  ||}dd |D fdd|D }| r6dp8d |r fdd}tj||tdd	d
\}	}
t|
rddd |
 D }t|n|D ]}|j	 |d qd S )Nc                 S   s   h | ]}|  r|jqS r1   )r   
image_namer`   r1   r1   r2   r   n  s      zProject.pull.<locals>.<setcomp>c                    s   g | ]}|j  kr|qS r1   )r  r`   )images_to_buildr1   r2   rH   o  s     
 z Project.pull.<locals>.<listcomp>ZPullingc                    s   | j  ddd}|d krd S t }|D ]x}d|kr6q(|d  }d|kr|d }d|krd|krt|d t|d  }d||}|| jt|dd	  q(d S )
NT)streamr   ZprogressDetailZcurrentZtotalz{} ({:.1%})c                 S   s   | S rq   r1   )rj   r1   r1   r2   r     r   z4Project.pull.<locals>.pull_service.<locals>.<lambda>)	r   r	   Zget_stream_writerlowerfloatr)   writer9   r    )ra   Zstrmwriterr   r   ZdetailZ
percentage)ignore_pull_failuresmsgr1   r2   pull_servicet  s&       z"Project.pull.<locals>.pull_servicer9   r   r   r   c                 S   s&   g | ]}t |tjr|d n|qS r   r   r   r1   r1   r2   rH     s    )r   )
rp   r	   r   r   r   rm   r   r   r   r   )r?   rc   r  Zparallel_pullr   ro   r:   Zservices_to_pullr  r   r   r   ra   r1   )r  r  r  r2   r   k  s(    


zProject.pullc           	      C   sj   t  }| j|ddD ]P}t|j\}}}|r:|||fn||df}||kr|| || qd S )NFr   Zlatest)r   rp   r   r  r   pushadd)	r?   rc   Zignore_push_failuresZunique_imagesra   ZrepotagsepZservice_image_namer1   r1   r2   r    s     
zProject.pushc                    s   t td  fdd jj|d j|didD }|r<|S t t fddtd  fdd jj|d j|d	d
idD S )Nc                    s   g | ]}t  j|qS r1   r   Zfrom_psr;   rF   r   rb   r1   r2   rH     s   z/Project._labeled_containers.<locals>.<listcomp>r   r   )allr   c                    s   |   jS rq   )Zhas_legacy_proj_namer9   )r  rb   r1   r2   r     r   z-Project._labeled_containers.<locals>.<lambda>c                    s   g | ]}t  j|qS r1   r  r  rb   r1   r2   rH     s   T)rD   rE   )rY   filterr;   r   r0   )r?   r   rD   Zctnrsr1   rb   r2   _labeled_containers  s    
zProject._labeled_containersc                    s@   r|   n| j| ||}fdd  fdd|D S )Nc                    s   | j t kS rq   )r0   r]   r   r   )rc   r1   r2   matches_service_names  s    z1Project.containers.<locals>.matches_service_namesc                    s   g | ]} |r|qS r1   r1   r   )r  r1   r2   rH     s      z&Project.containers.<locals>.<listcomp>)rf   rc   r  )r?   rc   r   rD   r   r1   )r  rc   r2   r     s    zProject.containersc              	      s    fdd}t | }|sd S |rn|D ]D}td|j z|  W n tk
r\   Y nX |jdd q&n tdd	dd	 |D  d S )
Nc                  3   sB   t    jdd } | D ] }|jt}| jkr|V  qd S )NTr   )r   r  r0   r]   r   rc   )r   ctnrrv   rb   r1   r2   _find  s
    
z-Project.find_orphan_containers.<locals>._findzRemoving orphan container "{0}"T)ZforcezFound orphan containers ({0}) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.r   c                 S   s   g | ]}d  |jqS )z{})r)   r9   )rF   r  r1   r1   r2   rH     s     z2Project.find_orphan_containers.<locals>.<listcomp>)
rY   r   r   r)   r9   r   r   r   r   r   )r?   r   r  Zorphansr  r1   rb   r2   r     s"    
zProject.find_orphan_containersc                 C   sB   |  }t|dkr,| jtt|dd}ng }|| || S )Nr   T)rc   ro   )r   rm   rp   rY   r   r(   )r?   Zaccra   Z	dep_namesZdep_servicesr1   r1   r2   rn     s    

zProject._inject_depsc                    s    fdd}|S )Nc                    s@     }|dd kr0| j}|d |d< t|  f |S )Nr   )copyr]   re   ra   Zstop_timeoutgetattr)r   Z_optionsra   	operationr   r?   r1   r2    container_operation_with_timeout  s
    z]Project.build_container_operation_with_timeout_func.<locals>.container_operation_with_timeoutr1   )r?   r  r   r   r1   r  r2   r     s    z3Project.build_container_operation_with_timeout_func)NNN)NF)NF)N)N)N)N)FNF)N)NFFFNNFFTFFN)N)F)NFFFF)NF).r4   r5   r6   __doc__r@   r"   r*   r0   r7   rT   propertyrc   re   rf   rp   rr   rW   rX   r[   r~   r   r   r   r   r   r   r   r   r   r   Zchangedr   rw   r   r   r   r   r   r   r   r  r  r   r   rn   r   r1   r1   r1   r2   r8   @   s   
	;







	   

             
*
)
3
L
  
/
r8   c                    s4    dd }|sg S fdd  fdd|D S )NrO   c                    s   | j dkr6z| j | jdW S  tk
r4   Y nX | j dkrtzt j| j}| j|dW S  tk
rr   Y nX t	d
d | jd S )Nra   )sourcer   zWService "{}" mounts volumes from "{}", which is not the name of a service or container.r9   )r   _replacere   r#  rd   r   rz   r;   r   r
   r)   )specr   )rK   r_   r1   r2   build_volume_from  s"    

z+get_volumes_from.<locals>.build_volume_fromc                    s   g | ]} |qS r1   r1   )rF   Zvf)r&  r1   r2   rH     s     z$get_volumes_from.<locals>.<listcomp>)rV   )rK   r_   rO   r1   )r&  rK   r_   r2   r\     s
    r\   c                 C   s   g }|D ]}| |j}|s0tdj| |jd| drRtdj| |jd q|jsd|jsd|jrztdj| |jd | d}t	
t|stdj| |d |||d	 q|S )
Nz8Service "{service}" uses an undefined secret "{secret}" )ra   secretZexternalzService "{service}" uses secret "{secret}" which is external. External secrets are not available to containers created by docker-compose.zService "{service}" uses secret "{secret}" with uid, gid, or mode. These fields are not supported by this implementation of the Compose filefilezwService "{service}" uses an undefined secret file "{secret_file}", the following file should be created "{secret_file}")ra   secret_file)r'  r(  )r]   r#  r
   r)   r   r   Zuidgidmoder   isfilestrr(   )ra   Zservice_secretsZsecret_defsrI   r'  Z
secret_defr)  r1   r1   r2   r^     sB     
  
 r^   c                   @   s   e Zd Zdd Zdd ZdS )rd   c                 C   s,   t |tjr|d}|| _d| j | _d S )Nr   zNo such service: %s)r   r   r   r   r9   r  )r?   r9   r1   r1   r2   r@   :  s    
zNoSuchService.__init__c                 C   s   | j S rq   r  rb   r1   r1   r2   __str__@  s    zNoSuchService.__str__N)r4   r5   r6   r@   r/  r1   r1   r1   r2   rd   9  s   rd   c                   @   s   e Zd Zdd ZdS )r   c                 C   s
   || _ d S rq   r.  )r?   r  r1   r1   r2   r@   E  s    zProjectError.__init__N)r4   r5   r6   r@   r1   r1   r1   r2   r   D  s   r   )AZ
__future__r   r   r   Zloggingr   rB   	functoolsr   osr   enumr   Zdocker.errorsr   Zdocker.utilsr   rA   r	   r   r
   Zconfig.configr   Zconfig.sort_servicesr   r   Zconstr   r   r   r   r   Znetworkr   r   r   ra   r   r   r   r   r   r   r   r   r   r   Zutilsr   r    Zvolumer!   Z	getLoggerr4   r   uniqueEnumr"   objectr8   r\   r^   	Exceptionrd   r   r1   r1   r1   r2   <module>   sb   
     <&