o
    f	                    @   s2  d 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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mZmZmZmZm Z m!Z!m"Z"m#Z# ddl$Z$ddl%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+ ddl,m-Z-m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6m7Z7m8Z8m9Z9m:Z: zddl;m<Z< W n e=y   e>Z<Y nw e?e@ZAdZBdZCdZDdZEddddZFdZGdZHdZIdZJeKd d! e-L D ZMerddlZdd"lNmOZOmPZP G d#d$ d$ePZQneRZQG d%d& d&e<ZSG d'd( d(eZTeeT ZUG d)d* d*eZVeVjWd+eCieVjXd+eEieVjYd+eDieVjZd+eEiiZ[G d,d- d-eZ\G d.d/ d/eZ]G d0d1 d1eZ^dd2d3d4eUd5ee_ d6e_d7e_fd8d9Z`G d:d; d;eaZbG d<d= d=ebZcd>d? Zd	ddAeRd7e_fdBdCZed7ee< fdDdEZfeSfdegdFeRdGe_dHe!e> fdIdJZheehddKZieehdLdKZjeSfdHe!e> fdMdNZkeSfdHe!e> fdOdPZldQdR ZmddFeRfdTdUZndVeRd7eeo fdWdXZp	@	@	SddVeRdYegdZegd[egd7egf
