oB]c@sdZddlmZddlmZddlmZmZddlZddl m Z ddl m Z ddl Z ddlZddlZddlZddlZide6d e6d d6Zd Zd Zd ZdZdZdZdefdYZedZdZedZ dZ!dZ"ddZ#ddZ$dZ%da&dZ'dZ(ddZ)d Z*d!Z+e,d"krej-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} ---tSchemaValidationErrorcBseZdZddZRS(s<Raised when validating a cloud-config file against a schema.cCsf||_g|D]\}}dj||^q}djdj|}tt|j|dS(sInit 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;tjddSX||d|}d }xgt|j|ddD]G}djg|j D]}t |^q} || |j ff7}qvW|r#|rt |q#g|D]\} } d j | | ^q} tjd d j| ndS( sValidate 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 rdj d| d| d| } n|jdj || |d7}qMW|j j d} d}xt | D]\}} ||d}|rd 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}|jtsddj|tj ff}t |}|rt t i||j n|nytj|}Wntjk r}d}} d } t|dr t|dr t|d} n0t|dr;t|dr;t|d} n| r^| jd}| jd} ndjd |d | d j|t|ff}t |}|rt t i||j n|nXyt||d tWn8t k r}|rt t |||j nnXd S(sValidate 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_filesJ        cCs|jjd}i}d}d}g}xt|dD]\}}ttj||jd} |j}| s=|jdrq=n|r|d\} } n d} d} |jdrt |} |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 fxGt 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.pyR5sJ"      %cCs|jdt}|tkr_|jdr_g|dD]}ttj||^q8}nt|trdj|}n|jdi}|jdd}xE|jdiD]1}|r|d7}n|dt|d7}qW|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.pyRs2 s c Cs|d}g}x|jdijD]\}}|jdd}|jtjd|d|dt|d|jddd|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(Rt new_prefixRtprop_keyt prop_configR((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pyRs %  Rdc Cs|jd}|sdSt}xt|D]|\}}|jd}g|D]}dj|^qN}|tkr|jdtj|dn|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(RRt 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|dtjtjddS(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-schemaRs.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|r8tdnt}|jryt|j||jWnQtk r}|jstt |qqt k r}tt |qXt dj |jn|jrx%|dD]}t t |qWndS(s@Handle provided schema args and perform the appropriate actions.s/Expected either --config-file argument or --docsValid cloud-config file {0}RN(t config_filetdoctanytallR,RRbR_R R%RRRVR R(Rtargstexclusive_argsRRt subschema((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pythandle_schema_argsds"     cCs t}td|jdS(sDTool to validate schema of a cloud-config file or print schema docs.scloudconfig-schemai(RRt parse_args(R((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytmainzs t__main__(.Rt __future__Rt cloudinitRtcloudinit.utilRRRt collectionsRtcopyRR!RPR7RRWR]RSR<R}R|RURRRRt ValueErrorR R1RMRbR5RRRRRRR,RRRRR(((s;/usr/lib/python2.7/site-packages/cloudinit/config/schema.pytsF       1 3 1