U
    Ad                  	   @   s  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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 ddlZdd	lmZmZ dd
lmZ ddl m!Z!m"Z"m#Z# zddl$m%Z& e&Z%W n e'k
r   e(Z%Y nX e)e*Z+dZ,dZ-ddddZ.dZ/dZ0dZ1dZ2dZ3dZ4dZ5dZ6dZ7ervddlZddl8m9Z9m:Z: G dd de:Z;ne<Z;G dd  d e%Z=G d!d" d"eZ>ee> Z?dd#d$e?ee@ e@e@d%d&d'ZAG d(d) d)eBZCd*d+ ZDde<e@d-d.d/ZEe=feFe<e@ee( d0d1d2ZGeeGdd3ZHeeGd4d3ZIe=fee( d5d6d7ZJe=fee( d5d8d9ZKd:d; ZLde<d=d>d?ZMde<ee< eFeFeFeFd@dAdBZNG dCdD dDZOdddEe<ePe<ee? ee? ee@ePf dFdGdHZQddIdJZRdKdL ZSdMdN ZTe<e@ee@ dOdPdQZUe<e<e@dRdSdTZVe@dUdVdWZWe<e<dXdYdZZXe<d[d\d]ZYe<e@d^d_d`ZZde<e<e@dbdcddZ[e;e@dedfdgZ\e;e@dedhdiZ]de;ee< e@djdkdlZ^e<dUdmdnZ_e`e@dodpdqZae@dUdrdsZbe<dUdtduZce<dUdvdwZdddxdyZedzd{ Zfd|d} Zge*d~kreheg  dS )zFschema.py: Set of module functions for processing cloud-config schema.    N)defaultdict)Iterable)deepcopy)partial)chain)TYPE_CHECKINGList
NamedTupleOptionalTypeUnioncast)importersafeyaml)Init)errorget_modules_from_dir	load_fileValidationErrorz!versions.schema.cloud-config.jsonzschema-cloud-config-v1.jsontrueZfalseZnull)TFNs   #cloud-configz
{name}
{title_underbar}
**Summary:** {title}

{description}

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

**Module frequency:** {frequency}

**Supported distros:** {distros}

{activate_by_schema_keys}{property_header}
{property_doc}

{examples}
z**Config schema**:z3{prefix}**{prop_name}:** ({prop_type}){description}zH{prefix}Each object in **{prop_name}** list supports the following keys:z**Examples**::

z
    # --- Example{0} ---
deprecatedzDEPRECATED: )NotRequired	TypedDictc                   @   sb   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d< eed< eee  ed< d	S )

MetaSchemanameidtitledescriptiondistrosexamples	frequencyactivate_by_schema_keysN)__name__
__module____qualname__str__annotations__typingr   r    r)   r)   9/usr/lib/python3/dist-packages/cloudinit/config/schema.pyr   K   s   
r   c                   @   s   e Zd ZdS )SchemaDeprecationErrorN)r#   r$   r%   r)   r)   r)   r*   r+   Y   s   r+   c                   @   s,   e Zd ZU eed< eed< edddZdS )SchemaProblempathmessagereturnc                 C   s   | j  d| j S )N: )r-   r.   selfr)   r)   r*   formata   s    zSchemaProblem.formatN)r#   r$   r%   r&   r'   r4   r)   r)   r)   r*   r,   ]   s   
r,   , prefix	separator)schema_problemsr7   r8   r0   c                C   s(   | tdd | }|r$| | }|S )Nc                 S   s   |   S N)r4   )pr)   r)   r*   <lambda>n       z)_format_schema_problems.<locals>.<lambda>)joinmap)r9   r7   r8   Z	formattedr)   r)   r*   _format_schema_problemsh   s    r@   c                       s@   e Zd ZdZd	ee ee d fddZedddZ  Z	S )
SchemaValidationErrorz<Raised when validating a cloud-config file against a schema.Nschema_errorsschema_deprecationsc                    sT   d}|r|t |dd7 }|r8|r(|d7 }|t |dd7 }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),)
         zCloud config schema errors: )r7   

