a )gm@s.ddlmZmZmZeZddlZddlmZm Z m Z m Z ddl m ZddlmZmZmZddlmZddlmZmZddlmZdd lmZdd lmZdd lmZdd l m!Z!dd l"m#Z#ddl$m%Z%ddl&m'Z'ddl(m)Z)ddl*m+Z+ddl,m-Z-ddl.m/Z/ddgZ0ddZ1Gdddeee%eZ2dS))absolute_importdivisionprint_functionN) ContainerMappingSetSequence) constants) AnsibleErrorAnsibleParserErrorAnsibleAssertionError)to_text) binary_type text_type)FieldAttribute)Base)CollectionSearch) Conditional)load_list_of_blocks) RoleMetadata)Taggable)add_all_plugin_dirs)AnsibleCollectionConfig) is_subpath)Sentinel) combine_varsRole hash_paramsc Cst|trt|ttfst|trzzt|}Wqtyvt}|D]\}}| |t |fqNt|}Yq0n^t|t t frz t|}Wqtyt}|D]}| t |qt|}Yq0nt|}|St|fS)a Construct a data structure of parameters that is hashable. This requires changing any mutable data structures into immutable ones. We chose a frozenset because role parameters have to be unique. .. warning:: this does not handle unhashable scalars. Two things mitigate that limitation: 1) There shouldn't be any unhashable scalars specified in the yaml 2) Our only choice would be to return an error anyway. ) isinstancerrrr frozensetitems TypeErrorsetaddrrr)params new_paramskvr(B/usr/lib/python3.9/site-packages/ansible/playbook/role/__init__.pyr3s(    cseZdZeddZeddZd9fdd Zd d Zd:d d Ze d;d dZ ddd Zd?d!d"Zd@d#d$ZdAd%d&Zd'd(Zd)d*Zd+d,ZdBd-d.Zd/d0ZdCd1d2ZdDfd3d4 ZdEfd5d6 Zd7d8ZZ S)Frstring)ZisaboolNFTcsd|_d|_d|_t|_d|_d|_||_g|_g|_ g|_ g|_ d|_ t|_ t|_t|_t|_||_|dur|i}||_||_tt|dSN) _role_name _role_path_role_collectiondict _role_params_loader _metadata_play_parents _dependencies _task_blocks_handler_blocks_compiled_handler_blocks _default_vars _role_vars _had_task_run _completed_should_validate _from_files from_includesuperr__init__)selfplay from_filesr@validate __class__r(r)rBhs,z Role.__init__cCs|Sr,)get_namerCr(r(r)__repr__sz Role.__repr__cCs&|r ddd|j|jfDS|jS)N.css|]}|r|VqdSr,r().0xr(r(r) z Role.get_name..)joinr/r-)rCZinclude_role_fqcnr(r(r)rIsz Role.get_namec Cs4|dur i}z|}|jdur,|j|d<|jdur@|j|d<|durP||d<|jr`|j|d<||d<t|}||jvr|j|D](\}} ||kr|r| || WSqt ||||d} | j ||d||jvrt |j|<| |j||<| WSt y.t d|jd Yn0dS) NwhentagsrEvarsr@)rDrEr@rF) parent_rolezvA recursion loop was detected with the roles specified. Make sure child roles do not have dependencies on parent roles)obj)get_role_paramsrRrSrTrrIZ ROLE_CACHEr add_parentr_load_role_datar0 RuntimeErrorr Z_ds) role_includerDrUrEr@rFr$Z hashed_paramsentryZrole_objrr(r(r)loads<       z Role.loadc s|j_|_|j_|_|_| _ |rF |j D]$}t d|t|d|tqLjdjddd_jduri_ntjtstdjjdjddd_jduri_ntjtstdjd}|r2tj|jj d __nt_g_jrZjd jn$tj }|rtjd |t!jjjrj"fd d jjDjrjrd nd}d jvrdjvrj#|jdjdd}j$r%}&||}|rtzt'|j(j jd_)Wn:t*yr} z tdj|| dWYd} ~ n d} ~ 00jdjdd} | rz t'| j(dj jd_+Wn:t*y} z tdj| | dWYd} ~ n d} ~ 00dS)N_rTT)main allow_dirzKThe vars/main.yml file for role '%s' must contain a dictionary of variablesdefaultszOThe defaults/main.yml file for role '%s' must contain a dictionary of variablesmeta)ownervariable_managerloaderrc3s|]}|jvr|VqdSr,) collections)rMcrJr(r)rOrPz'Role._load_role_data..zansible.builtinzansible.legacytasksr`)rDrolerfrezBThe tasks/main.yml file for role '%s' must contain a list of tasks)rVZorig_exchandlers)rDrkZ use_handlersrfrezEThe handlers/main.yml file for role '%s' must contain a list of tasks),rkr-Z get_role_pathr.r/rWr1Zget_variable_manager_variable_manager get_loaderr2rXZ fattributessetattrgetattrr_load_role_yamlr?getr;rrr r:rr^r3_load_dependenciesr6rginsertrdefault_collectionrextendappendr>_get_role_argspecs_prepend_validation_taskrr4r7AssertionErrorr8) rCr[rUZ attr_namemetadataruZdefault_append_collection task_dataZ role_argspecseZ handler_datar(rJr)rYsv      "             zRole._load_role_datac Cs~tj|jdd}tjD]V}||}|j|r|jddd}z| dpLiWSt yliYS0qt |j diS)aGet the role argument spec data. Role arg specs can be in one of two files in the role meta subdir: argument_specs.yml or main.yml. The former has precedence over the latter. Data is not combined between the files. :returns: A dict of all data under the top-level ``argument_specs`` YAML key in the argument spec file. An empty dict is returned if there is no argspec data. rcargument_specsrj) ospathrQr.CZYAML_FILENAME_EXTENSIONSr2 path_existsrqrrAttributeErrorrpr3)rCZbase_argspec_pathext full_pathr~r(r(r)rxs    zRole._get_role_argspecscCsD|r@|jdd}||}|r@|||}|s4g}|d||S)aInsert a role validation task if we have a role argument spec. This method will prepend a validation task to the front of the role task list to perform argument spec validation before any other tasks, if an arg spec exists for the entry point. Entry point defaults to `main`. :param task_data: List of tasks loaded from the role. :param argspecs: The role argument spec data dict. :returns: The (possibly modified) task list. rir`r)r?rr_create_validation_taskrt)rCr|ZargspecsZ entrypointZentrypoint_arg_specZvalidation_taskr(r(r)ry/s    zRole._prepend_validation_taskcCsPd|}d|vr |d|d}d|di|jd|j||jdd|d gd S) aCreate a new task data structure that uses the validate_argument_spec action plugin. :param argument_spec: The arg spec definition for a particular role entry point. This will be the entire arg spec for the entry point as read from the input file. :param entrypoint_name: The name of the role entry point associated with the supplied `argument_spec`. z*Validating arguments against arg spec '%s'Zshort_descriptionz - z&ansible.builtin.validate_argument_specoptionsrk)typenameZargument_spec_namer)module argument_specZprovided_argumentsZvalidate_args_contextalways)actionrrS)rrr1r-r.)rCrZentrypoint_nameZ task_namer(r(r)rLs   zRole._create_validation_taskc Csd}tj|j|}|j|r|j|rgd}|durLd}|dn|}|dd|j ||||}|r|D]d} t | |st dt | |j t |f|j| } | rv|durt| trt|| }n| }|svqqvn|durt d||f|S)aj Find and load role YAML files and return data found. :param subdir: subdir of role to search (vars, files, tasks, handlers, defaults) :type subdir: string :param main: filename to match, will default to 'main.' if not provided. :type main: string :param allow_dir: If true we combine results of multiple matching files found. If false, highlander rules. Only for vars(dicts) and not tasks(lists). :type allow_dir: bool :returns: data from the matched file(s), type can be dict or list depending on vars or tasks. N)z.ymlz.yamlz.jsonr`rzRFailed loading '%s' for role (%s) as it is not inside the expected role path: '%s'z,Could not find specified file in role: %s/%s)rrrQr.r2rZ is_directoryrwrtZfind_vars_filesrr r r-Zload_from_filerrr) rCZsubdirr`radataZ file_path extensionsZ_mainZ found_filesfoundZnew_datar(r(r)rqks4      zRole._load_role_yamlcCs8g}|jr4|jjD] }tj||j|d}||q|S)zr Recursively loads role dependencies from the metadata list of dependencies, if it exists )rDrU)r3Z dependenciesrr^r4rw)rCdepsr[r]r(r(r)rss   zRole._load_dependenciescCs*t|tst||jvr&|j|dS)z/ adds a role to the list of this roles parents N)rrr r5rw)rCrUr(r(r)rXs  zRole.add_parentcCs|jSr,)r5rJr(r(r) get_parentsszRole.get_parentscCs\|dur gn|}t}|D]}t||}q|rL|D]}t||j}q:t||j}|Sr,)r0get_all_dependenciesrget_default_varsr:)rC dep_chainZ default_varsdepparentr(r(r)rs  zRole.get_default_varscCs@|dur gn|}t}|r<|D]}t||j}t||j}q|Sr,)r0rrTr;)rCrZinherited_varsrr(r(r)get_inherited_varss zRole.get_inherited_varscCs>|dur gn|}i}|r.|D]}t||j}qt||j}|Sr,)rr1)rCrr$rr(r(r)rWs zRole.get_role_paramscCsl|dur gn|}||}|D]}t||j|d}q"t||j}t||j}|rht||j|d}|S)N)include_params)r)rrrget_varsrTr;rW)rCrrZall_varsrr(r(r)rs    z Role.get_varscCs|jddSr,)r6rJr(r(r)get_direct_dependenciesszRole.get_direct_dependenciescCs8g}|D]&}|D]}||q||q |S)z Returns a list of all deps, built recursively from all child dependencies, in the proper order in which they should be executed or evaluated. )rrrw)rCZ child_depsrZ child_depr(r(r)rs     zRole.get_all_dependenciescCs|jddSr,)r7rJr(r(r)get_task_blocksszRole.get_task_blocksc Cs|jr |jSg|_}|dur"g}||g}|D]}|j||d}||q4|jD]"}|}||_||_||qX|S)NrDr) r9rget_handler_blocksrvr8copy _dep_chainr4rw) rCrDr block_list new_dep_chainr dep_blocks task_blocknew_task_blockr(r(r)rs      zRole.get_handler_blockscCs|j|jvo|jj S)zs Returns true if this role has been iterated over completely and at least one task was run )rr=r3Zallow_duplicates)rChostr(r(r)has_runsz Role.has_runcCsddlm}ddlm}g}|dur(g}||g}|}|D]}|j||d} || q>|jD]"} | } || _ || _ | | qb||d} |j | _ || _ |j| _d| _|| d} || _ d | _d d i| _d | _d g| _d | _| g| _| | |S)a Returns the task list for this role, which is created by first recursively compiling the tasks for all direct dependencies, and then adding on the tasks for this role. The role compile() also remembers and saves the dependency chain with each task, so tasks know by which route they were found, and can correctly take their parent's tags/conditionals into account. r)Block)TaskNr)rDF)blockrcZ _raw_paramsZ role_completeTr)Zansible.playbook.blockrZansible.playbook.taskrrcompilervr7rrr4rwr2Z_rolermZrun_oncerargsZimplicitrSrRr)rCrDrrrrrrrrrrZ eor_blockZeor_taskr(r(r)r%s<          z Role.compilecstt|}|j|d<|j|d<|j|d<|j|d<|j|d<|j |d<|j |d<|j rp|j |d<|rg}| D]}| |q||d <g}|jD]}| |jd d q||d <|S) Nr-r.r;r1r:r<r=r3r6F include_depsr5)rAr serializer-r.r;r1r:r<rr=r3rrwr5)rCrresrrkparentsrrGr(r)rWs(       zRole.serializec s*|dd|_|dd|_|dt|_|dt|_|dt|_|dt|_|dt|_|rg}|d gD]}t }| || |qt |d ||d g}g}|D]"}t }|j |d d | |qt |d ||d } | rt } | | | |_tt | |dS)Nr-rr.r;r1r:r<r=r6r5Frr3)rrr-r.r0r;r1r:r<r=r deserializerwrorr3rA) rCrrrrr]Z parent_datarrZ metadata_datamrGr(r)rrs6        zRole.deserializecCs8||_|jD]}||q |D]}||q$dSr,)r2r5 set_loaderr)rCrfrrr(r(r)rs    zRole.set_loader)NNFT)T)NNFT)N)NF)N)N)N)NT)N)N)T)T)!__name__ __module__ __qualname__rZ delegate_toZdelegate_factsrBrKrI staticmethodr^rYrxryrrqrsrXrrrrWrrrrrrrrrr __classcell__r(r(rGr)rcs8    0 U 6   2!)3Z __future__rrrrZ __metaclass__rcollections.abcrrrrZansibler rZansible.errorsr r r Zansible.module_utils._textr Zansible.module_utils.sixrrZansible.playbook.attributerZansible.playbook.baserZ!ansible.playbook.collectionsearchrZansible.playbook.conditionalrZansible.playbook.helpersrZansible.playbook.role.metadatarZansible.playbook.taggablerZansible.plugins.loaderrZansible.utils.collection_loaderrZansible.utils.pathrZansible.utils.sentinelrZansible.utils.varsr__all__rrr(r(r(r)s,              0