ó oBú]c@s¦dZddlmZddlmZddlmZmZddlZddl m Z ddl m Z ddl Z ddlZddlZddlZddlZide6d e6d d6Zd Zd Zd ZdZdZdZdefd„ƒYZed„Zd„Zed„Z d„Z!d„Z"dd„Z#dd„Z$d„Z%da&d„Z'd„Z(dd„Z)d „Z*d!„Z+e,d"kr¢ej-e+ƒƒndS(#sFschema.py: Set of module functions for processing cloud-config schema.iÿÿÿÿ(tprint_function(timporter(t find_modulest load_fileN(t defaultdict(tdeepcopyttruetfalsetnullt UNDEFINEDs #cloud-configsÍ {name} {title_underbar} **Summary:** {title} {description} **Internal name:** ``{id}`` **Module frequency:** {frequency} **Supported distros:** {distros} **Config schema**: {property_doc} {examples} s/{prefix}**{prop_name}:** ({type}) {description}s **Examples**:: s # --- Example{0} ---tSchemaValidationErrorcBseZdZdd„ZRS(s<Raised when validating a cloud-config file against a schema.cCsf||_g|D]\}}dj||ƒ^q}djdj|ƒƒ}tt|ƒj|ƒdS(s—Init the exception an n-tuple of schema errors. @param schema_errors: An n-tuple of the format: ((flat.config.key, msg),) s{0}: {1}sCloud config schema errors: {0}s, N(t schema_errorstformattjointsuperR t__init__(tselfR t config_keytmessageterror_messages((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyR.s  (((t__name__t __module__t__doc__R(((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyR +sc Cs'yddlm}m}Wntk r;tjdƒdSX||d|ƒƒ}d }xgt|j|ƒdd„ƒD]G}djg|j D]}t |ƒ^qŒƒ} || |j ff7}qvW|r#|rÜt |ƒ‚q#g|D]\} } d j | | ƒ^qã} tjd d j| ƒƒndS( sìValidate provided config meets the schema definition. @param config: Dict of cloud configuration settings validated against schema. @param schema: jsonschema dict describing the supported schema definition for the cloud config module (config.cc_*). @param strict: Boolean, when True raise SchemaValidationErrors instead of logging warnings. @raises: SchemaValidationError when provided config does not validate against the provided schema. iÿÿÿÿ(tDraft4Validatort FormatCheckers<Ignoring schema validation. python-jsonschema is not presentNtformat_checkertkeycSs|jS(N(tpath(te((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytRst.s{0}: {1}sInvalid config: %ss ((t jsonschemaRRt ImportErrortloggingtdebugtsortedt iter_errorsR RtstrRR R twarning( tconfigtschematstrictRRt validatorterrorsterrortpRtktmsgtmessages((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytvalidate_cloudconfig_schema=s  %++cCs÷|s |Si}|r(t||ƒ}nttƒ}d}g}g}xÃ|D]»\}} tjd|ƒ} | r| jƒ\} } |t| ƒj| ƒnd} |||j| ƒ| dk rådj d| d| d| ƒ} n|jdj || ƒƒ|d7}qMW|j ƒj dƒ} d}x¡t | ƒD]“\}} ||d}|rºd j gtd t|ƒƒD]}d j ||ƒ^qpƒ}|t|ƒ7}|j| d |ƒq4|j| ƒq4W|jd j dj |ƒƒƒdj |ƒS(s|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 schema_errors: List of tuples from a JSONSchemaValidationError. The tuples consist of (schemapath, error_message). is&format-l(?P\d+)\.c(?P\d+).*sLine {line} column {col}: {msg}tlinetcolR/s # E{0}: {1}s t,isE{0}s # s# Errors: ------------- {0} N(t_schemapath_for_cloudconfigRtlisttretmatchtgroupstinttappendtNoneR tdecodetsplitt enumerateR trangetlen(t cloudconfigtoriginal_contentR t schemapathsterrors_by_linet error_countt error_footertannotated_contentRR/R8R2R3tlinest line_numberR+tcountt error_label((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytannotated_cloudconfig_file]sH    5c Cstjj|ƒs*tdj|ƒƒ‚nt|dtƒ}|jtƒs£ddj|tj ƒƒff}t |ƒ}|ršt t i||j ƒƒn|‚nytj|ƒ}Wntjk rÈ}d}} d } t|dƒr t|dƒr t|dƒ} n0t|dƒr;t|dƒr;t|dƒ} n| r^| jd}| jd} ndjd |d | ƒd j|t|ƒƒff}t |ƒ}|r¿t t i||j ƒƒn|‚nXyt||d tƒWn8t k r}|rt t |||j ƒƒn‚nXd S(sÖValidate cloudconfig file adheres to a specific jsonschema. @param config_path: Path to the yaml cloud-config file to parse. @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. sConfigfile {0} does not existR=s format-l1.c1s"File {0} needs to begin with "{1}"it context_markt problem_marksformat-l{line}.c{col}R2R3sFile {0} is not valid yaml. {1}R)N(tosRtexistst RuntimeErrorR RtFalset startswithtCLOUD_CONFIG_HEADERR=R tprintRMR tyamlt safe_loadt YAMLErrorR<thasattrtgetattrR2tcolumnR%R1tTrue( t config_pathR(tannotatetcontentR+R,RBRR2R\tmark((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytvalidate_cloudconfig_fileŽsJ        cCs|jƒjdƒ}i}d}d}g}xÓt|dƒD]Â\}}ttj||ƒjƒdƒ} |jƒ}| s=|jdƒr“q=n|r¬|d\} } n d} d} |jdƒrêt |ƒ} |d} |d7}nd}|jd dƒ\} } x7| | krA|r2|j ƒ\} } q d} d} q W| rY| d | } n|j | | fƒ| rõ| jƒ} | jd ƒrõ|j | d | d fƒxGt dtt j| ƒƒƒD]$}| d t |ƒ}|||R?RAR7R8R9tstripRTR%tpopR;R@RWRX(R'RCt content_linestschema_line_numberst list_indextRE_YAML_INDENTtscopesRJR2t indent_depthtprevious_deptht path_prefixRtvaluetinner_list_indextlist_key((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyR5ÁsJ"      %cCs|jdtƒ}|tkr_|jdƒr_g|dD]}ttj||ƒƒ^q8}nt|tƒr€dj|ƒ}n|jdiƒ}|jddƒ}xE|jdiƒD]1}|rÐ|d7}n|dt|ƒd7}q·W|rd j||ƒS|S( sEReturn a string representing a property type from a given jsonschema.ttypetenumt/titemsRdtoneOft(t)s {0} of {1}( tgettSCHEMA_UNDEFINEDR%t _YAML_MAPt isinstanceR6R t_get_property_typeR (t property_dictt property_typeR.Rwtsub_property_typetsub_item((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyRòs2 s c Cs½|d}g}x|jdiƒjƒD]ƒ\}}|jddƒ}|jtjd|d|dt|ƒd|jddƒƒƒd|kr)|jt|d|ƒƒq)q)Wd j|ƒS( sDReturn restructured text describing the supported schema properties.s t propertiest descriptionRdtprefixt prop_nameRts s ( R{RwR;tSCHEMA_PROPERTY_TMPLR Rtreplacet_get_property_docR (R(R†t new_prefixR„tprop_keyt prop_configR…((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyRŠs %  Rdc Cs°|jdƒ}|sdSt}xŠt|ƒD]|\}}|jdƒ}g|D]}dj|ƒ^qN}|tkr•|jdtj|dƒƒn|dj|ƒ7}q,W|S(sCReturn restructured text describing the schema examples if present.texamplesRds s {0}ii(R{tSCHEMA_EXAMPLES_HEADERR?R>R tinserttSCHEMA_EXAMPLES_SPACER_TEMPLATER ( R(R†RŽt rst_contentRKtexampleRIR2tindented_lines((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyt_get_schema_exampless" cCsmt|ƒ}t|ƒ|dReturn jsonschema coalesced from all cc_* cloud-config module.s'http://json-schema.org/draft-04/schema#s$schemascloud-config-schematidtallOfscloudinit.configR(i( t FULL_SCHEMARPRtdirnametabspatht__file__RRwRt find_modulet import_moduleR;R((t full_schemat configs_dirtpotential_handlerst_fnametmod_nametmod_locst _looked_locstmod((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyt get_schema;s cCs$t|dtjƒtjdƒdS(Ntfilei(RVtsyststderrtexit(R((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyR,Psc Cs||s!tjddddƒ}n|jddddƒ|jd d d d d tddƒ|jdd d d tddƒ|S(s0Return a parser for supported cmdline arguments.tprogscloudconfig-schemaR…s.Validate cloud-config files or document schemas-cs --config-filethelps.Path of the cloud-config yaml file to validates-ds--doctactiont store_truetdefaultsPrint schema documentations --annotates/Annotate existing cloud-config file with errors(targparsetArgumentParsert add_argumentRS(tparser((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyt get_parserUs  cCs|j|jg}t|ƒ s+t|ƒr8tdƒntƒ}|jrÑyt|j||jƒWnQtk r•}|jsÎtt |ƒƒqÎqÑt k r·}tt |ƒƒqÑXt dj |jƒƒn|jrx%|dD]}t t |ƒƒqåWndS(s@Handle provided schema args and perform the appropriate actions.s/Expected either --config-file argument or --docsValid cloud-config file {0}R N(t config_filetdoctanytallR,R¯RbR_R R%RRRVR Rž(R™targstexclusive_argsR§Rt subschema((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pythandle_schema_argsds"     cCs tƒ}td|jƒƒdS(sDTool to validate schema of a cloud-config file or print schema docs.scloudconfig-schemai(R½RÅt parse_args(R¼((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytmainzs t__main__(.Rt __future__Rt cloudinitRtcloudinit.utilRRR¹t collectionsRtcopyRR!RPR7R±RWR]RSR<R}R|RURœRˆRR‘t ValueErrorR R1RMRbR5RRŠR•RžR¡R¯R,R½RÅRÇRR³(((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytsF       1 3 1