"Cloud config schema deprecations: N)r@   super__init__rC   rD   )r3   rC   rD   r.   	__class__r)   r*   rI   w   s      zSchemaValidationError.__init__r/   c                 C   s
   t | jS r:   )boolrC   r2   r)   r)   r*   
has_errors   s    z SchemaValidationError.has_errors)NN)
r#   r$   r%   __doc__r
   SchemaProblemsrI   rL   rM   __classcell__r)   r)   rJ   r*   rA   t   s     rA   c                 C   sB   zddl m} W n tk
r&   Y dS X |j|dp@t|tfS )zWTYPE_CHECKER override allowing bytes for string type

    For jsonschema v. 3.0.0+
    r   )Draft4ValidatorFstring)
jsonschemarQ   ImportErrorTYPE_CHECKERZis_type
isinstancebytes)ZcheckerinstancerQ   r)   r)   r*   is_schema_byte_string   s     
rY   F)configr0   c                    sR   t d fdd}|r|ndddg}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| } rbd| S d	|  d
S )NrE   Z_descriptionZ_versionz	<missing z'_version key, please file a bug report>z in version .  z

**)get
capitalizestrip)r\   Zkey_descriptionvmsgannotaterZ   r)   r*   format_message   s    

z:_add_deprecated_changed_or_new_msg.<locals>.format_messager   changednewrE   r   )r&   r>   r?   r`   rstrip)rZ   rf   
filter_keyrg   Zfilter_keysZchanged_new_deprecatedr   r)   re   r*   "_add_deprecated_changed_or_new_msg   s    	rl   )r   schemark   
error_typec                 c   s"   |rt |d|gd}||V  dS )zJsonschema validator for `deprecated` items.

    It raises a instance of `error_type` if deprecated that must be handled,
    otherwise the instance is consider faulty.
    T)rf   rk   N)rl   )
_validatorr   Z	_instancerm   rk   rn   rd   r)   r)   r*   ro      s      ro   )rk   rh   rn   c                 #   s   ddl m} g }g }t|D ]d\}}	t| j||	|d}
tt fdd|
}tt fdd|
}|sv||  q|| q|d|f |dV  |E d	H  d	S )
zJsonschema 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`.
    r   r   Zschema_pathc                    s   t |   S r:   rV   erp   r)   r*   r<      r=   z_anyOf.<locals>.<lambda>c                    s
   t |  S r:   rr   rs   rp   r)   r*   r<      r=   .%r is not valid under any of the given schemascontextN)rS   r   	enumeratelistdescendfilterextend)	validatoranyOfrX   _schemarn   r   
all_errorsall_deprecationsindex	subschemaall_errserrsdeprecationsr)   rp   r*   _anyOf   s(    
r   c                 #   s   ddl m} t|}g }g }|D ]h\}	}
tj|
|	d}tt fdd|}tt fdd|}|s~|
}||  q|| q |df |dV  fd	d
|D }|r|| ddd |D }|d|f V  n
|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   r   rq   c                    s   t |   S r:   rr   rs   rp   r)   r*   r<     r=   z_oneOf.<locals>.<lambda>c                    s
   t |  S r:   rr   rs   rp   r)   r*   r<     r=   ru   rv   c                    s    g | ]\}}  |r|qS r)   )is_valid).0is)rX   r}   r)   r*   
<listcomp>(  s      z_oneOf.<locals>.<listcomp>r5   c                 s   s   | ]}t |V  qd S r:   )repr)r   rm   r)   r)   r*   	<genexpr>+  s     z_oneOf.<locals>.<genexpr>z%r is valid under each of %sN)	rS   r   rx   ry   rz   r{   r|   appendr>   )r}   oneOfrX   r   rn   r   Z
subschemasr   r   r   r   r   r   r   Zfirst_validZ
more_validZreprsr)   )rn   rX   r}   r*   _oneOf  s:    


r   c            
      C   s   ddl m} m} ddlm} t| j}d|d< ddi|d d	< i }t| d
