o nnhQ@s ddlmZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z mZddlmZddlmZmZddlmZmZmZddlmZdd lmZdd lmZmZmZm Z m!Z!m"Z"dd l#m$Z$dd l%m&Z&e&Z'e(d ej)j*ej)j*fZ+GdddZ,dS)) annotationsN) constants)AnsibleFileNotFoundAnsibleParserError) is_executable) binary_type text_type)to_bytes to_nativeto_text)unquote) from_yaml)VaultLibb_HEADER is_encryptedis_encrypted_fileparse_vaulttext_envelopePromptVaultSecret) unfrackpath)Displayz(?:^|%s)+tasks%s?$c@seZdZdZddZdWdd ZdXdYddZdZd[ddZd\ddZd\ddZ d\d d!Z d]d#d$Z d\d%d&Z d^d_d-d.Z d`d/d0Zdad1d2Zdbd4d5Zdcd7d8Zd\d9d:Zddded>d?ZdddfdAdBZdgdEdFZdhdidIdJZdjdKdLZdkdMdNZdldmdSdTZdndUdVZd'S)o DataLoaderaU The DataLoader class is used to load and parse YAML or JSON content, either from a given file name or from a string that was previously read in through other means. A Vault password can be specified, and any vault-encrypted files will be decrypted. Data read from files will also be cached, so the file will never be read from disk more than once. Usage: dl = DataLoader() # optionally: dl.set_vault_secrets([('default', ansible.parsing.vault.PrompVaultSecret(...),)]) ds = dl.load('...') ds = dl.load_from_file('/path/to/file') cCs2d|_t|_t|_i|_t|_|ddS)N.) _basedirdict _FILE_CACHEset _tempfiles_vaultsr_vaultset_vault_secretsselfr"E/usr/local/lib/python3.10/dist-packages/ansible/parsing/dataloader.py__init__4s zDataLoader.__init__ vault_secrets*list[tuple[str, PromptVaultSecret]] | NonereturnNonecCs ||j_dSN)rsecrets)r!r%r"r"r#rIs zDataLoader.set_vault_secretsTFdatastr file_name show_contentbool json_onlyt.AnycCst||||jj|dS)zBackwards compat for now)r1)r rr*)r!r,r.r/r1r"r"r#loadLszDataLoader.loadallcacheunsafec Cs||}td||dkr||jvr|j|}n+||\}}t|dd}|j||||d}|dkr;||j|<n |dkrF|sF||j|<|rJ|St|S)a Loads data from a file, which can contain either JSON or YAML. :param file_name: The name of the file to load data from. :param cache: Options for caching: none|all|vaulted :param unsafe: If True, returns the parsed data as-is without deep copying. :param json_only: If True, only loads JSON data from the file. :return: The loaded data, optionally deep-copied for safety. zLoading data from %snonesurrogate_or_stricterrors)r,r.r/r1r4vaulted) path_dwimdisplaydebugr_get_file_contentsr r3copydeepcopy) r!r.r5r6r1 parsed_data b_file_datar/ file_datar"r"r#load_from_filePs       zDataLoader.load_from_filepathcC||}tjt|ddSNr8r9)r<osrFexistsr r!rFr"r"r# path_existsw zDataLoader.path_existscCs(||}tjt|ddp|tjkSrH)r<rIrFisfiler devnullrKr"r"r#is_file{s zDataLoader.is_filecCrGrH)r<rIrFisdirr rKr"r"r# is_directoryrMzDataLoader.is_directory list[str]cCs||}t|Sr))r<rIlistdirrKr"r"r#list_directorys  zDataLoader.list_directorycCs||}t|S)zis the given path executable?)r<rrKr"r"r#rs zDataLoader.is_executableN b_vault_databytes b_file_name bytes | Nonetuple[bytes, bool]c Cs@t|s d}||fSt|\}}}}|jj||d}d}||fS)zMDecrypt b_vault_data if encrypted and return b_data and the show_content flagTfilenameF)rrrdecrypt) r!rVrXr/ b_ciphertext b_version cipher_namevault_idb_datar"r"r#_decrypt_if_vault_datasz!DataLoader._decrypt_if_vault_datac Cs|r t|ttfstdt|t||}||s#td|dz#t |d}| }| ||WdWS1s?wYWdSt t fy`}z td|t|f|dd}~ww)a  Reads the file contents from the given file name If the contents are vault-encrypted, it will decrypt them and return the decrypted data :arg file_name: The name of the file to read. If this is a relative path, it will be expanded relative to the basedir :raises AnsibleFileNotFound: if the file_name does not refer to a file :raises AnsibleParserError: if we were unable to read the file :return: Returns a byte string of the file contents Invalid filename: '%s'z Unable to retrieve file contentsr.rbN8an error occurred while trying to read the file '%s': %sorig_exc) isinstancerrrr r r<rLropenreadrcIOErrorOSError)r!r.rXfr,er"r"r#r?s     (zDataLoader._get_file_contentscCs|jS)z returns the current basedir )rr r"r"r# get_basedirszDataLoader.get_basedirbasedircCs|dur t||_dSdS)zK sets the base directory, used to find files when a relative path is given N)r r)r!rrr"r"r# set_basedirszDataLoader.set_basedirgivencCs^t|}t|dd}|ttjjs|dr|}nt|jdd}tj||}t|ddS)z= make relative paths work like folks expect. r8r9~Ffollow) r r startswithrIrFseprjoinr)r!rtrFrrr"r"r#r<s  zDataLoader.path_dwimc Cs&t|dd}tj|}tt|dddd}tj|dtj|dtj|df}tj|dtj|d tj|d tj|d tj|d tj|d tj|dtj|d tj|d tj|d tj|d tj|d f }ttjj|}ttjj|}t |rt |st |rdSdS)zR imperfect role detection, roles are still valid w/o tasks|meta/main.yml|yaml|etc r8r9Frvsmain.ymls main.yamlsmainstasks/main.ymlstasks/main.yamls tasks/mains meta/main.ymlsmeta/main.yamls meta/mainT) r rIrFdirnamerrzmaprJRE_TASKSsearchany) r!rFb_pathb_path_dirnameb_upathuntasked_paths tasked_pathsexists_untasked exists_taskedr"r"r#_is_roles2                 zDataLoader._is_roler{sourceis_rolec Csg}t|dd}|ttjjs|dr |t|ddn|tj|||t|dd}|s8||}|rIt |rIttj |dd}|j }| ||ttj|||dd| ||r{||s{|ttj|d|dd|ttj||dd|ttj||dd||tj||||||D]}tjt|ddr|Sq|S)z find one file in either a role or playbook dir with or without explicitly named dirname subdirs Used in action plugins and lookups to find supplemental files that could be in either place. r8r9ruFrvtasks)r rxrIrFryappendrrzrr}r~r{rrsendswithr<rJr ) r!rFr{rrr~rr cur_basedir candidater"r"r#path_dwim_relatives4     zDataLoader.path_dwim_relativepathscCst|dd}t|dd}d}g}|durtdn|r;|ds(|tjjr;t|dd} tjt| ddr:| }nt dd ||D]W} t| dd} t| dd} tj | } |sb| | r| d r|tj tj | |||tj | ||d d |kr|tj | |||tj | |qG|d d |kr|tj t|dd|||tj t|dd|t d td ||D]}td|t|ftj|rt|}nq|durt|dd|Dd|S)au find one file in first path in stack taking roles into account and adding play basedir as fallback :arg paths: A list of text strings which are the paths to look for the filename in. :arg dirname: A text string representing a directory. The directory is prepended to the source to form the path to search for. :arg source: A text string which is the filename to search for :rtype: A text string :returns: An absolute path to the filename ``source`` if found :raises: An AnsibleFileNotFound Exception if the file is found to exist in the search paths r8r9Nz:Invalid request to find a file that matches a "null" valueruFrvzevaluation_path: %sz s/tasks/rzsearch_path: %ss zlooking for "%s" at "%s"cSsg|]}t|qSr")r ).0pr"r"r# _sz7DataLoader.path_dwim_relative_stack..)r.r)r r=warningrxrIrFryrrJr>rzr{rrrsplitrqr vvvvvr)r!rr{rr b_dirnameb_sourceresultr~ test_pathrFupathr b_pb_base_dir b_candidater"r"r#path_dwim_relative_stack)sF      "   z#DataLoader.path_dwim_relative_stackcontent str | bytesc Csztjtjd\}}t|d}t|}z$z||Wnty0}z t |t|d}~wwW| |S| w)z. Create a tempfile containing defined content )dirwbN) tempfilemkstempCDEFAULT_LOCAL_TMPrIfdopenr write Exceptionremoveclose)r!rfdcontent_tempfileroerrr"r"r#_create_content_tempfilecs   z#DataLoader._create_content_tempfile file_pathr]c Cs4|r t|ttfstdt|t|dd}||r!||s&t|d| |}zR|r{t t|d>}t |t t drj|}|jjsNtdt||jj||d}||}|j|Wd |WSWd |WS1svwY|WSttfy}ztd t|t|f|d d }~ww) z If the file is vault encrypted return a path to a temporary decrypted file If the file is not encrypted then the path is returned Temporary files are cleanup in the destructor rdr8r9rerf)countz:A vault password or secret must be specified to decrypt %sr[Nrgrh)rjrrrr r rLrPrr<rkrlenrrlrr*r]rraddrmrn)r!rr] b_file_path real_pathror,rpr"r"r# get_real_fileqs6      zDataLoader.get_real_filecCs(||jvrt||j|dSdS)z Removes any temporary files created from a previous call to get_real_file. file_path must be the path returned from a previous call to get_real_file. N)rrIunlinkr)r!rr"r"r#cleanup_tmp_files  zDataLoader.cleanup_tmp_filec CsXt|jD]$}z||Wqty)}ztdt|WYd}~qd}~wwdS)z Removes all temporary files that DataLoader has created NOTE: not thread safe, forks also need special handling see __init__ for details. z Unable to cleanup temp files: %sN)listrrrr=rr )r!rorpr"r"r#cleanup_all_tmp_filessz DataLoader.cleanup_all_tmp_filesname extensionslist[str] | None allow_dirc Csttj||}g}|durdgtj}|D]@}d|vr$|t|}n|r0d|t|g}n|}||rW||rM|rL|| t |||Sq| t ||Sq|S)z Find vars files in a given path with specified name. This will find files in a dir named / or a file called ending in known extensions. Nr.) r rIrFrzrYAML_FILENAME_EXTENSIONSrLrRextend_get_dir_vars_filesr r) r!rFrrrrfoundext full_pathr"r"r#find_vars_filess,    zDataLoader.find_vars_filescCsg}t||D]>}|dsG|dsGtj|d}tj||}||r5|s5| | ||q | |rG|rBt ||vrG| |q |S)Nrru)sortedrUrxrrIrFsplitextrzrRrrrPr r)r!rFrrspathr full_spathr"r"r#rs zDataLoader._get_dir_vars_files)r%r&r'r()r+TF) r,r-r.r-r/r0r1r0r'r2)r4FF) r.r-r5r-r6r0r1r0r'r2)rFr-r'r0)rFr-r'rSr))rVrWrXrYr'rZ)r.r-r'rZ)r'r-)rrr-r'r()rtr-r'r-)F) rFr-r{r-rr-rr0r'r-) rrSr{r-rr-rr0r'r-)rrr'r-)T)rr-r]r0r'r-)rr-r'r()r'r()NT) rFr-rr-rrrr0r'rS)rFr-rrSr'rS)__name__ __module__ __qualname____doc__r$rr3rErLrPrRrUrrcr?rqrsr<rrrrrrrrrr"r"r"r#r!s2    '          " 7 :  ( "r)- __future__rr@rIos.pathrertypingtansiblerransible.errorsrransible.module_utils.basicransible.module_utils.sixrr+ansible.module_utils.common.text.convertersr r r ansible.parsing.quotingr ansible.parsing.utils.yamlr ansible.parsing.vaultrrrrrransible.utils.pathransible.utils.displayrr=compilerFryr}rr"r"r"r#s(