a )g+@sddlmZmZmZeZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z mZmZmZmZddlmZddlmZddlmZddlmZmZmZddlmZdd lmZdd l m!Z!m"Z"dd l#m$Z%dd l&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,dd l-m.Z.m/Z/ddl0m1Z1m2Z2m3Z3ddl4m5Z5ddl6m7Z7m8Z8m9Z9ddl:m;Z;mm?Z?ddl@mAZAddlBmCZCddlDmEZEddlFmGZGddlHmIZImJZJmKZKmLZLeCZMddgZNeOefZPdZQeRdZSeRdZTeeUdZVd?ddZWddZXd d!ZYd"d#ZZd$d%Z[d&d'Z\d(d)Z]d*d+Z^d,d-Z_d.d/Z`Gd0d1d1e"ZaGd2d3d3e!ZbGd4d5d5eZcd6d7Zde^d8d9ZeGd:d;d;eZfGdddZhdS)@)absolute_importdivisionprint_functionN)IteratorSequenceMapping MappingViewMutableMapping)contextmanager)Number) format_exc)TemplateSyntaxErrorUndefinedError SecurityError)FileSystemLoader)NativeEnvironment)ContextStrictUndefined) constants)AnsibleAssertionError AnsibleErrorAnsibleFilterErrorAnsibleLookupErrorAnsibleOptionsErrorAnsibleUndefinedVariable) string_types text_type) to_nativeto_textto_bytes) is_sequence) filter_loader lookup_loader test_loader)ansible_native_concatansible_eval_concatansible_concat)AnsibleJ2Template) AnsibleJ2Vars)Display)listify_lookup_plugin_termsNativeJinjaText)wrap_varAnsibleUnsafeTextAnsibleUnsafeBytesNativeJinjaUnsafeTextTemplargenerate_ansible_template_varsz#jinja2:)variable_beginZ block_begin comment_beginZ raw_begin) variable_endZ block_endZ comment_endZraw_endc Cs|durt|}nt|}ztt|jj}Wn"ttfyTt|j}Yn0t t d|t j tj |t |t j |rt|ndd}|durtj ||d<n||d<tj}|j|d|d|dd}t tt|ttj ||d<|S) N) template_host template_pathZtemplate_mtime template_uidZtemplate_run_dateZtemplate_destpathZtemplate_fullpathr7r9r8)hostuidfileZansible_managed)rpwdgetpwuidosstatst_uidpw_nameKeyError TypeErrorrunamedatetimeZ fromtimestamppathgetmtimenowrabspathCZDEFAULT_MANAGED_STRformattimestrftime localtime)rGfullpathZ dest_pathb_pathr9Z temp_varsZmanaged_defaultZ managed_strrR=/usr/lib/python3.9/site-packages/ansible/template/__init__.pyr2Ls2  &cCsd|vrd|vrg}||}d}||D]z}|ddkrPd}||dq,|ddkrpd}||dq,|r|dd kr||ddd q,||dq,d |}|S) aDouble backslashes within jinja2 expressions A user may enter something like this in a playbook:: debug: msg: "Test Case 1\3; {{ test1_name | regex_replace('^(.*)_name$', '\1')}}" The string inside of the {{ gets interpreted multiple times First by yaml. Then by python. And finally by jinja2 as part of it's variable. Because it is processed by both python and jinja2, the backslash escaped characters get unescaped twice. This means that we'd normally have to use four backslashes to escape that. This is painful for playbook authors as they have to remember different rules for inside vs outside of a jinja2 expression (The backslashes outside of the "{{ }}" only get processed by yaml and python. So they only need to be escaped once). The following code fixes this by automatically performing the extra quoting of backslashes inside of a jinja2 expression. \z{{Fr6r3Tr5stringz\\) preprocesslexappendreplacejoin)data jinja_envZnew_datad2Zin_vartokenrRrRrS_escape_backslashesqs     racCs2t|tr.|j|j|jfD]}||vrdSqdS)aDetermines if a string looks like a template, by seeing if it contains a jinja2 start delimiter. Does not guarantee that the string is actually a template. This is different than ``is_template`` which is more strict. This method may return ``True`` on a string that is not templatable. Useful when guarding passing a string for templating, but when you want to allow the templating engine to make the final assessment which may result in ``TemplateSyntaxError``. TF) isinstancerZblock_start_stringvariable_start_stringZcomment_start_string)r]r^ZmarkerrRrRrSis_possibly_templates rdcCsd}d}d}||}t||s$dSz||D]t}|dtvrl|rT|ddkrTd}d}|ddd}q0|dtvr0|ddd|krWdS|rq0WdSq0WntyYdS0dS)zThis function attempts to quickly detect whether a value is a jinja2 template. To do so, we look for the first 2 matching jinja2 tokens for start and end delimiters. NTFr6r4_r)rXrdrYJINJA2_BEGIN_TOKENSsplitJINJA2_END_TOKENSr )r]r^foundstartZcommentr_r`rRrRrS is_templates,     rkcCsPz4t|}|d}||dkr(|d8}q|d|WStyJ|YS0dS)z Counts the number of newlines at the end of a string. This is used during the jinja2 templating to ensure the count matches the input, since some newlines may be thrown away during the templating. r6 N)len IndexError)Zin_strijrRrRrS_count_newlines_from_ends   rqcCshddlm}t|tr.|D]}t||qn6t|trL|D] }t|q.wrapper_update_wrapperrrrRrrS_unroll_iterators rc CsddD]2}zt||}Wnty(Yq0t|||qdD]}t||t||iq<||_|S)N) __module____name__ __qualname____doc____annotations__)__dict__)getattrAttributeErrorsetattrupdate __wrapped__)rrattrrzrRrRrSrs rcsfdd}t|S)zWrapper function, that intercepts the result of a filter and wraps it into NativeJinjaText which is then used in ``ansible_native_concat`` to indicate that it is a text which should not be passed into ``literal_eval``. cs|i|}t|Sr|r+r}rrRrSr$sz"_wrap_native_text..wrapperrrrRrrS_wrap_native_texts rc@s0eZdZdZddZddZddZdd Zd S) AnsibleUndefinedz} A custom Undefined class, which returns further Undefined objects on access, rather than throwing an exception. cCs|dkrt||S)N __UNSAFE__)r)selfnamerRrRrS __getattr__0szAnsibleUndefined.__getattr__cCs|Sr|rRrrxrRrRrS __getitem__8szAnsibleUndefined.__getitem__cCsd|j|j|jS)Nz3AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r}))rLZ_undefined_hintZ_undefined_objZ_undefined_namerrRrRrS__repr__<s zAnsibleUndefined.__repr__cCs|Sr|rR)rrwrRrRrS __contains__CszAnsibleUndefined.__contains__N)rrrrrrrrrRrRrRrSr+s rcsjeZdZdZeejjejjejjhZ fddZ fddZ ddZ dd Z fd d Zd d ZZS)AnsibleContexta$ A custom context, which intercepts resolve_or_missing() calls and sets a flag internally if any variable lookup returns an AnsibleUnsafe value. This flag is checked post-templating, and (when set) will result in the final templated result being wrapped in AnsibleUnsafe. cs tt|j|i|d|_dS)NF)superr__init__unsaferr~r __class__rRrSrUszAnsibleContext.__init__csDt|dd|jvs||jvr*t|dtj|g|Ri|S)Nrz is not safely callable)r_disallowed_callablesrrcall)robjr~rrrRrSrYszAnsibleContext.callcCslt|tr.|D]}|||rdSqn:t|trT|D]}||r<dSq|D] }t|q.nt|trPt||S)zsRecursively find an undefined value in a nested data structure and properly raise the undefined exception. )rbrvalues_fail_on_undefinedr rstr)r]rzrwrRrRrSrs     rcCst|dur|SdS)aSA custom finalize function for jinja2, which prevents None from being returned. This avoids a string of ``"None"`` as ``None`` has no importance in YAML. The function is decorated with ``_unroll_iterator`` so that users are not required to explicitly use ``|list`` to unroll a generator. This only affects the scenario where the final result of templating is a generator, e.g. ``range``, ``dict.items()`` and so on. Filters which can produce a generator in the middle of a template are already wrapped with ``_unroll_generator`` in ``JinjaPluginIntercept``. NrW)r)thingrRrRrS_ansible_finalizes rcs0eZdZdZeZeZee Z fddZ Z S)AnsibleEnvironmentz Our custom environment, which simply allows us to override the class-level values for the Template and Context classes used by jinja2 internally. csDtj|i|t|jt|_t|jt|_d|_t|_ t |_ dSr) rrrfiltersr!Ztestsr#Z trim_blocksrZ undefinedrfinalizerrrRrSrs zAnsibleEnvironment.__init__) rrrrrZ context_classr'template_class staticmethodr%concatrrrRrRrrSrs rcs$eZdZeeZfddZZS)AnsibleNativeEnvironmentcs tj|i|tt|_dSr|)rrrrrrrrRrSr(sz!AnsibleNativeEnvironment.__init__)rrrrr$rrrrRrRrrSr%src @seZdZdZd$ddZefddZddZed d Z e j d d Z e d d Z d%ddZ ddZeZddZddZddZd&ddZddZddZd'd d!Zd(d"d#ZeZdS))r1zQ The main class for templating, with the main entry-point of template(). NcCs|durtjddd||_|dur(in||_tj|_tjr@tnt }|| t |rZ| ndd|_ ||j j_t|j jd<|j|j jd<|j|j jd<|j jd <|j|j jd <|j|j jd <d|_td |j j|j jf|_tj|_dS) NzuThe `shared_loader_obj` option to `Templar` is no longer functional, ansible.plugins.loader is used directly instead.z2.16version.) extensionsloaderrlookupqueryqrIZundefz^%s\s*(\w*)\s*%s$)r deprecated_loader_available_variablesrKZDEFAULT_UNDEFINED_VAR_BEHAVIOR_fail_on_undefined_errorsZDEFAULT_JINJA2_NATIVErr_get_extensionsrZ get_basedir environmentrenvironment_classrglobals_lookup _query_lookup _now_datetime_make_undefined cur_contextrecompilercvariable_end_string SINGLE_VAR jinja2_native)rrZshared_loader_obj variablesrrRrRrSr2s,  zTemplar.__init__c Kst|}|j|jjtt}|j|j||_|tu|_||jd}| D]@\}}| ||}z|durt |||WqVt yYqV0qV|S)aVCreates a new copy of Templar with a new environment. :kwarg environment_class: Environment class used for creating a new environment. :kwarg \*\*kwargs: Optional arguments for the new environment that override existing environment attributes. :returns: Copy of Templar with updated environment. available_variablesZ searchpathN) object__new__rrrr1rrritemsrrr) rrrZnew_envZ new_templarmappingrxrzrrRrRrScopy_with_new_envXs"     zTemplar.copy_with_new_envcCs"g}tjrtjddd}|S)z Return jinja2 extensions to load. If some extensions are set via jinja_extensions in ansible.cfg, we try to load them with the jinja environment.  rW,)rKZDEFAULT_JINJA2_EXTENSIONSr[rg)rZ jinja_extsrRrRrSr|szTemplar._get_extensionscCs|jSr|)rrrRrRrSrszTemplar.available_variablescCs$t|tstdt|||_dS)a  Sets the list of template variables this Templar instance will use to template things, so we don't have to pass them around between internal methods. We also clear the template cache here, as the variables are being changed. z8the type of 'variables' should be a Mapping but was a %sN)rbrrrr)rrrRrRrSrs c ks||jjd}i}|D]P\}}|||j}z&t||||<|durTt|||WqtyhYq0qdV|D]"}|||j}t||||qvdS)a;Context manager used to set temporary templating context, without having to worry about resetting original values afterward Use a keyword that maps to the attr you are setting. Applies to ``self.environment`` by default, to set context on another object, it must be in ``mapping``. rN)rrrrrrr)rrroriginalrxrzrrRrRrSset_temporary_contexts  zTemplar.set_temporary_contextFTc  sP|dur gn|}| dur&tjdddt|dr4|SdurBj|rP|}t|trΈ|sh|Sj |} | r| d} | j vrj | } t| t r| S| durt jSj|||d}|St|rfdd |DSt|trHi}|D]:}||vr4j||d ||<n ||||<q|S|SdS) z Templates (possibly recursively) any given data as input. If convert_bare is set to True, the given data will be wrapped as a jinja2 variable ('{{foo}}') before being sent through the template engine. NzjThe `cache` option to `Templar.template` is no longer functional, and will be removed in a future release.2.18rrr6)preserve_trailing_newlinesescape_backslashesfail_on_undefined overridesdisable_lookups convert_datac s g|]}j|dqS)rrrr)template).0vrrrrrrRrS sz$Templar.template..r)rrhasattrr_convert_bare_variablerbrrdrmatchgrouprNON_TEMPLATED_TYPESrKZDEFAULT_NULL_REPRESENTATION do_templater rrr)rvariable convert_barerrrrrZ static_varscacherZonly_oneZvar_nameZ resolved_valresultdkrRrrSrsb              zTemplar.templatecCsvt|trt||jSt|ttfr@|D]}||r(dSq(n2t|trr|D]"}||sj|||rNdSqNdS)z#lets us know if data has a templateTF)rbrrkrrvtupler)rr]rrrRrRrSrk s     zTemplar.is_templatecCs t||jSr|)rdr)rr]rRrRrSrdszTemplar.is_possibly_templatecCsht|trdd|v}|dddddd}|sB||jvrd|jj|vrdd|jj||jjfS|S)z Wraps a bare string, which may have an attribute portion (ie. foo.bar) in jinja2 variable braces so that it is evaluated properly. |rr[z%s%s%s)rbrrgrrrcr)rrZcontains_filtersZ first_partrRrRrSr s  "zTemplar._convert_bare_variablecOstd|dS)NzHThe lookup `%s` was found, however lookups were disabled from templating)rrrr~rrRrRrS _fail_lookup,szTemplar._fail_lookupcCs,|rtj}n tj}|r(||S|S)zUjinja2 global function to return current datetime, potentially formatted via strftime)rFZutcnowrIrN)rZutcfmtrIrRrRrSr/s    zTemplar._now_datetimecOs d|d<|j|g|Ri|S)z( wrapper for lookup, force wantlist trueTwantlist)rrrRrRrSr;szTemplar._query_lookupc Ostj||j|d}|dur&td||dd}|dtj}|dd}t||ddd }z|j|fd |j i|} Wnft t fy} zt | WYd} ~ n>d} ~ 0t y} z| WYd} ~ nd} ~ 0t yF} zZd t| } |d krt| n|d kr tj| ddn| |r.gndWYd} ~ Sd} ~ 0ty} zd|t| t| f} |d krt| n<|d krtj| ddn"tdttt| | d|rgndWYd} ~ Sd} ~ 00t| stjd|dt| d|ddd| r|dur|jr2d|j_|r@t| Sz6t| dtrfttd| } ntd| } Wnptyt| t std|t!| dkrt| d} nt| } Yn"t"ytd| } Yn0| S)N)rtemplarzlookup plugin (%s) not foundrF allow_unsafeerrorsstrictT)Ztermsrrrrz0Lookup failed but the error is being ignored: %swarnignore)Zlog_onlyzjAn unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %sz&exception during Jinja2 execution: {0}Zorig_exczThe lookup plugin 'z&' was expected to return a list, got 'z' instead. The lookup plugin 'zM' needs to be changed to return a list. This will be an error in Ansible 2.18rrrrz-The lookup plugin '%s' did not return a list.r6)#r"rrrpoprKZDEFAULT_ALLOW_UNSAFE_LOOKUPSr*runrrrrrrrZwarningrrrZvvvrLr r rrrr-rbr,r\rDrrmrC) rrr~rinstancerrrZ loop_termsZranrmsgrRrRrSr@sv       "   $   zTemplar._lookupcCs2ddlm}|dus&t||s&|dkr*d}t|S)NrrrrWz*Mandatory variable has not been overridden)rtrsrbr)rhintrsrRrRrSrs zTemplar._make_undefinedc Cs|jrt|ts|St|}|dur*|j}|t} z|rJ|j|} n| rZ|j} n|j} | r| d} |t t| } || dd}| dD]J} d| vrt d| | dd\}}| }t| |t| q|rt|| }z| |}WntyB}z(t dt|t|f|dWYd}~ndd}~0ty}zBdt|vrvt d t||dn|WYd}~WSWYd}~n d}~00|r|j|jd <|jd <|jd <t||j}|j}| jj| _|js|st| _|j|d d|_||j}zz*| |}t|jdd}|r:t |}Wnt!y}zrdt|vrdt|}|dt|7}t"||dn.t#$dt%|t dt|t|f|dWYd}~n d}~00W||_n||_0t|tr |r t|}||kr || j&||7}|r t |}|WSt't"fy}zB|rNt"||dn"t#$dt%||WYd}~SWYd}~n d}~00dS)Nrlr6r:zhfailed to parse jinja2 override '%s'. Did you use something different from colon as key-value separator?z6template error while templating string: %s. String: %sr! recursionz.recursive loop detected in template string: %srrrT)ZsharedrFrzIUnable to look up a name or access an attribute in template string (%s). zMMake sure your variable name does not contain invalid characters like '-': %sz5failing because of a type error, template data is: %sz5Unexpected templating type error occurred on (%s): %szIgnoring undefined failure: %s)(rrbrrqr startswithJINJA2_OVERRIDErZoverlayfindrmrgrstriprastZ literal_evalraZ from_stringr rrrrr(rrrr&Z new_contextZroot_render_funcrr-rDrrdebugrZnewline_sequencer)rr]rrrrrrZ data_newlinesZhas_template_overridesZmyenvZeollineZpairrxrtrZjvarsZcached_contextZrfresrteerrmsgZ res_newlinesrRrRrSr s    0(       4  zTemplar.do_template)NN) FTTNNTNNF)FN)N)TTNNFF)rrrrrrrrpropertyrsetterr rrrkZ templatablerdr rrrrrr Z _do_templaterRrRrRrSr1-s4 & $    N T  v)NN)iZ __future__rrrrZ __metaclass__r-rFr?r=rrMcollections.abcrrrrr contextlibr Znumbersr tracebackr Zjinja2.exceptionsr rrZjinja2.loadersrZjinja2.nativetypesrrtrrZansiblerrKZansible.errorsrrrrrrZansible.module_utils.sixrrZansible.module_utils._textrrrZ'ansible.module_utils.common.collectionsr Zansible.plugins.loaderr!r"r#Zansible.template.native_helpersr$r%r&Zansible.template.templater'Zansible.template.varsr(Zansible.utils.displayr)Zansible.utils.listifyr*Zansible.utils.native_jinjar,Zansible.utils.unsafe_proxyr-r.r/r0r__all__boolr r*rrfrhrangeryr2rardrkrqrur{rrrrrrrrrrr1rRrRrRrSsl               %+&  TN