rd| j	dt
}d|i}n| j}ttf|d< d|i}t| j}t|t< t|d< t|d< t|d< |f ||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   )rQ   FormatChecker)createFZadditionalPropertiestyperR   
propertieslabelrU   type_checkerZdefault_typesrh   r   r~   Zdraft4)Zmeta_schema
validatorsversionNc                 [   s$   t dd | ||}t|ddkS )zgOverride version of `is_valid`.

        It does ignore instances of `SchemaDeprecationError`.
        c                 S   s   t | t S r:   )rV   r+   rs   r)   r)   r*   r<   r  s    z<get_jsonschema_validator.<locals>.is_valid.<locals>.<lambda>N)r{   iter_errorsnext)r3   rX   r   __errorsr)   r)   r*   r   l  s
    
z*get_jsonschema_validator.<locals>.is_valid)N)rS   rQ   r   Zjsonschema.validatorsr   r   ZMETA_SCHEMAhasattrrU   ZredefinerY   ZDEFAULT_TYPESr&   rW   dictZ
VALIDATORS_validator_deprecatedDEPRECATED_KEY_validator_changedr   r   r   )
rQ   r   r   strict_metaschemaZvalidator_kwargsr   typesr   cloudinitValidatorr   r)   r)   r*   get_jsonschema_validator3  s@    

  

r   Trm   c              
   C   sz   ddl m} z| | W nZ |k
rt } z<|rXttddd |jD |jgd|t	d| W 5 d}~X Y nX dS )	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   s   g | ]}t |qS r)   r&   r   r;   r)   r)   r*   r     s     z3validate_cloudconfig_metaschema.<locals>.<listcomp>rC   zGMeta-schema validation failed, attempting to validate config anyway: %sN)
Zjsonschema.exceptionsr   Zcheck_schemarA   r,   r>   r-   r.   LOGwarning)r}   rm   throwr   errr)   r)   r*   validate_cloudconfig_metaschema~  s$     r   )rZ   rm   strictr   log_detailslog_deprecationsc                 C   s&  |dkrt  }z t \}}|r,t||dd W n  tk
rN   td Y dS X ||| d}g }	g }
t|| dd dD ]D}d	d
d |j	D }t
||jf}t|tr|
|7 }
q||	|7 }	q||r|
rt|
ddd}t| |r|	s|
rt|	|
|	r"|rt|	ddd}nd}t| dS )a  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 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.
    NF)r   z5Ignoring schema validation. jsonschema is not present)Zformat_checkerc                 S   s   | j S r:   )r-   rs   r)   r)   r*   r<     r=   z-validate_cloudconfig_schema.<locals>.<lambda>r[   r   c                 S   s   g | ]}t |qS r)   r   r   r)   r)   r*   r     s     z/validate_cloudconfig_schema.<locals>.<listcomp>z"Deprecated cloud-config provided:

r6   zInvalid cloud-config provided:
zeInvalid cloud-config provided: Please run 'sudo cloud-init schema --system' to see the schema errors.)
get_schemar   r   rT   r   debugsortedr   r>   r-   r,   r.   rV   r+   r@   r   rA   )rZ   rm   r   r   r   r   r   r   r}   r   r   Zschema_errorr-   problemr.   Zdetailsr)   r)   r*   validate_cloudconfig_schema  s^    
  

 
 



