a
   f!᳤                   @   sP  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 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 eeZddddddddddddddZdZdZdZdjedZdjedZdZd  d!jeed"! Z"e	j#ded#d$d% Z$e	j#d&ed#d'd( Z%e	j#d)ed*d+d, Z&d-d. Z'd/d0 Z(d1d2 Z)d3d4 Z*d5d6 Z+d7d8 Z,d9d: Z-d;d< Z.d=d> Z/d?d@ Z0dAdB Z1dCdD Z2dEdF Z3dGdH Z4dIdJ Z5dKdL Z6dMdN Z7dOdP Z8dQdR Z9dSdT Z:dUdV Z;dWdX Z<dYdZ Z=d[d\ Z>d]d^ Z?d_d` Z@dadb ZAdcdd ZBdedf ZCdgdh ZDdidj ZEdkdl ZFdS )m    N)
split_port)Draft4Validator)FormatChecker)RefResolver)ValidationError   )COMPOSEFILE_V1)NANOCPUS_SCALE   ConfigurationError)VERSION_EXPLANATION)"get_service_name_from_network_modeZ
cpu_sharesZextra_hostsZdeviceslinksZmemswap_limitportsZ
privilegedvolumesZworking_dir)Z	cpu_shareZadd_hostZhostsZ
extra_hostZdevicelinkZmemory_swapportZ	privilegeZ
priviligedZ	priviligeZvolumeZworkdirz[a-zA-Z0-9\._\-]z^\d+(\-\d+)?(\/[a-zA-Z]+)?$z!(\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])z({IPV4_SEG}\.){{3}}{IPV4_SEG})ZIPV4_SEGz!^{IPV4_ADDR}/(\d|[1-2]\d|3[0-2])$)	IPV4_ADDRz[0-9a-fA-F]{1,4} a9  
^
(
    (({IPV6_SEG}:){{7}}{IPV6_SEG})|
    (({IPV6_SEG}:){{1,7}}:)|
    (({IPV6_SEG}:){{1,6}}(:{IPV6_SEG}){{1,1}})|
    (({IPV6_SEG}:){{1,5}}(:{IPV6_SEG}){{1,2}})|
    (({IPV6_SEG}:){{1,4}}(:{IPV6_SEG}){{1,3}})|
    (({IPV6_SEG}:){{1,3}}(:{IPV6_SEG}){{1,4}})|
    (({IPV6_SEG}:){{1,2}}(:{IPV6_SEG}){{1,5}})|
    (({IPV6_SEG}:){{1,1}}(:{IPV6_SEG}){{1,6}})|
    (:((:{IPV6_SEG}){{1,7}}|:))|
    (fe80:(:{IPV6_SEG}){{0,4}}%[0-9a-zA-Z]{{1,}})|
    (::(ffff(:0{{1,4}}){{0,1}}:){{0,1}}{IPV4_ADDR})|
    (({IPV6_SEG}:){{1,4}}:{IPV4_ADDR})
)
/(\d|[1-9]\d|1[0-1]\d|12[0-8])
$
)ZIPV6_SEGr   )formatraisesc              
   C   sB   zt |  W n0 ty< } ztt|W Y d }~n
d }~0 0 dS )NT)r   
ValueErrorr   str)instancee r   =/usr/lib/python3.9/site-packages/compose/config/validation.pyformat_portsE   s
    "r   exposec                 C   s"   t | trtt| stddS )Nz)should be of the format 'PORT[/PROTOCOL]'T)
isinstancer   rematchVALID_EXPOSE_FORMATr   r   r   r   r   format_exposeN   s    
r%   subnet_ip_address)r   c                 C   s.   t | tr*tt| s*tt| s*tddS )Nzshould use the CIDR formatT)r    r   r!   r"   VALID_REGEX_IPV4_CIDRVALID_REGEX_IPV6_CIDRr   r$   r   r   r   format_subnet_ip_addressX   s    