d\d]ZqdeVjWd@d@dSd@fdAeRdFeeR d^eVdYegd_egd[egd`egd7egfdadbZrG dcdd ddZsdddedfeRdge_dheRdieeU djeeU d7e"e_etf fdkdlZudme_d7eeT fdndoZv	ddpe_dme_dqee_ d7e^fdrdsZweVjWd@dfdpe_dFeRd^eVdZegdqee_ d7egfdtduZxdvdw Zydxdy ZzdzeRd{e_d7ee_ fd|d}Z{dzeRd~eRd7e_fddZ|d7e_fddZ}deRd~eRfddZ~deRfddZdeRd7e_fddZddFeRd~eRd7e_fddZdeQd7e_fddZdeQd7e_fddZddeQdFeeR d7e_fddZd7eRfddZded7e_fddZd7e_fddZd7eRfddZeVjWfd^eVd7eRfddZdddZdd Zd7e e_ee] f fddZdd Zdd Ze@dkree  dS dS )zFschema.py: Set of module functions for processing cloud-config schema.    N)defaultdict)Iterable)suppress)deepcopy)Enum)EACCES)partial)chain)	TYPE_CHECKINGDefaultDictList
NamedTupleOptionalTupleTypeUnioncast)featuresimporter	lifecyclesafeyaml)read_cfg_paths)INCLUSION_TYPES_MAPtype_from_starts_with)Paths)DataSourceNotFoundException)mkdtemp)errorget_modules_from_dirload_text_file	load_yaml
write_file)ValidationErrorz!versions.schema.cloud-config.jsonzschema-cloud-config-v1.jsonzschema-network-config-v1.jsonzschema-network-config-v2.jsontruefalsenull)TFNap  
{name}
{title_underbar}

{title}

.. tab-set::

{prefix3}.. tab-item:: Summary

{description}

{prefix6}**Internal name:** ``{id}``

{prefix6}**Module frequency:** {frequency}

{prefix6}**Supported distros:** {distros}

{prefix6}{activate_by_schema_keys}

{prefix3}.. tab-item:: Config schema

{property_doc}

{prefix3}.. tab-item:: Examples

{prefix6}::

{examples}
z5{prefix}* **{prop_name}:** ({prop_type}){description}zJ{prefix}* Each object in **{prop_name}** list supports the following keys:
deprecatedc                 C   s   g | ]
}|d  dkr|qS )r   # ).0tr(   r(   9/usr/lib/python3/dist-packages/cloudinit/config/schema.py
<listcomp>o   s    r,   )NotRequired	TypedDictc                   @   sj   e Zd ZU eed< eed< eed< eed< eje ed< ejeeef  ed< eed< e	ee  ed< d	S )

MetaSchemaidnametitledescriptiondistrosexamples	frequencyactivate_by_schema_keysN)
__name__
__module____qualname__str__annotations__typingr   r   dictr-   r(   r(   r(   r+   r/   y   s   
 r/   c                       s&   e Zd Zdedef fddZ  ZS )SchemaDeprecationErrormessageversionc                    s   t  j|fi | || _d S N)super__init__rA   )selfr@   rA   kwargs	__class__r(   r+   rD      s   
zSchemaDeprecationError.__init__)r8   r9   r:   r;   rD   __classcell__r(   r(   rG   r+   r?      s    r?   c                   @   s,   e Zd ZU eed< eed< defddZdS )SchemaProblempathr@   returnc                 C   s   | j  d| j S )N: )rK   r@   rE   r(   r(   r+   format   s   zSchemaProblem.formatN)r8   r9   r:   r;   r<   rO   r(   r(   r(   r+   rJ      s   
 rJ   c                   @   s    e Zd ZdZdZdZdZdZdS )
SchemaTypea  Supported schema types are either cloud-config or network-config.

    Vendordata and Vendordata2 format adheres to cloud-config schema type.
    Cloud Metadata is unique schema to each cloud platform and likely will not
    be represented in this enum.
    zcloud-confignetwork-configznetwork-config-v1znetwork-config-v2N)r8   r9   r:   __doc__CLOUD_CONFIGNETWORK_CONFIGNETWORK_CONFIG_V1NETWORK_CONFIG_V2r(   r(   r(   r+   rP      s    rP   latestc                   @   s(   e Zd ZdZdZdZdZdZdd ZdS )	InstanceDataTypez-Types of instance data provided to cloud-initz	user-datarQ   zvendor-datazvendor2-datac                 C      | j S rB   valuerN   r(   r(   r+   __str__   s   zInstanceDataType.__str__N)	r8   r9   r:   rR   USERDATArT   
VENDORDATAVENDOR2DATAr\   r(   r(   r(   r+   rX      s    rX   c                   @   s&   e Zd ZU eed< eed< eed< dS )InstanceDataPartconfig_typeschema_typeconfig_pathN)r8   r9   r:   rX   r<   rP   r;   r(   r(   r(   r+   r`      s   
 r`   c                   @   s   e Zd ZU eed< eed< dS )UserDataTypeAndDecodedContentuserdata_typecontentN)r8   r9   r:   r;   r<   r(   r(   r(   r+   rd      s   
 rd   , prefix	separatorschema_problemsri   rj   rL   c                C   s(   | tdd | }|r| | }|S )Nc                 S   s   |   S rB   )rO   )pr(   r(   r+   <lambda>   s    z)_format_schema_problems.<locals>.<lambda>)joinmap)rk   ri   rj   	formattedr(   r(   r+   _format_schema_problems   s   rq   c                       sF   e Zd ZdZ		d
dee dee f fddZdefdd	Z  Z	S )SchemaValidationErrorz<Raised when validating a cloud-config file against a schema.Nschema_errorsschema_deprecationsc                    s<   d  fdd}||dd| _ ||dd| _t   dS )zInit the exception an n-tuple of schema errors.

        @param schema_errors: An n-tuple of the format:
            ((flat.config.key, msg),)
        @param schema_deprecations: An n-tuple of the format:
            ((flat.config.key, msg),)
         c                    s8   | s| S  r
 d7  t tt| }  t| |d7  | S )N

ri   )sortedlistsetrq   )problemsri   r@   r(   r+   handle_problems   s   z7SchemaValidationError.__init__.<locals>.handle_problemszCloud config schema errors: rw   "Cloud config schema deprecations: N)rs   rt   rC   rD   )rE   rs   rt   r}   rG   r|   r+   rD      s   
zSchemaValidationError.__init__rL   c                 C   s
   t | jS rB   )boolrs   rN   r(   r(   r+   
has_errors  s   
z SchemaValidationError.has_errors)NN)
r8   r9   r:   rR   r   SchemaProblemsrD   r   r   rI   r(   r(   rG   r+   rr      s    "rr   c                   @   s   e Zd ZdZdS )"SchemaValidationInvalidHeaderErrorz>Raised when no valid header is declared in the user-data file.N)r8   r9   r:   rR   r(   r(   r(   r+   r   
  s    r   c                 C   s@   zddl m} W n
 ty   Y dS w |j|dpt|tfS )zWTYPE_CHECKER override allowing bytes for string type

    For jsonschema v. 3.0.0+
    r   )Draft4ValidatorFstring)
jsonschemar   ImportErrorTYPE_CHECKERis_type
isinstancebytes)checkerinstancer   r(   r(   r+   is_schema_byte_string  s   
r   Fconfigc                    sP   dt f fdd}|r|ng d}dt||}dd}| |  S )zcombine description with new/changed/deprecated message

    deprecated/changed/new keys require a _version key (this is verified
    in a unittest), a _description key is optional
    keyc                    sr    |  sdS  |  dd} |  dd|  d}|   d| d| } r1d| S d	|  d
S )Nru   _description_versionz	<missing z'_version key, please file a bug report>z in version .  z

**)get
capitalizestrip)r   key_descriptionvmsgannotater   r(   r+   format_message%  s   

z:_add_deprecated_changed_or_new_msg.<locals>.format_message)r&   changednewru   r3   )r;   rn   ro   r   rstrip)r   r   
filter_keyr   filter_keyschanged_new_deprecatedr3   r(   r   r+   "_add_deprecated_changed_or_new_msg  s   	r   c                 C   s   g }d}t |tod|v }| D ]\}|rO|d |jdi di dg v r+|g  S t|dr?|jdd dkr>|| q|jrN|jd dkrN|| qt|j|kr\|| qt|j|krkt|j}|g}q|S )zReturn the best_match errors based on the deepest match in the json_path

    This is useful for anyOf and oneOf subschemas where the most-specific error
    tends to be the most appropriate.
    r   type
propertiesenum	json_pathN)	r   r>   schemar   hasattrr   appendrK   len)errorsr   best_matches
path_depthr   errr(   r(   r+   cloud_init_deepest_matches?  s2   




r   r   r   
error_typec                 c   s2    |rt |d|gd}|||ddV  dS dS )zJsonschema validator for `deprecated` items.

    It yields an instance of `error_type` if deprecated that must be handled,
    otherwise the instance is consider faulty.
    T)r   r   deprecated_versiondevelN)r   r   )
_validatorr&   	_instancer   r   r   r   r(   r(   r+   r   `  s   r   )r   r   c                 #   s    ddl m} g }g }d}t|D ]U\}	}
t| j||
|	d}tt fdd|}tt fdd|}|s>||  n:t|trad|v rad	|
	d
dv rad|d  |
d
 v rad}|E dH  || q|sn||V  t
d|f |dV  |E dH  dS )a  Jsonschema validator for `anyOf`.

    It treats occurrences of `error_type` as non-errors, but yield them for
    external processing. Useful to process schema annotations, as `deprecated`.

    Cloud-init's network schema under the `config` key has a complexity of
    allowing each list dict item to declare it's type with a `type` key which
    can contain the values: bond, bridge, nameserver, physical, route, vlan.

    This schema 'flexibility' makes it hard for the default
    jsonschema.exceptions.best_match function to find the correct schema
    failure because it typically returns the failing schema error based on
    the schema of greatest match depth. Since each anyOf dict matches the
    same depth into the network schema path, `best_match` just returns the
    first set of schema errors, which is almost always incorrect.

    To find a better schema match when encountering schema validation errors,
    cloud-init network schema introduced schema $defs with the prefix
    `anyOf_type_`. If the object we are validating contains a 'type' key, and
    one of the failing schema objects in an anyOf clause has a name of the
    format anyOf_type_XXX, raise those schema errors instead of calling
    best_match.
    r   )