r   c                	   @   s   e Zd ZeeedddZeeee edddZ	e
ddd	Zedee ee ee eeedddZee eeee dddZe
e
eeef dddZdS )
_Annotator)cloudconfigoriginal_contentschemamarksc                 C   s   || _ || _|| _d S r:   )_cloudconfig_original_content_schemamarks)r3   r   r   r   r)   r)   r*   rI     s    z_Annotator.__init__)r   contentr0   c                 C   s   d |}d|  d| dS )Nr   # z: -------------
rF   )r>   )r   r   Zbodyr)   r)   r*   _build_footer  s    
z_Annotator._build_footer)r9   c                 C   sz   t t}|D ]h\}}td|}|rD| \}}|t| | nd }|| j|  | |d k	rdj|||d}q|S )Nz&format-l(?P<line>\d+)\.c(?P<col>\d+).*zLine {line} column {col}: {msg})linecolrd   )	r   ry   rematchgroupsintr   r   r4   )r3   r9   errors_by_liner-   rd   r   r   r   r)   r)   r*   _build_errors_by_line  s      z _Annotator._build_errors_by_linerE   )problemslabelsfooterr   label_prefixr0   c                 C   sB   | D ]8}| | }| | | d| d|  |d7 }q|S )Nr   r1      )r   )r   r   r   r   r   r   r   r)   r)   r*   _add_problems  s    

z_Annotator._add_problems)linesr   deprecations_by_liner0   c              	      s   g }g }g }d}d}t |dD ]p\}	}
||	 }||	 }|s>|rg } j||||dd} j||||dd}||
d d|  q||
 q|t fddtd	d d
|fd|ff |S )Nr   E)r   Dz		# ,c                    s
    j |  S r:   )r   seqr2   r)   r*   r<   A  r=   z._Annotator._annotate_content.<locals>.<lambda>c                 S   s   t | d S )Nr   )rL   r   r)   r)   r*   r<   C  r=   ErrorsZDeprecations)rx   r   r   r>   r|   r?   r{   )r3   r   r   r   annotated_contentZerror_footerZdeprecation_footerZerror_indexZdeprecation_indexZline_numberr   r   r   r   r)   r2   r*   _annotate_content!  sL        
z_Annotator._annotate_content)rC   rD   r0   c                 C   sp   |s|s| j S | j  d}t| jtsDd|| ddgg S | |}| |}| 	|||}d|S )Nr   r   z&# E1: Cloud-config is not a YAML dict.)
r   decodesplitrV   r   r   r>   r   r   r   )r3   rC   rD   r   r   r   r   r)   r)   r*   rf   M  s*     

  z_Annotator.annotateN)rE   )r#   r$   r%   r   rW   rI   staticmethodr&   r   r   rO   r   r   r   r   r   rf   r)   r)   r)   r*   r     s4   
 .
r   rB   )r   r   r   rC   rD   r0   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 unparseable.
    @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
    )r   rf   )r   r   r   rC   rD   r)   r)   r*   annotated_cloudconfig_fileg  s     r   c                 C   s  t | dd}|tsTtdd| t g}t|}|rPtti |i |j	d |z&|rjt
|\}}nt
|}i }W n tjk
rN } zd }	}
d}t|drt|drt|d}nt|d	rt|d	rt|d	}|r|jd }	|jd }
td
j|	|
dd| t|g}t|}|r8tti |i |j	d ||W 5 d}~X Y nX t|tsj|sjtdzt||ddd W nr tk
r } zR|rtt||||j	|jd n |jrt|jddd}t| | r W 5 d}~X Y nX dS )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 annotate: Boolean set True to print original config file with error
        annotations on the offending lines.

    @raises SchemaValidationError containing any of schema_errors encountered.
    @raises RuntimeError when config_path does not exist.
    F)r   zformat-l1.c1z"File {0} needs to begin with "{1}"r   r   NZcontext_markZproblem_markzformat-l{line}.c{col})r   r   zFile {0} is not valid yaml. {1}z Cloud-config is not a YAML dict.T)r   r   rB   rG   r5   r6   )r   