r)   c                 C   sD   |  dg }|D ].}|jr|j|vrtd| |  dqd S )Nr   z^Named volume "{}" is used in service "{}" but no declaration was found in the volumes section.name)getZis_named_volumeZexternalr   r   repr)Zservice_dictZproject_volumesZservice_volumesZvolume_specr   r   r   match_named_volumesb   s    r-   c              	   C   s(   t | j}ddddddddd||S )NmappingZarrayZnumberZbooleanstring)dictlistintfloatboolZunicoder   bytes)type__name__r+   )type_	type_namer   r   r   python_type_to_yaml_typen   s    
	r:   c              	   C   s   t |ts&tdj| |tt|d| D ]V\}}t |tsTtdj| ||dt |ttdfs.tdj| ||tt|dq.dS )zValidate the structure of a configuration section. This must be done
    before interpolation so it's separate from schema validation.
    z>In file '{filename}', {section} must be a mapping, not {type}.)filenamesectionr6   zWIn file '{filename}', the {section} name {name} must be a quoted string, i.e. '{name}'.)r;   r<   r*   NzFIn file '{filename}', {section} '{name}' must be a mapping not {type}.)r;   r<   r*   r6   )	r    r0   r   r   anglicize_json_typer:   itemsr   r6   )r;   configr<   keyvaluer   r   r   validate_config_section|   s4    



rB   c                 C   s(   t | jts$td| jt| jd S )Nz8Top level object in '{}' needs to be an object not '{}'.)r    r?   r0   r   r   r;   r6   )config_filer   r   r   validate_top_level_object   s    rD   c                 C   sP   | j di }| D ]4\}}t|tr|d |d kstdj| |dqd S )NZulimitsZsoftZhardzdService '{s.name}' has invalid ulimit '{ulimit}'. 'soft' value can not be greater than 'hard' value )sZulimit)r?   r+   r>   r    r0   r   r   )service_configZulimit_configZ
limit_nameZsoft_hard_valuesr   r   r   validate_ulimits   s    
rG   c                 C   s(   d|  }d|vr$|du r$t d| dS )zo
    The service to be extended must either be defined in the config key 'file',
    or within 'filename'.
    z'Invalid 'extends' configuration for %s:fileNz;%s you need to specify a 'file', e.g. 'file: something.yml'r   )service_nameZextends_optionsr;   Zerror_prefixr   r   r   validate_extends_file_path   s
    rJ   c                 C   sT   | j d}|sd S d| j v r&tdt|}|s6d S ||vrPtdj| |dd S )Nnetwork_modeZnetworksz0'network_mode' and 'networks' cannot be combinedzPService '{s.name}' uses the network stack of service '{dep}' which is undefined.rE   Zdep)r?   r+   r   r   r   )rF   service_namesrK   
dependencyr   r   r   validate_network_mode   s    
rO   c                 C   sB   | j d}|sd S t|}|s$d S ||vr>tdj| |dd S )NpidzPService '{s.name}' uses the PID namespace of service '{dep}' which is undefined.rL   r?   r+   r   r   r   )rF   rM   Zpid_moderN   r   r   r   validate_pid_mode   s    rR   c                 C   sB   | j d}|sd S t|}|s$d S ||vr>tdj| |dd S )NZipczPService '{s.name}' uses the IPC namespace of service '{dep}' which is undefined.rL   rQ   )rF   rM   Zipc_moderN   r   r   r   validate_ipc_mode   s    rS   c                 C   s<   | j dg D ](}|dd |vrtdj| |dqd S )Nr   :r   zEService '{s.name}' has a link to service '{link}' which is undefined.)rE   r   )r?   r+   splitr   r   )rF   rM   r   r   r   r   validate_links   s    rV   c                 C   s:   | j di }| D ]}||vrtdj| |dqd S )NZ
depends_onzAService '{s.name}' depends on service '{dep}' which is undefined.rL   )r?   r+   keysr   r   )rF   rM   ZdepsrN   r   r   r   validate_depends_on   s    rX   c                 C   s8   | j d}|sd S d|vr4d|vr4tdj| dd S )Ncredential_specregistryrH   zQService '{s.name}' is missing 'credential_spec.file' or credential_spec.registry')rE   )r?   r+   r   r   )rF   rY   r   r   r   validate_credential_spec   s    r[   c                 C   s.   d t| |}|tv r*|d t| 7 }|S )Nz&Unsupported config option for {}: '{}'z (did you mean '{}'?))r   path_stringDOCKER_CONFIG_HINTS)pathZ	error_keymsgr   r   r   get_unsupported_config_msg
  s    r`   c                 C   s   |  drd|  S d|  S )N)ar   iouzan za )
startswith)Z	json_typer   r   r   r=     s    
r=   c                 C   s   | dv S )N)zconfig_schema_v1.jsonz#/properties/servicesr   )	schema_idr   r   r   is_service_dict_schema  s    rg   c                 C   s   | j d }t|r<| jdkr<ddd t| jD d tS | jdkr|dkr`t| }t||S |	drt| }d	j|d