best_matchFschema_pathc                       t |   S rB   r   er   r(   r+   rm         z_anyOf.<locals>.<lambda>c                    
   t |  S rB   r   r   r   r(   r+   rm        
 r   
anyOf_type$refru   anyOf_type_TNz.%r is not valid under any of the given schemas)context)jsonschema.exceptionsr   	enumeratery   descendfilterextendr   r>   r   r"   )	validatoranyOfr   _schemar   r   
all_errorsall_deprecationsskip_best_matchindex	subschemaall_errserrsdeprecationsr(   r   r+   _anyOfx  s>   


r   c                 #   s    t |}g }g }|D ]4\}}	tj|	|d}
tt fdd|
}tt fdd|
}|s:|	}||  n|| qt|E dH  fdd|D }|rn|| dd	d
 |D }td|f V  dS |E dH  dS )zJsonschema validator for `oneOf`.

    It treats occurrences of `error_type` as non-errors, but yield them for
    external processing. Useful to process schema annotations, as `deprecated`.
    r   c                    r   rB   r   r   r   r(   r+   rm     r   z_oneOf.<locals>.<lambda>c                    r   rB   r   r   r   r(   r+   rm     r   Nc                    s    g | ]\}}  |r|qS r(   )is_valid)r)   is)r   r   r(   r+   r,     s     z_oneOf.<locals>.<listcomp>rg   c                 s       | ]}t |V  qd S rB   )repr)r)   r   r(   r(   r+   	<genexpr>      z_oneOf.<locals>.<genexpr>z%r is valid under each of %s)	r   ry   r   r   r   r   r   rn   r"   )r   oneOfr   r   r   
subschemasr   r   r   r   r   r   r   first_valid
more_validreprsr(   )r   r   r   r+   _oneOf  s4   



r   c            
      C   s   ddl m} m} ddlm} t| j}ddi|d d< i }t| dr2d	|d
< | j	dt
}d|i}n| j}ttf|d< d|i}t| j}t|t< t|d< t|d< t|d< |d||dd|}ddd}	|	|_||fS )zGet metaschema validator and format checker

    Older versions of jsonschema require some compatibility changes.

    @returns: Tuple: (jsonschema.Validator, FormatChecker)
    @raises: ImportError when jsonschema is not present
    r   )r   FormatChecker)creater   r   r   labelr   FadditionalPropertiestype_checkerdefault_typesr   r   r   draft4)meta_schema
validatorsrA   Nc                 [   s$   t dd | ||}t|ddu S )zgOverride version of `is_valid`.

        It does ignore instances of `SchemaDeprecationError`.
        c                 S   s   t | t S rB   )r   r?   r   r(   r(   r+   rm   %  s    z<get_jsonschema_validator.<locals>.is_valid.<locals>.<lambda>N)r   iter_errorsnext)rE   r   r   __r   r(   r(   r+   r     s
   
z*get_jsonschema_validator.<locals>.is_validr(   rB   )r   r   r   jsonschema.validatorsr   r   META_SCHEMAr   r   redefiner   DEFAULT_TYPESr;   r   r>   
VALIDATORS_validator_deprecatedDEPRECATED_KEY_validator_changedr   r   r   )
r   r   r   r   validator_kwargsr   typesr   cloudinitValidatorr   r(   r(   r+   get_jsonschema_validator  s<   



r   Tc              
   C   s|   ddl m} z| | W dS  |y= } z#|r,ttddd |jD |jgd|t	d| W Y d}~dS d}~ww )	a   Validate provided schema meets the metaschema definition. Return strict
    Validator and FormatChecker for use in validation
    @param validator: Draft4Validator instance used to validate the schema
    @param schema: schema to validate
    @param throw: Sometimes the validator and checker are required, even if
        the schema is invalid. Toggle for whether to raise
        SchemaValidationError or log warnings.

    @raises: ImportError when jsonschema is not present
    @raises: SchemaValidationError when the schema is invalid
    r   )SchemaError.c                 S      g | ]}t |qS r(   r;   r)   rl   r(   r(   r+   r,   I      z3validate_cloudconfig_metaschema.<locals>.<listcomp>rs   zGMeta-schema validation failed, attempting to validate config anyway: %sN)
r   r   check_schemarr   rJ   rn   rK   r@   LOGwarning)r   r   throwr   r   r(   r(   r+   validate_cloudconfig_metaschema1  s&   r  network_configc                 C   s    d| v r| d  dS |  dS )z6Return the version of the network schema when present.networkrA   r   )r	  r(   r(   r+   network_schema_versionT  s   
r  strictr   log_detailsc              
   C   sb  z
ddl m}m} W n ty   td Y dS w t }tj	|d}t
| }d|vr0d|i}t|}	t||	dd | }
g }z|
| W n% |ym } z|td	j|j|jd
d|j  W Y d}~nd}~ww tj|ryt| |r|r|rt|	\}}tt||	||d t||rt|tjj ddd}ntjj d}t | dS )aj  On systems with netplan, validate network_config schema for file

    Leverage NetplanParser for error annotation line, column and detailed
    errors.

    @param network_config: Dict of network configuration settings validated
        against
    @param strict: Boolean, when True raise SchemaValidationErrors instead of
       logging warnings.
    @param annotate: Boolean, when True, print original network_config_file
        content with error annotations
    @param log_details: Boolean, when True logs details of validation errors.
       If there are concerns about logging sensitive userdata, this should
       be set to False.

    @return: True when schema validation was performed. False when not on a
        system with netplan and netplan python support.
    @raises: SchemaValidationError when netplan's parser raises
        NetplanParserExceptions.
    r   )NetplanParserExceptionParserz<Skipping netplan schema validation. No netplan API availableFzetc/netplan/network-config.yamlr
  i  )modeformat-l{line}.c{col}linecolzInvalid netplan schema. Nr   failed schema validation!