startswithCLOUD_CONFIG_HEADERr,   r4   r   rA   printr   rC   r   Zload_with_marksloadyamlZ	YAMLErrorr   getattrr   columnr&   rV   r   RuntimeErrorr   rD   r@   rM   )Zconfig_pathrm   rf   r   r   r   r   Zmarksrt   r   r   Zmarkr.   r)   r)   r*   validate_cloudconfig_file  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.
    Zarray   objectr   r   r)   )valuer)   r)   r*   _sort_property_order  s
    r   c                 c   s<   | D ]2}t |tr0t |ttfs0t|E d H  q|V  qd S r:   )rV   r   r&   rW   _flatten)Zxsxr)   r)   r*   r     s    r   )property_dict	multi_keyr0   c                 C   sn   g }|  |i D ]P}| tr q| drH|dd | dg D  q| dr||d  qtt|S )Nenumc                 S   s    g | ]}d t || d qS ``	_YAML_MAPr`   )r   Z
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   )r   defsr0   c           
      C   sx  t | | | dg }t|ts&|g}| drDdd | d D }n6| dr`|t| d n| drz|t| d t|dkr|d }n|jtd	 d
	|}| di }|dg }t|ts|g}t
|}t|di |di D ]*}t||}|r|dkrq|| q|rnt|dkrB| d|d  S |jtd	 dd
	| d}	| d|	 S |pvdS )zNReturn a string representing a property type from a given
    jsonschema.
    r   r   c                 S   s    g | ]}d t || d qS r   r   r   kr)   r)   r*   r   	  s    z&_get_property_type.<locals>.<listcomp>r   r~   r   r   r[   /itemsZ	UNDEFINEDz of ())_flatten_schema_refsr`   rV   ry   r|   r   lensortr   r>   rL   r   _get_property_typer   )
r   r   r   Zproperty_typer   Zsub_property_typesZprune_undefinedsub_itemZsub_typeZsub_property_docr)   r)   r*   r    sB    








r  r/   c                 C   sB   |d }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{}-)r   subr4   )r   r7   Zlist_paragraphr)   r)   r*   _parse_description+  s      r  )src_cfgr   c                 C   s   d| kr(|  ddd}| ||  d| krd| d krd| d  ddd}| d ||  d| d kr| d d D ],}d|kr|| ddd}|||  q|t| dg | dg | dg D ],}d|kr| ddd}|||  qdS )	zEFlatten schema: replace $refs in src_cfg with definitions from $defs.z$refz#/$defs/rE   r   r   r~   allOfN)popreplaceupdater   r`   )r  r   Z	reference
sub_schemar)   r)   r*   r   A  s(    


r   )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  Zsub_schemasr  r)   r)   r*   _flatten_schema_all_of[  s
    r  )prop_configr0   c                 C   s|   t ttddd}| di }| di }g }g }|| || t||D ]}|||| qHdt||}|rxd| }|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 ":".
    rZ   descriptionsdeprecated_descriptionsc                 S   s<   t t| jdr |t|  n| dr8|t|  d S )N)Zdeprecated_versionZchanged_versionZnew_versionr   )anyr?   r`   r   rl   r  r)   r)   r*   assign_descriptionss  s    
z6_get_property_description.<locals>.assign_descriptionsr   r~   r]   r^   )r   ry   r`   r   r>   )r  r  r   r~   r  r  r  r   r)   r)   r*   _get_property_descriptionh  s      
r      )rm   r   r0   c                    s  |d }g }  ddkrdS  fdddD } fdd|D }|D ]T}| D ]D\}}	t|	| t|	 |	 ddkrqTt|	}
|	 d	|}|tj||t|
|t	|	|d
 |	 d}|rtt|| | ds| dr|t
j||d |d7 }|t|||d | dg D ]N}| ds@| dr$|t
j||d |d7 }|t|||d q$d|	ksd|	krT|t|	||d qTqFd|S )zDReturn restructured text describing the supported schema properties.r  hiddenTrE   c                    s$   g | ]}d  ks| d  k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   )r7   	prop_namer   Z	prop_typer   r   r  )r7   r  )r   r7   r   rF   )r`   r   r   r  r  r   SCHEMA_PROPERTY_TMPLr4   r  r  SCHEMA_LIST_ITEM_TMPL_get_property_docr>   )rm   r   r7   Z
new_prefixr   Zproperty_keysZproperty_schemasZprop_schemaZprop_keyr  r   r   r   Z
alt_schemar)   r   r*   r    s    




      r  )metar0   c                 C   sj   |  d}|sdS t}t|D ]F\}}t|dd}|tkrV|dt|d  |d	|7 }q|S )zAReturn restructured text describing the meta examples if present.r    rE   r  r   r   r   )
r`   SCHEMA_EXAMPLES_HEADERrx   textwrapindentr   insertSCHEMA_EXAMPLES_SPACER_TEMPLATEr4   r>   )r  r    Zrst_contentcountZexampleZindented_linesr)   r)   r*   _get_examples  s    
 r%  c                 C   s2   |  dsdS ddd | d D }d| dS )Nr"   rE   r5   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:** rF   )r`   r>   )r  Zschema_keysr)   r)   r*    _get_activate_by_schema_keys_doc  s    

