o nnhC@sddlmZddlmZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddl mZddlmZddlmZddlmZmZdd lmZdd lmZdd lmZeZGd d d eZ dddZ!e"dkr{e!dSdS)) annotations)CLIN) constants)context)option_helpers)AnsibleOptionsError) to_nativeto_text) module_loader)run_cmd)DisplaycseZdZdZdZdZdZdZdddZd d iZ d Z e d d Z fddZ fddZfddZe ddZe ddZZS)PullCLIaO Used to pull a remote copy of ansible on each managed node, each set to run via cron and update playbook source via a source repository. This inverts the default *push* architecture of ansible into a *pull* architecture, which has near-limitless scaling potential. None of the CLI tools are designed to run concurrently with themselves, you should use an external scheduler and/or locking to ensure there are no clashing operations. The setup playbook can be tuned to change the cron frequency, logging locations, and parameters to ansible-pull. This is useful both for extreme scale-out as well as periodic remediation. Usage of the 'fetch' module to retrieve logs from ansible-pull runs would be an excellent way to gather and analyze remote logs from ansible-pull. z ansible-pullgitz local.yml)r subversionhgbzrzFile does not existzFile is not readable) playbook.ymlaThe name of one the YAML format files to run as an Ansible playbook. This can be a relative path within the checkout. By default, Ansible will look for a playbook based on the host's fully-qualified domain name, on the host hostname and finally a playbook named *local.yml*.TcCsdd}tjddr0tjdD]!}t|tr|dd|7}qd|vs)tj|r/|d|7}q|S)N inventoryFz -i '%s' ,z -i %s ) rCLIARGSget isinstancelistjoinospathexists)inv_optsinvr";/usr/local/lib/python3.10/dist-packages/ansible/cli/pull.py _get_inv_cliBs  zPullCLI._get_inv_clicstt|jdddt|jt|jt|jt|jt |jt |jt |j|jj ddddd|jj d d d d d |jj dddd d dd|jj dddddd|jj dddd d dd|jj ddddt d d!|jj d"d#d$dd%d|jj d&d'd d(d)|jj d*d+d,d-d.|jj d/d d0d d1d2|jj d3d4d5|jd6|j|jfd|jj d7d8d d d9d|jj d:d;d d dd d d?d|jj d@d dAd dBd2|jj dCtjdDd dEd2dS)Fz* create an options parser for bin/ansible z0%prog -U [options] []z@pulls playbooks from a VCS repo and executes them on target host)usagedescargsz Playbook(s)r*)helpmetavarnargsz--purgeF store_truez!purge checkout after playbook run)defaultactionr)z-oz--only-if-changed ifchangedz8only run the playbook if the repository has been updated)destr-r.r)z-sz--sleepsleepNz|sleep for random interval (between 0 and n number of seconds) before starting. This is a useful way to disperse git requests)r0r-r)z-fz--forceforcezr post_process_argsr0socketgetfqdnrrrrM ANSIBLE_HOMErisdirrr1randomrandintint ValueErrorr4r8rL verbositydisplayvalidate_conflicts)rOoptionshostnamesecsrPr"r#rSs(    zPullCLI.post_process_argsc sFtt|tj}t|dtdtj t }t }dt|||dd|ddg}|rAd|}nd}d}tjd dkr`|d d d d tdtjd D7}|}|std}|dtdtj7}tjddkrdtjdtjdf}tjdr|dtjd7}tjdr|d7}tjdr|dtjd7}tjdr|d7}tjdr|d7}tjd s|d!7}ntjdd"krd#tjdtjdf}tjdr|d$tjd7}tjd s|d%7}nWtjdd&krd#tjdtjdf}tjdr|d$tjd7}n3tjdd'kr;dtjdtjdf}tjdr:|dtjd7}ntd(tjdd|jftjd)rT|d*7}ttjd} | d+urjtd,tjdtjtjtj d} d-| ||tjd||f} tjd.D] } | d/t| 7} qtjd0rtd1tjd0t tjd0t!d2t"d3| t#| d4d5\} }}| dkrtjd6rt$d7n| Stjd8rd9|vrtd:dS|%tjd}|d+urtd;d<| ||f} tjd=rtjd=D] }| d>|7} q tjd?r*tjd?D] }| d@|7} q tjdAr9| dBtjdA7} tjdCrH| dDtjdC7} tjd.D] } | d/t| 7} qMtjdErd| dF7} tjdGrx| dHt&dtjdG7} tjdIr| dJt&dtjdI7} tjdKr| dLtjdK7} n| dL|7} tjdMr| dN7} tjdOr| dP7} t'tjd|}|r| |7} t!dQt!d3| t#| d4d5\} }}tjdRr!t'dSzt!dTtjdt()tjdW| St*y }zt+dUtjdt,|fWYd+}~| Sd+}~ww| S)Vz! use Runner lib to do SSH things zStarting Ansible Pull at %F %T r.rzlocalhost,%s,127.0.0.1zlocalhost,127.0.0.1z -c local r\z -%srcSsg|]}dqS)vr").0xr"r"r# szPullCLI.run..z -i localhost, z-e %s zansible_python_interpreter=%sr8rzname=%s dest=%sr4r0r6z version=%sr7z accept_hostkey=yesprivate_key_filez key_file=%sr9z verify_commit=yesr;z track_submodules=yesr5z depth=1rzrepo=%s dest=%sz revision=%sz export=yesrrz5Unsupported (%s) SCM module for pull, choices are: %sr:z force=yesNzmodule '%s' not found. z*%s/ansible %s %s -m %s -a "%s" all -l "%s" extra_varsz -e %sr1zSleeping for %d seconds...z0running ansible with VCS module to checkout repozEXEC: %sT)liver2zFUnable to update repository. Continuing with (forced) run of playbook.r/s"changed": truez%Repository has not changed, quitting.z!Could not find a playbook to run.z%s/ansible-playbook %s %svault_password_filesz --vault-password-file=%s vault_idsz --vault-id=%sbecome_password_filez --become-password-file=%sconnection_password_filez --connection-password-file=%sbecome_ask_passz --ask-become-pass skip_tagsz --skip-tags "%s"tagsz -t "%s"subsetz -l "%s"r<z -Cr=z -Dz*running ansible-playbook to do actual workpurge/z removing: %szFailed to remove %s: %s)-r>r rundatetimenowr]strftimersysargvplatformnoderTrUsetsplitrrranger$shlexquote executablerrLr find_pluginrrdirnameabspathtimer1debugvvvvr warningselect_playbookrchdirshutilrmtree Exceptionerrorr )rOrwr|host hostnames limit_opts base_optsr repo_optsrbin_pathcmdevrcb_outb_errplaybookvault_password_filevault_iderPr"r#rus * (                                  &z PullCLI.runcCs&tj|sdSt|tjsdSdS)Nrrr)rrraccessR_OK)rr"r"r# try_playbookCs zPullCLI.try_playbookc Csdd}g}tjdr`tjdddur`g}tjdD]$}tj||}t|}|dkr8|d|tj|fq||qdt |krNt d||St |t tjdkr^d|}|St }tj||d}tj||ddd} tj|tj} || | fD]} t| }|dkr| }n |d| tj|fq|durt d||S)Nr'rz%s: %s rbz.ymlrc)rrrrrr rappendPLAYBOOK_ERRORSlenr]rrTrUr~DEFAULT_PLAYBOOK) rrerrors playbooksbook book_pathrfqdnhostpb shorthostpblocalpbpbr"r"r#rKs<     zPullCLI.select_playbook)__name__ __module__ __qualname____doc__namerKrrLr ARGUMENTSSKIP_INVENTORY_DEFAULTS staticmethodr$r?rSrurr __classcell__r"r"rPr#r #s*  4 % r cCst|dSN)r cli_executor)r'r"r"r#mainnsr__main__r)# __future__r ansible.clirrvrr{rXrrrTryransiblerrMransible.cli.argumentsrr@ansible.errorsr+ansible.module_utils.common.text.convertersrr ansible.plugins.loaderr ansible.utils.cmd_functionsr ansible.utils.displayr r]r rrr"r"r"r#s6          M