rh   ^ failed schema validation! You may run 'sudo cloud-init schema --system' to check the details.T)!netplanr  r  r   r  debugr   osrK   rn   r   r   dumpsr!   load_yaml_hierarchyr   rJ   rO   r  columnr@   existsshutilrmtreeload_with_marksprintannotated_cloudconfig_filerr   rq   rP   rT   r[   r  )r	  r  r   r  r  r  	parse_dirnetplan_filenet_cfgsrc_contentparserr   r   _marksr@   r(   r(   r+   netplan_validate_network_schema[  sj   





r,  rb   strict_metaschemalog_deprecationsc                 C   s*  ddl m} |tjkr"t| }|dkrtj}n|dkrtj}t|}|tjkr5t| ||dr0dS | r5dS |du r=t|}zt	 \}	}
|rLt
|	|dd	 W n ty\   td
 Y dS w |	||
 d}g }g }g }t|| dd dD ]U}ddd |jD }|s|jdkr|j|krtd|j}|r|d }t|tr|jdkst|jtjr|t||j qu|t||j qu|t||j qu|r|rt |dd}t!| |rt |dd}t"| |r|s|s|rt#||| |r|rt ||j$ ddd}n|j$ d}t%| dS )aP  Validate provided config meets the schema definition.

    @param config: Dict of cloud configuration settings validated against
        schema. Ignored if strict_metaschema=True
    @param schema: jsonschema dict describing the supported schema definition
       for the cloud config module (config.cc_*). If None, validate against
       global schema.
    @param schema_type: Optional SchemaType.
       One of: SchemaType.CLOUD_CONFIG or SchemaType.NETWORK_CONFIG_V1 or
            SchemaType.NETWORK_CONFIG_V2
       Default: SchemaType.CLOUD_CONFIG
    @param strict: Boolean, when True raise SchemaValidationErrors instead of
       logging warnings.
    @param strict_metaschema: Boolean, when True validates schema using strict
       metaschema definition at runtime (currently unused)
    @param log_details: Boolean, when True logs details of validation errors.
       If there are concerns about logging sensitive userdata, this should
       be set to False.
    @param log_deprecations: Controls whether to log deprecations or not.

    @raises: SchemaValidationError when provided config does not validate
        against the provided schema.
    @raises: RuntimeError when provided config sourced from YAML is not a dict.
    @raises: ValueError on invalid schema_type not in CLOUD_CONFIG or
        NETWORK_CONFIG_V1 or NETWORK_CONFIG_V2
    r   	available      )r	  r  r  TFN)r  z5Ignoring schema validation. jsonschema is not present)format_checkerc                 S   rY   rB   )rK   r   r(   r(   r+   rm   
  s    z-validate_cloudconfig_schema.<locals>.<lambda>r   r   c                 S   r   r(   r   r  r(   r(   r+   r,     r  z/validate_cloudconfig_schema.<locals>.<listcomp>r   z#.*\('(?P<name>.*)' was unexpected\)r1   r   z"Deprecated cloud-config provided: rw   r  r  rh   r  )&cloudinit.net.netplanr0  rP   rT   r  rV   rU   
get_schemar,  r   r  r   r  r  rx   r   rn   rK   r   r   rematchr@   r   r?   rA   r   should_log_deprecationr   DEPRECATION_INFO_BOUNDARYr   rJ   rq   infor&   rr   r[   r  )r   r   rb   r  r-  r  r.  netplan_availablenetwork_versionr   r   r   r   r   info_deprecationsschema_errorrK   
prop_matchr@   detailsr(   r(   r+   validate_cloudconfig_schema  s   #













rB  c                   @   s   e Zd ZdededefddZededee defd	d
Zde	fddZ
e	d dee dee dee dededefddZdee dededee fddZde	de	defddZdS )!
_Annotatorcloudconfigoriginal_contentschemamarksc                 C   s   || _ || _|| _d S rB   )_cloudconfig_original_content_schemamarks)rE   rD  rE  rF  r(   r(   r+   rD   L  s   
z_Annotator.__init__r2   rf   rL   c                 C   s   d |}d|  d| dS )Nr  # z: -------------
rv   )rn   )r2   rf   bodyr(   r(   r+   _build_footerV  s   
z_Annotator._build_footerrk   c                 C   sz   t t}|D ]4\}}td|}|r"| \}}|t| | nd }|| j|  | |d ur:dj|||d}q|S )Nz&format-l(?P<line>\d+)\.c(?P<col>\d+).*zLine {line} column {col}: {msg})r  r  r   )	r   ry   r7  r8  groupsintr   rI  rO   )rE   rk   errors_by_linerK   r   r8  r  r  r(   r(   r+   _build_errors_by_line[  s   z _Annotator._build_errors_by_lineru   r{   labelsfooterr   label_prefixc                 C   sB   | D ]}| | }| | | d| d|  |d7 }q|S )NrJ  rM   r2  )r   )r{   rQ  rR  r   rS  problemr   r(   r(   r+   _add_problemsk  s   

z_Annotator._add_problemslinesrO  deprecations_by_linec              	      s   g }g }g }d}d}t |dD ]8\}	}
||	 }||	 }|s|rBg } j||||dd} j||||dd}||
d d|  q||
 q|t fddtd	d d