r&  )r  rm   r0   c           	      C   sl  |dkrt  }| r|stdt|  }ddddddd	h}d
h}d}|| r^d|| }n|| | rxd|| }|rt|tt| }d|d< |di }|| d r|| d i }t	t|}zt
||d|d< W n( tk
r   td d|d< Y nX |d rt|d< t| |d< d| d |d< tdd| d	 |d< t| |d
< tjf |}|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 schemar   r   r    r!   r   r   r   r"   rE   z(Missing required keys in module meta: {}z3Additional unexpected keys found in module meta: {}Zproperty_header$defs)r   Zproperty_docz3Unable to render property_doc due to invalid schemar5   r   -Ztitle_underbar)r   
ValueErrorsetkeysr4   KeyErrorr   r   r`   r   r  AttributeErrorr   r   SCHEMA_PROPERTY_HEADERr%  r>   r   r  r&  SCHEMA_DOC_TMPL)	r  rm   r+  Zrequired_keysZoptional_keysZerror_messageZ	meta_copyr   templater)   r)   r*   get_meta_doc  s^    	


r1  c                  C   s   t jt jt} t| S r:   )osr-   dirnameabspath__file__r   )Zconfigs_dirr)   r)   r*   get_modules1  s    r6  )requested_modulesr0   c                 C   s   d}t t  dg }t| t|}|rLtdt |d|dd |D ]J}d| ksd|| krPt	|dgdg\}}|rPt
|d	 }||jpd7 }qP|S )
zaLoad module docstrings

    Docstrings are generated on module load. Reduce, reuse, recycle.
    rE   allz+Invalid --docs value {}. Must be one of: {}r5   Tsys_exitcloudinit.configr  r   )ry   r6  valuesr*  
differencer   r4   r>   r   find_moduleimport_modulerN   )r7  docsZall_modulesZinvalid_docsmod_namemod_locs_modr)   r)   r*   load_doc6  s,      rE  c                   C   s   t jt jt jtdS )NZschemas)r2  r-   r>   r3  r4  r5  r)   r)   r)   r*   get_schema_dirQ  s    rF  c               
   C   sx   t jt t} d}ztt| }W n0 tk
rV } zt	
d| | W 5 d}~X Y nX |stt	
d|  i dg d}|S )z?Return jsonschema coalesced from all cc_* cloud-config modules.Nz$Cannot parse JSON schema file %s. %szCNo base JSON schema files found at %s. Setting default empty schemaz'http://json-schema.org/draft-04/schema#)r'  z$schemar	  )r2  r-   r>   rF  USERDATA_SCHEMA_FILEjsonloadsr   	Exceptionr   r   )Zschema_filefull_schemart   r)   r)   r*   r   U  s      r   c                  C   sV   t  } t  D ]@\}}t|dgdg\}}|rt|d }|j| |jd < q| S )z<Return metadata coalesced from all cc_* cloud-config module.r;  r  r   r   )r   r6  r   r   r>  r?  r  )Z	full_metarC  rA  rB  rD  r)   r)   r*   get_metat  s      rL  c                 C   s\   | st jddd} | jdd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-schemaz.Validate cloud-config files or document schema)progr   z-cz--config-filez.Path of the cloud-config yaml file to validate)helpz--system
store_trueFz)Validate the system cloud-config userdata)actiondefaultrO  z-dz--docs+zCPrint schema module docs. Choices: all or space-delimited cc_names.)nargsrO  z
--annotatez/Annotate existing cloud-config file with errors)argparseArgumentParseradd_argumentparserr)   r)   r*   
get_parser  s:    	rZ  c                 C   s  |j |j|jg}tdd |D dkr2tddd |jrJ|jrJtddd t }|jrhtt|j dS |j r|d	|j ff}nt	
 d
krtddd tg d}|jdd |jd}|stddd dS d	|ff}d|jdfd|jdff}|D ]&\}}	|	rt	j|	r|||	ff7 }qt	j|d
 d sTtd|d
 d  dddd d}
tt|dk}|rtdddd |D   d}
g }t|dD ]\}\}}|rtd| d | d!| d" zt|||j W n tk
r: } z<|js*t|
 d#|  tt||
d$ d% || W 5 d}~X Y nv tk
r } z4t|
 d#|  tt||
d$ d% || W 5 d}~X Y n$X |j r|n|}t|
 d&|  q|rtdd'd |D d(dd dS ))z@Handle provided schema args and perform the appropriate actions.c                 S   s   g | ]}|r|qS r)   r)   )r   argr)   r)   r*   r     s      z&handle_schema_args.<locals>.<listcomp>r   z;Expected one of --config-file, --system or --docs argumentsTr9  z;Invalid flag combination. Cannot use --annotate with --docsNz	user-datar   zNUnable to read system userdata or vendordata as non-root user. Try using sudo.)Zds_depsZtrust)existingZcloud_configz;Unable to obtain user data file. No instance data availablezvendor-dataZvendor_cloud_configzvendor2-dataZvendor2_cloud_configzConfig file z does not existz	Error: {})fmtr:  rE   z!Found cloud-config data types: %sr5   c                 s   s   | ]\}}|V  qd S r:   r)   )r   cfg_typerC  r)   r)   r*   r     s     z%handle_schema_args.<locals>.<genexpr>z  r   r]   z at :zInvalid cloud-config z
Error: {}
)r]  zValid cloud-config: c                 s   s   | ]
}|V  qd S r:   r)   )r   rn   r)   r)   r*   r     s     z'Error: Invalid cloud-config schema: {}
)Zconfig_filer@  systemr  r   rf   r   r   rE  r2  getuidr   ZfetchpathsZ	get_ipathr-   existsrL   r>   rx   r   rA   r&   r   r   )r   argsZexclusive_argsrK  Zconfig_filesZinitZuserdata_fileZvendor_config_filesr^  Zvendor_fileZnested_output_prefixZmulti_config_outputZerror_typesidxZcfg_filert   Zcfgr)   r)   r*   handle_schema_args  s    

rf  c                  C   s   t  } td|   dS )zDTool to validate schema of a cloud-config file or print schema docs.rM  r   )rZ  rf  
parse_argsrX  r)   r)   r*   main  s    rh  __main__)FN)T)NFFTF)F)r  )N)N)irN   rU  rH  Zloggingr2  r   sysr   collectionsr   Zcollections.abcr   copyr   	functoolsr   	itertoolsr   r(   r   r   r	   r
   r   r   r   r   Z	cloudinitr   r   Zcloudinit.stagesr   Zcloudinit.utilr   r   r   rS   r   Z_ValidationErrorrT   rJ  Z	getLoggerr#   r   ZVERSIONED_USERDATA_SCHEMA_FILErG  r   r   r/  r.  r  r  r  r#  r   ZDEPRECATED_PREFIXZtyping_extensionsr   r   r   r   r+   r,   rO   r&   r@   r)  rA   rY   rl   rL   ro   r   r   r   r   r   r   r   r   rW   r   r   r   r   r   r  r  r   r  r  r  r%  r&  r1  r6  ry   rE  rF  r   rL  rZ  rf  rh  exitr)   r)   r)   r*   <module>   s   $

#   ))/K%     Qz

Z,*H	>
$X