| j d  tdS | jsd| jtS d S )NidadditionalPropertiesz:Invalid service name '{}' - only {} characters are allowedc                 S   s&   g | ]}|rt td d |r|qS )c                 S   s   t t|  S N)r!   r"   VALID_NAME_CHARS)cr   r   r   <lambda>"      z<handle_error_for_schema_with_id.<locals>.<listcomp>.<lambda>)anyfilter).0rb   r   r   r   
<listcomp>!  s   z3handle_error_for_schema_with_id.<locals>.<listcomp>r   z#/definitions/serviceZconfig_schema_zInvalid top-level property "{key}". Valid top-level sections for this Compose file are: {properties}, and extensions starting with "x-".

{explanation}, 
properties)r@   rt   Zexplanationz{}

{})schemarg   	validatorr   r1   r   rk   parse_key_from_error_msgr`   re   joinrW   r   r^   message)errorr^   rf   invalid_config_keyr   r   r   handle_error_for_schema_with_id  s*    



r|   c                 C   s   d }| j }| jdkr4d}t| \}}|r|| n| jdkrNd}t| j}n| jdkrjd| j}d}nh| jdkrt| j d	 }d
| j| }d}|| d	||}n | j
rt| j
}d}n
| jrd}|r|j	t||dS | j S )NoneOfz{path} {msg}r6   z3{path} contains an invalid type, it should be {msg}requiredrs   z%{path} is invalid, {msg} is required.Zdependenciesr   ,z{path} is invalid: {msg}z,when defining '{}' you must set '{}' as wellz{path} value {msg})r^   r_   )ry   rv   _parse_oneof_validatorappend!_parse_valid_types_from_validatorvalidator_valuerx   r1   rW   r   causer   r^   r\   )rz   r^   Z
msg_format	error_msgZ
config_keyrequired_keysr   r   r   handle_generic_error:  s<    





r   c                 C   sJ   z| j dd W S  tyD   | j dd dd d Y S 0 d S )N'r
   ( r   )ry   rU   
IndexErrorstrip)rz   r   r   r   rw   c  s    rw   c                 C   s   d dd | D S )N.c                 s   s   | ]}t |tr|V  qd S rj   )r    r   )rq   rl   r   r   r   	<genexpr>k  rn   zpath_string.<locals>.<genexpr>)rx   )r^   r   r   r   r\   j  s    r\   c                 C   sZ   t | tst| S t| dkr*t| d S ddt| d g| dd  t| d S )zA validator value can be either an array of valid types or a string of
    a valid type. Parse the valid types and prefix with the correct article.
    r
   r   z	{}, or {}rs   )r    r1   r=   lenr   rx   )rv   r   r   r   r   n  s    

r   c                 C   s   g }| j D ]}|jdkr6t|\}}t|j|f  S |jdkrNd|jf  S |jdkrrt|}dd|f  S |jdkr|jrt|jndd|jf  S |jrt|jdt	
|jt|jf  S |jd	kr
||j q
t|}dd
|fS )a  oneOf has multiple schemas, so we need to reason about which schema, sub
    schema or constraint the validation is failing on.
    Inspecting the context value of a ValidationError gives us information about
    which sub schema failed and which kind of error it is.
    r}   r~   Nri   z!contains unsupported option: '{}'ZuniqueItemsz;contains non-unique items, please remove duplicates from {}z6contains {}, which is an invalid type, it should be {}r6   z)contains an invalid type, it should be {})contextrv   r   r\   r^   ry   rw   r   r   jsondumpsr   r   r   )rz   typesr   _r   r{   Zvalid_typesr   r   r   r   }  s6    






r   c                 C   sf   |t krDd| jv r&d| jv r&d|S d| jv rDd| jv rDd|S d| jvrbd| jvrbd|S d S )NZimageZbuildzService {} has both an image and build path specified. A service can either be built to image or use an existing image, not both.Z
dockerfilezService {} has both an image and alternate Dockerfile. A service can either be built to image or use an existing image, not both.z]Service {} has neither an image nor a build context specified. At least one must be provided.)V1r   r   )rz   rI   versionr   r   r   !process_service_constraint_errors  s     r   c                 C   s0   t | j}d| jv r&t| |}|r&|S t| |S )Nrh   )r1   r^   ru   r|   r   )rz   r^   r   r   r   r   process_config_schema_errors  s    


r   c                 C   s@   i }|   D ].\}}||t|< t|trt||t|< q|S )zH
        Non-string keys may break validator with patterned fields.
    )r>   r   r    r0   keys_to_str)rC   dkvr   r   r   r     s    
r   c                 C   sL   t |}t| j}tg d}t|tt ||d}t||t	| j
 d S )N)r   r   r&   )Zresolverformat_checker)load_jsonschemar   r?   r   r   r   get_resolver_pathhandle_errorsiter_errorsr   r;   )rC   r   ru   r?   r   rv   r   r   r   validate_against_config_schema  s    

r   c                    sB    fdd}t  j}t|d d d }t|| |d  d S )Nc                    s   t |  jS rj   )r   r   )errorsrC   rI   r   r   handler  s    z-validate_service_constraints.<locals>.handlerZdefinitionsconstraintsZservice)r   r   r   r   r   )r?   rI   rC   r   ru   rv   r   r   r   validate_service_constraints  s    
r   c                 C   s:   | j d}|sd S |t }t|tr6| s6tdd S )Ncpusz6cpus must have nine or less digits after decimal point)r?   r+   r	   r    r3   
is_integerr   )rF   r   Z	nano_cpusr   r   r   validate_cpu  s    r   c                   C   s   t jt jtS rj   )osr^   dirnameabspath__file__r   r   r   r   get_schema_path  s    r   c                 C   sx   d}| t krd}tjt d|}tj|sBtd|tt	|}t
|W  d    S 1 sj0    Y  d S )NZcompose_specZconfig_schema_v1z{}.jsonz"Version in "{}" is unsupported. {})r   r   r^   rx   r   r   existsr   r   openr   load)r   r*   r;   Zfhr   r   r   r     s    
r   c                  C   s2   t  } tjdkr"d}| dd} nd}d|| S )Nwin32z///\/z//z
file:{}{}/)r   sysplatformreplacer   )Zschema_pathschemer   r   r   r   	  s    
r   c                    sP   t | td} | sdS d fdd| D }tdj|r@d|nd|d	dS )
zjsonschema returns an error tree full of information to explain what has
    gone wrong. Process each error and pull out relevant information and re-write
    helpful error messages that are relevant.
    )r@   N
c                 3   s   | ]} |V  qd S rj   r   )rq   rz   format_error_funcr   r   r     rn   z handle_errors.<locals>.<genexpr>z:The Compose file{file_msg} is invalid because:
{error_msg}z '{}'r   )Zfile_msgr   )sortedr   rx   r   r   )r   r   r;   r   r   r   r   r     s    r   c                 C   s   | j di }d|v rt|d trt|d dkrFtd| jnN|d d dkrtt|dkrttd| jn |d d dvrtd	| jd S )
Nhealthchecktestr   zDService "{}" defines an invalid healthcheck: "test" is an empty listNONEr
   zbService "{}" defines an invalid healthcheck: "disable: true" cannot be combined with other options)r   ZCMDz	CMD-SHELLzwService "{}" defines an invalid healthcheck: when "test" is a list the first item must be either NONE, CMD or CMD-SHELL)r?   r+   r    r1   r   r   r   r*   )rF   r   r   r   r   validate_healthcheck$  s(    r   )Gr   Zloggingr   r!   r   Zdocker.utils.portsr   Z
jsonschemar   r   r   r   constr   r   r	   r   r   r   Zsort_servicesr   Z	getLoggerr7   logr]   rk   r#   ZVALID_IPV4_SEGr   ZVALID_IPV4_ADDRr'   ZVALID_IPV6_SEGrx   rU   r(   Z
cls_checksr   r%   r)   r-   r:   rB   rD   rG   rJ   rO   rR   rS   rV   rX   r[   r`   r=   rg   r|   r   rw   r\   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s   


	
	
))