|fd|ff |S )Nr2  E)rS  Dz		# ,c                    s
    j |  S rB   )rL  seqrN   r(   r+   rm     r   z._Annotator._annotate_content.<locals>.<lambda>c                 S   s   t | d S )Nr2  )r   r[  r(   r(   r+   rm     r   ErrorsDeprecations)r   rU  r   rn   r   ro   r   )rE   rV  rO  rW  annotated_contenterror_footerdeprecation_footererror_indexdeprecation_indexline_numberr  r   r   rQ  r(   rN   r+   _annotate_contentz  sD   

z_Annotator._annotate_contentrs   rt   c                 C   sF   |s|s| j S | j d}| |}| |}| |||}d|S )Nr  )rH  splitrP  re  rn   )rE   rs   rt   rV  rO  rW  r_  r(   r(   r+   r     s   


z_Annotator.annotateN)ru   )r8   r9   r:   r>   r;   rD   staticmethodr   rL  r   rP  rN  rU  re  r   r(   r(   r(   r+   rC  K  sT    


,rC  rs   rt   rD  rE  rF  rs   rt   c                C   s   t | |||p	g |pg S )a  Return contents of the cloud-config file annotated with schema errors.

    @param cloudconfig: YAML-loaded dict from the original_content or empty
        dict if unparsable.
    @param original_content: The contents of a cloud-config file
    @param schemamarks: Dict with schema marks.
    @param schema_errors: Instance of `SchemaProblems`.
    @param schema_deprecations: Instance of `SchemaProblems`.

    @return Annotated schema
    )rC  r   )rD  rE  rF  rs   rt   r(   r(   r+   r$    s   r$  rf   c              	   C   sb   ddl m} || vrg S g }t|  dD ]\}}||r.|td| d||d q|S )a  Annotate and return schema validation errors in merged cloud-config.txt

    When merging multiple cloud-config parts cloud-init logs an error and
    ignores any user-data parts which are declared as #cloud-config but
    cannot be processed. the handler.cloud_config module also leaves comments
    in the final merged config for every invalid part file which begin with
    MERGED_CONFIG_SCHEMA_ERROR_PREFIX to aid in triage.
    r   )MERGED_PART_SCHEMA_ERROR_PREFIXr2  zformat-lz.c1zIgnored invalid user-data: )cloudinit.handlers.cloud_configri  r   
splitlines
startswithr   rJ   replace)rf   ri  r   line_numr  r(   r(   r+   )process_merged_cloud_config_part_problems  s"   

	ro  rc   instance_data_pathc                 C   s:  ddl m}m}m}m} t|}d}|dkrnz||| |}W nI |y3 }	 z	tt|dg|	d}	~	w |yN }	 ztdt	|	 dd	 W Y d}	~	nd}	~	w |yg }	 ztt	|	dd	 W Y d}	~	nd}	~	ww d
}t|}|s|
d\}
}}tt|d|  d|
 ddt g|dkrtd| d t||S )a  
    Return tuple of user-data-type and rendered content.

    When encountering jinja user-data, render said content.

    :return: UserDataTypeAndDecodedContent
    :raises: SchemaValidationError when non-jinja content found but
        header declared ## template: jinja.
    :raises JinjaSyntaxParsingException when jinja syntax error found.
    :raises JinjaLoadError when jinja template fails to load.
    r   )JinjaLoadErrorJinjaSyntaxParsingExceptionNotJinjaErrorrender_jinja_payload_from_filezformat-l1.c1ztext/jinja2zRDetected type '{user_data_type}' from header. But, content is not a jinja templateNz&Failed to render templated user-data. Tsys_exitzformat-l2.c1r  z!Unrecognized user-data header in z: "z%".
Expected first line to be one of: rg   text/cloud-configzUser-data type 'z.' not currently evaluated by cloud-init schema)!cloudinit.handlers.jinja_templaterq  rr  rs  rt  r   rr   rJ   r   r;   	partitionr   rn   USERDATA_VALID_HEADERSr#  rd   )rc   rf   rp  rq  rr  rs  rt  user_data_typeschema_positionr   header_liner*  r(   r(   r+   &_get_config_type_and_rendered_userdata  sb   	



r~  c                 C   s  ddl m} t| }|std|j| f  dS |tjfv r$t|j|}nt| ||}|j	dvr1dS |j
}t|}	z|rCt|\}
}nt|}
i }W ne tjy } zXd }}d}t|drjt|drjt|d}nt|d	ryt|d	ryt|d	}|r|jd }|jd }|	td
j||dd| t| t|	}|rtti |i |jd ||d}~ww t|
ts|st|j d|  d|tjkr|
d|
std dS t |
}|dkrtj!}t"|
d|drdS | rtd dS n|dkrtj#}t$|}zt%|
||dddstd|j d W dS W dS  ty] } z:|& r)|	|j7 }	|r9tt|
|||	|j'd n|j'rIt(|j'ddd}t| |	rRt|	d|W Y d}~dS d}~ww )a  Validate cloudconfig file adheres to a specific jsonschema.

    @param config_path: Path to the yaml cloud-config file to parse, or None
        to default to system userdata from Paths object.
    @param schema: Dict describing a valid jsonschema to validate against.
    @param schema_type: One of SchemaType.NETWORK_CONFIG or CLOUD_CONFIG
    @param annotate: Boolean set True to print original config file with error
        annotations on the offending lines.
    @param instance_data_path: Path to instance_data JSON, used for text/jinja
        rendering.

    :return: True when validation was performed successfully
    :raises SchemaValidationError containing any of schema_errors encountered.
    :raises RuntimeError when config_path does not exist.
    r   r/  z,Empty '%s' found at %s. Nothing to validate.F)rQ   rw  r2  Ncontext_markproblem_markr  r  zFile {0} is not valid YAML. {1}r  r   z is not a YAML dict.r
  z:Skipping network-config schema validation on empty config.r1  T)r	  r  r   zSSkipping network-config schema validation for version: 2. No netplan API available.)r   rb   r  r.  z	Skipping z2 schema validation. Jsonschema dependency missing.rh  r~   rg   rh   ))r5  r0  r   r#  r[   rP   rT   rd   r~  re   rf   ro  r   r"  yaml	safe_load	YAMLErrorr   getattrr  r  r   rJ   rO   r;   rr   r$  rs   r   r>   RuntimeErrorr   r  rV   r,  rU   r6  rB  r   rt   rq   )rc   r   rb   r   rp  r<  decoded_contentdecoded_configrf   r   rD  r+  r   r  r  markr?  r=  r@   r(   r(   r+   validate_cloudconfig_file1  s   







"

	
r  c                 C   s   | dkrdS | dkrdS dS )zProvide a sorting weight for documentation of property types.

    Weight values ensure 'array' sorted after 'object' which is sorted
    after anything else which remains unsorted.
    arrayr1  objectr2  r   r(   rZ   r(   r(   r+   _sort_property_order  s
   r  c                 c   s>    | D ]}t |trt |ttfst|E d H  q|V  qd S rB   )r   r   r;   r   _flatten)xsxr(   r(   r+   r    s   r  property_dict	multi_keyc                 C   sn   g }|  |i D ](}| trq| dr$|dd | dg D  q| dr0||d  qtt|S )Nr   c                 S       g | ]}d t || d qS ``	_YAML_MAPr   )r)   
enum_valuer(   r(   r+   r,     s    z,_collect_subschema_types.<locals>.<listcomp>r   )r   r   r   r   ry   r  )r  r  property_typesr   r(   r(   r+   _collect_subschema_types  s   



r  defsc           
      C   sn  t | | | dg }t|ts|g}| dr"dd | d D }n| dr0|t| d n| dr=|t| d t|dkrH|d }n|jtd	 d
	|}| di }|dg }t|tsg|g}t
|}t|di |di D ]}t||}|r|dkrqx|| qx|rt|dkr| d|d  S |jtd	 dd
	| d}	| d|	 S |pdS )zNReturn a string representing a property type from a given
    jsonschema.
    r   r   c                 S   r  r  r  r)   kr(   r(   r+   r,     s    z&_get_property_type.<locals>.<listcomp>r   r   r2  r   r4  /items	UNDEFINEDz of ())flatten_schema_refsr   r   ry   r   r  r   sortr  rn   r   r	   _get_property_typer   )
r  r  r  property_typer  sub_property_typesprune_undefinedsub_itemsub_typesub_property_docr(   r(   r+   r    sB   








r  c                 C   s>   |}t dd| } t dd|| } t dd|| } | S )a  Parse description from the meta in a format that we can better
    display in our docs. This parser does three things:

    - Guarantee that a paragraph will be in a single line
    - Guarantee that each new paragraph will be aligned with
      the first paragraph
    - Proper align lists of items

    @param description: The original description in the meta.
    @param prefix: The number of spaces used to align the current description
    z
(\S)\n(\S)z\1 \2z\n\nz\n\n{}z\n( +)-z\n{}-)r7  subrO   )r3   ri   list_paragraphr(   r(   r+   _parse_description  s   r  src_cfgc                 C   s   d| v r|  ddd}| ||  d| v rUd| d v r2| d  ddd}| d ||  d| d v rU| d d D ]}d|v rT| ddd}|||  q>t| dg | dg | dg D ]}d|v r}| ddd}|||  qgdS )	zEFlatten schema: replace $refs in src_cfg with definitions from $defs.r   z#/$defs/ru   r  r   r   allOfN)poprm  updater	   r   )r  r  	reference
sub_schemar(   r(   r+   r  '  s.   


r  c                 C   s,   |  dd}|s
dS |D ]}| | qdS )zFlatten schema: Merge allOf.

    If a schema as allOf, then all of the sub-schemas must hold. Therefore
    it is safe to merge them.
    r  N)r  r  )r  sub_schemasr  r(   r(   r+   flatten_schema_all_ofA  s   r  prop_configc                 C   s   dt dtdtfdd}| di }| di }g }g }|| || t||D ]}|||| q&dt||}|r>d	| }|S )
aG  Return accumulated property description.

    Account for the following keys:
    - top-level description key
    - any description key present in each subitem under anyOf or allOf

    Order and deprecated property description after active descriptions.
    Add a trailing stop "." to any description not ending with ":".
    r   descriptionsdeprecated_descriptionsc                 S   sB   t t| jdr|t|  d S | dr|t|  d S d S )N)r   changed_versionnew_versionr3   )anyro   r   r   r   )r   r  r  r(   r(   r+   assign_descriptionsY  s   
z6_get_property_description.<locals>.assign_descriptionsr   r   r   r   )r>   ry   r   r	   rn   )r  r  r   r   r  r  r  r3   r(   r(   r+   _get_property_descriptionN  s$   

r     c                    s  |d }g }  ddu rdS  fdddD } fdd|D }|D ]}| D ]\}}	t|	| t|	 |	 ddu r>q)t|	}
|	 d	|}|tj||t|
|d t	|	|d
 |	 d}|rt|| | dsr| dr|t
j||d |t|||d | dg D ] }| ds| dr|t
j||d |t|||d qd|	v sd|	v r|t|	||d q)q#d|S )zDReturn restructured text describing the supported schema properties.  hiddenTru   c                    s$   g | ]}d  vs| d  vr|qS )r  r(   r)   r   r   r(   r+   r,   ~  s
    z%_get_property_doc.<locals>.<listcomp>)r   patternPropertiesc                    s   g | ]}  |i qS r(   r  r  r  r(   r+   r,     s    r   )ri   	prop_namer3   	prop_typer  r   r  )ri   r  r  ri   r   rv   )r   r  r  r  r  r   SCHEMA_PROPERTY_TMPLrO   r  r  SCHEMA_LIST_ITEM_TMPL_get_property_docrn   )r   r  ri   
new_prefixr   property_keysproperty_schemasprop_schemaprop_keyr  r3   r   r  
alt_schemar(   r  r+   r  x  sz   




5r  metac                 C   s   t  }tj|jd}| d}|sdS d}|D ]3}t|tr;|d r,d|d  d}nd}|ttj||d  }t	
|dd}|d|7 }q|S )	zAReturn restructured text describing the meta examples if present.module-docsr5   ru   commentrJ  r  filer  )r   r  rK   rn   docs_dirr   r   r>   r   textwrapindentrf  )r  pathsmodule_docs_dirr5   rst_contentexampler  indented_linesr(   r(   r+   _get_examples  s"   

r  c                 C   s2   |  dsdS ddd | d D }d| dS )Nr7   ru   rg   c                 s   s    | ]	}d | d V  qdS )r  Nr(   r  r(   r(   r+   r     s    
z3_get_activate_by_schema_keys_doc.<locals>.<genexpr>z**Activate only on keys:** rv   )r   rn   )r  schema_keysr(   r(   r+    _get_activate_by_schema_keys_doc  s   

r  c           	      C   s  |du rt  }| r|stdt|  }h d}dh}d}|| r*d|| }n|| | r7d|| }|r=t|tt| }d|d< d	|d
< d|d< t	t
t|d d	|d< |di }|| d rv|| d i }t
t|}t|d  rzt||d	d|d< W n ty   td d|d< Y nw |ddsd|d< t	t| d	|d< |d sd|d< d| d |d< tdd| d |d< t| |d< tjdi |}|S )zReturn reStructured text rendering the provided metadata.

    @param meta: Dict of metadata to render.
    @param schema: Optional module schema, if absent, read global schema.
    @raise KeyError: If metadata lacks an expected key.
    Nz"Expected non-empty meta and schema>   r0   r1   r2   r4   r5   r6   r3   r7   ru   z(Missing required keys in module meta: {}z3Additional unexpected keys found in module meta: {}property_headerz      prefix6r  prefix3r3   z$defsr0   r   r  property_docz3Unable to render property_doc due to invalid schemaz+      No schema definitions for this moduler5   z$         No examples for this modulerg   r4   r   -r1   title_underbarr(   )r6  
ValueErrorrz   keysrO   KeyErrorr>   r   r  r  r   r;   r   r  valuesr  AttributeErrorr  r  r  rn   r7  r  r  SCHEMA_DOC_TMPL)	r  r   r  required_keysoptional_keyserror_message	meta_copyr  templater(   r(   r+   get_meta_doc  sh   	

r  c                  C   s   t jt jt} t| S rB   )r  rK   dirnameabspath__file__r   )configs_dirr(   r(   r+   get_modules(  s   r  requested_modulesc           
      C   s   d}t t  dg }t| t|}|r&tdt |d|dd t }t	 }t
|D ]E}d| v s:|| v rut|dgdg\}}|rut|d	 }	||	jd
 rn|	j||	jd
 i  |t|	j|pkd7 }q0||	jpsd7 }q0|S )zaLoad module docstrings

    Docstrings are generated on module load. Reduce, reuse, recycle.
    ru   allz+Invalid --docs value {}. Must be one of: {}rg   Tru  zcloudinit.configr  r   r0   )ry   r  r  rz   
differencer   rO   rn   get_module_docsr6  rx   r   find_moduleimport_moduler   r  r  r  rR   )
r  docsall_modulesinvalid_docsmodule_docsr   mod_namemod_locsr*  modr(   r(   r+   load_doc-  s4   
r  c                   C   s   t jt jt jtdS )Nschemas)r  rK   rn   r  r  r  r(   r(   r(   r+   get_schema_dirO  s   r  c                  C   sF   t  } i }tj| jd}t| dD ]}|tt| q|S )z<Return a dict keyed on cc_<mod_name> with documentation infor  z/*/data.yaml)	r   r  rK   rn   r  globr  r    r   )r  mod_docsr  mod_docr(   r(   r+   r  S  s   r  c              	   C   s\   t jt t|  d }d}z
tt|}W |S  tt	fy-   t
d| j| i  Y S w )ziReturn jsonschema for a specific type.

    Return empty schema when no specific schema file exists.
    rW   Nz<Skipping %s schema validation. No JSON schema file found %s.)r  rK   rn   r  SCHEMA_FILES_BY_TYPEjsonloadsr   IOErrorOSErrorr  r  r[   )rb   schema_filefull_schemar(   r(   r+   r6  ]  s   r6  c                 C   s   | s	t jddd} | jdddd | jdd	ttjjtjjgd
tj d | jddtdt 	d d | jddddd | jddddd | jddddd | S )z0Return a parser for supported cmdline arguments.cloudconfig-schemazSchema validation and documentation of instance-data configuration provided to cloud-init. This includes: user-data, vendor-data and network-config)progr3   z-cz--config-filez@Path of the cloud-config or network-config YAML file to validate)helpz-tz--schema-typezSWhen providing --config-file, the schema type to validate config against. Default: )r   choicesr  z-iz--instance-datazbPath to instance-data.json file for variable expansion of '##template: jinja' user-data. Default: instance_data)r   r  z--system
store_trueFzVValidate the system instance-data provided as vendor-data user-data and network-config)actiondefaultr  z-dz--docs+zCPrint schema module docs. Choices: all or space-delimited cc_names.)nargsr  z
--annotatez;Annotate existing instance-data files any discovered errors)
argparseArgumentParseradd_argumentr;   rP   rS   r[   rT   r   get_runpathr)  r(   r(   r+   
get_parserr  s`   

		r  c                 C   st   | j | j| jg}tdd |D dkrtddd t| j| jgr(| jr(td | jr6| jr8tddd d	S d	S d	S )
z:Error or warn on invalid exclusive parameter combinations.c                 S   s   g | ]}|r|qS r(   r(   )r)   argr(   r(   r+   r,     r  z*_assert_exclusive_args.<locals>.<listcomp>r2  z;Expected one of --config-file, --system or --docs argumentsTru  z[WARNING: The --schema-type parameter is inapplicable when either --system or --docs presentz;Invalid flag combination. Cannot use --annotate with --docsN)	config_filer  systemr   r   r  rb   r#  r   )argsexclusive_argsr(   r(   r+   _assert_exclusive_args  s    
r%  c              
   C   s  dt dtdtdtfdd}ztdd}W n3 ttfy7 } z|jtkr,td	 t }n W Y d
}~nd
}~w t	yG   t }t
d Y nw | jrO| j}nt dkr[|d}n|d}g }| jr| jrnt| j}ntj}|tjkrztj}ntj}|t||| j nUt dkrtddd ||dd}|ttjtj| ttjtj||ddttjtj||ddttjtj|dpdg}	|	D ]}
|
jrtj|
jr||
 qtj|d jstd|d j dddd ||fS )a  Return appropriate instance-data.json and instance data parts

    Based on command line args, and user permissions, determine the
    appropriate instance-data.json to source for jinja templates and
    a list of applicable InstanceDataParts such as user-data, vendor-data
    and network-config for which to validate schema. Avoid returning any
    InstanceDataParts when the expected config_path does not exist.

    :return: A tuple of the instance-data.json path and a list of
        viable InstanceDataParts present on the system.
    r  primary_path_keyraw_fallback_path_keyrL   c                 S   s   |  |pd}tt- t|js(|  |pd}t|jr0|W  d   S W d   |S W d   |S 1 s;w   Y  |S )ak  Get processed data path when non-empty of fallback to raw data path.

        - When primary path and raw path exist and are empty, prefer primary
          path.
        - When primary path is empty but the raw fallback path is non-empty,
          this indicates an invalid and ignored raw user-data was provided and
          cloud-init emitted a warning and did not process unknown raw
          user-data.
          In the case of invalid raw user-data header, prefer
          raw_fallback_path_key so actionable sensible warnings can be
          reported to the user about the raw unparsable user-data.
        ru   N)	get_ipathr   FileNotFoundErrorr  statst_size)r  r&  r'  primary_datapathraw_pathr(   r(   r+   get_processed_or_fallback_path  s   


zBget_config_paths_from_args.<locals>.get_processed_or_fallback_pathtrust)fetch_existing_datasourcez=Using default instance-data/user-data paths for non-root userNzEdatasource not detected, using default instance-data/user-data paths.r   r  instance_data_sensitivezNUnable to read system userdata or vendordata as non-root user. Try using sudo.Tru  cloud_configuserdata_rawvendor_cloud_configvendordata_rawvendor2_cloud_configvendordata2_rawr	  ru   zConfig file z does not existz	Error: {}fmtrv  )r   r;   r   r  r  errnor   r  r  r   r  r  r  getuidr  r!  rb   rP   rS   rT   rX   r]   r   r`   r   r^   r_   r(  rc   rK   r  )r#  r.  r  r   rp  config_filesrb   instancedata_typeuserdata_filesupplemental_config_files	data_partr(   r(   r+   get_config_paths_from_args  s   




rA  c                 C   s  t | t }|jrtt|j dS t|\}}d}tt|dk}|r5tdddd |D   d}g }t	|dD ]\}}	d	}
|rTtd
| d|	j
 d|	j d |	jtjkr`t|	j}n|}zt|	j||	j|j|}
W n^ ty } z'|jst| d|	j
 d|	j  tt||d d ||	j
 W Y d}~q<d}~w ty } z t| d|	j
 tt||d d ||	j
 W Y d}~q<d}~ww |
r|jr|	j}n|	j
}t| d| q<|rtddd |D ddd dS dS )z@Handle provided schema args and perform the appropriate actions.Nru   r2  z!Found cloud-config data types: %srg   c                 s   s    | ]}t |jV  qd S rB   )r;   ra   )r)   cfg_partr(   r(   r+   r   U  s    z%handle_schema_args.<locals>.<genexpr>r  Fr  r   z at :zInvalid r   z
Error: {}
)r9  zValid schema c                 s   r   rB   r   )r)   r   r(   r(   r+   r     r   zError: Invalid schema: {}
Tr8  )r%  r6  r  r#  r  rA  r   r   rn   r   ra   rc   rb   rP   rT   r  r   rr   r   r;   r   r  r!  )r1   r#  r  rp  r<  nested_output_prefixmulti_config_outputerror_typesidxrB  performed_schema_validation
cfg_schemar   cfgr(   r(   r+   handle_schema_argsG  s   
rK  c                  C   s   t  } td|   dS )zDTool to validate schema of a cloud-config file or print schema docs.r  r   )r  rK  
parse_argsr  r(   r(   r+   main  s   rM  __main__)FN)T)FFTrB   )r  )rR   r  r  r
  loggingr  r7  r   sysr  collectionsr   collections.abcr   
contextlibr   copyr   r   r   r:  r   	functoolsr   	itertoolsr	   r=   r
   r   r   r   r   r   r   r   r   r  	cloudinitr   r   r   r   cloudinit.cmd.develr   cloudinit.handlersr   r   cloudinit.helpersr   cloudinit.sourcesr   cloudinit.temp_utilsr   cloudinit.utilr   r   r   r    r!   r   r"   r   	Exception	getLoggerr8   r  VERSIONED_USERDATA_SCHEMA_FILEUSERDATA_SCHEMA_FILENETWORK_CONFIG_V1_SCHEMA_FILENETWORK_CONFIG_V2_SCHEMA_FILEr  r  r  r  r   rx   r  rz  typing_extensionsr-   r.   r/   r>   r?   rJ   r   rP   rS   rT   rU   rV   r	  rX   r`   rd   r;   rq   r  rr   r   r   r   r   r   r   r   r   r   r   r   r  rN  r  r,  rB  rC  r   r$  ro  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  ry   r  r  r  r6  r  r%  rA  rK  rM  exitr(   r(   r(   r+   <module>   s  ,

)
#'

H
*L#	
c
 p


!
H
 ,*F	J"

D
}C
