o
    w7e"                  
   @   s  U d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZ ddlmZ dd	lmZmZ dd
lmZmZ ddlmZ ddlmZmZ ddlmZmZ dddeegdgedededgdZ ee!d< ee Z e	e"Z#dZ$G dd dej%Z&G dd de&Z'G dd de&Z(de)ded ed!e*d"df
d#d$Z+de,fd%d&Z-de,d"e,fd'd(Z.d)e&de,fd*d+Z/de,de&fd,d-Z0de,de&fd.d/Z1dS )0z9ansible enables running on first boot either ansible-pull    N)deepcopy)	getLogger)dedent)Optional)Cloud)Config)
MetaSchemaget_meta_doc)ALL_DISTROSDistro)PER_INSTANCE)subpwhich)Versionget_cfg_by_path
cc_ansibleAnsiblezConfigure ansible for instanceansiblea          This module provides ``ansible`` integration for
        augmenting cloud-init's configuration of the local
        node.


        This module installs ansible during boot and
        then uses ``ansible-pull`` to run the playbook
        repository at the remote URL.
        z            ansible:
              package_name: ansible-core
              install_method: distro
              pull:
                url: "https://github.com/holmanb/vmboot.git"
                playbook_name: ubuntu.yml
            z            ansible:
              package_name: ansible-core
              install_method: pip
              pull:
                url: "https://github.com/holmanb/vmboot.git"
                playbook_name: ubuntu.yml
            )idnametitle	frequencydistrosactivate_by_schema_keysdescriptionexamplesmetaansible_configc                   @   sz   e Zd ZdefddZdee fddZdefddZ	d	d
 Z
defddZdd Zejdd ZejdefddZdS )AnsiblePulldistroc                 C   s>   dg| _ ddg| _|| _tj| _d | _| jdd| jd< d S )Nzansible-pullz	--versionHOMEz/root)cmd_pullcmd_versionr   osenvironenvrun_userget)selfr    r)   =/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py__init__E   s   
zAnsiblePull.__init__returnc                 C   sF   |  | j\}}| d}td|}|r!|d}t|S d S )Nr   z	([\d\.]+))	do_asr"   
splitlinespopresearchgroupr   from_str)r(   stdout_
first_linematchesversionr)   r)   r*   get_versionP   s   

zAnsiblePull.get_versionc                 G   s   |  g | j|\}}|S N)r-   r!   )r(   argsr4   r5   r)   r)   r*   pullY   s   zAnsiblePull.pullc                 C   s   |   stdd S )Nz!command: ansible is not installed)is_installed
ValueErrorr(   r)   r)   r*   
check_deps]   s   zAnsiblePull.check_depscommandc                 K   s0   | j s| j|fi |S | jj|| j fi |S r:   )r&   r   r   r-   r(   rA   kwargsr)   r)   r*   r-   a   s   zAnsiblePull.do_asc                 K   s   t |fd| ji|S )Nr%   )r   r%   rB   r)   r)   r*   r   f   s   zAnsiblePull.subpc                 C      d S r:   r)   r?   r)   r)   r*   r=   i      zAnsiblePull.is_installedpkg_namec                 C   rD   r:   r)   r(   rF   r)   r)   r*   installm   rE   zAnsiblePull.installN)__name__
__module____qualname__r   r+   r   r   r9   strr<   r@   listr-   r   abcabstractmethodr=   rH   r)   r)   r)   r*   r   D   s    	
r   c                       sF   e Zd Zdedee f fddZdefddZdefd	d
Z	  Z
S )AnsiblePullPipr   userc                    sh   t  | || _| tjddg\}}| d}| jd}|r-d||g| jd< d S || jd< d S )Nz-cz('import site; print(site.getuserbase())'z/bin/PATH:)	superr+   r&   r-   sys
executabler%   r'   join)r(   r   rQ   	user_baser5   ansible_pathold_path	__class__r)   r*   r+   s   s   

zAnsiblePullPip.__init__rF   c                 C   s   |   sTzddl}W n ty   | j| jj Y nw tjdddg}tj	
tj	tddr6|d | jr>|d	 | g |d
d | g || dS dS )zishould cloud-init grow an interface for non-distro package
        managers? this seems reusable
        r   N-mpiprH   stdlibzEXTERNALLY-MANAGEDz--break-system-packagesz--userz	--upgrade)r=   r^   ImportErrorr   install_packagespip_package_namerU   rV   r#   pathexistsrW   	sysconfigget_pathappendr&   r-   )r(   rF   r^   cmdr)   r)   r*   rH      s,   


zAnsiblePullPip.installr,   c                 C   s    |  tjdddg\}}d|v S )Nr]   r^   rM   r   )r-   rU   rV   )r(   r4   r5   r)   r)   r*   r=      s   zAnsiblePullPip.is_installed)rI   rJ   rK   r   r   rL   r+   rH   boolr=   __classcell__r)   r)   r[   r*   rP   r   s    rP   c                   @   s(   e Zd ZdefddZdefddZdS )AnsiblePullDistrorF   c                 C   s   |   s| j| d S d S r:   )r=   r   ra   rG   r)   r)   r*   rH      s   zAnsiblePullDistro.installr,   c                 C   s   t tdS )Nr   )ri   r   r?   r)   r)   r*   r=      s   zAnsiblePullDistro.is_installedN)rI   rJ   rK   rL   rH   ri   r=   r)   r)   r)   r*   rk      s    rk   r   cfgcloudr;   r,   c                 C   s   | di }| d}| d}| d}| d}| d}	| dd}
|rkt| |j}|d	kr8t||}nt|}||
 |  | d
d}|rR||jt< |rYt	|| |	rbt
|t|	 |rmt|| d S d S d S )Nr   r&   install_methodsetup_controllergalaxyr<   package_name r^   r   )r'   validate_configr   rP   rk   rH   r@   r%   CFG_OVERRIDEansible_galaxyrun_ansible_pullr   ansible_controller)r   rl   rm   r;   ansible_cfgansible_userrn   ro   
galaxy_cfgpull_cfgrq   r   r   r   r)   r)   r*   handle   s4   







r|   c                 C   s   d}|D ]}t | |std| d|  q| dr/dD ]}t | |s.td| d|  q| d}|rIt|d|dgsItd	| | d
 }|dvrUtdd S )N)rn   rq   zMissing required key 'z' from r<   )zpull/urlzpull/playbook_namero   repositoriesrun_ansiblezMissing required key from rn   )r^   r   z Invalid install method {install})r   r>   r'   any)rl   required_keyskeycontroller_cfgrH   r)   r)   r*   rs      s,   



rs   c                 C   s   dd |   D S )zremove boolean false valuesc                 S   s&   i | ]\}}|d ur| dd|qS )Fr5   -)replace.0r   valuer)   r)   r*   
<dictcomp>   s
    zfilter_args.<locals>.<dictcomp>)items)rl   r)   r)   r*   filter_args   s   r   r<   c                 C   s   | d}|  }|std n|tdddk r/|dr/td|j d|j d|j	 d	| j
g d
d t| D |R  }|rMtj|  d S d S )Nplaybook_namezCannot parse ansible version      r   diffzAnsible version .z%doesn't support --diff flag, exiting.c                 S   s2   g | ]\}}|d urd| d| nd| qS )T--=r)   r   r)   r)   r*   
<listcomp>  s     z$run_ansible_pull.<locals>.<listcomp>)r/   r9   LOGwarningr   r'   r>   majorminorpatchr<   r   r   rU   r4   write)r<   rl   r   vr4   r)   r)   r*   rv      s&   


rv   c                 C   s4   |  dg }|std|  |D ]}|| qd S )NactionszInvalid config: %s)r'   r   r   r-   )rl   r   r   rA   r)   r)   r*   ru     s   ru   c                 C   s   |  dg D ]}|dd|d |d g q|  dg D ]"}|d}|d}d	|gd
d t| D }|j||d qd S )Nr}   gitclonesourcerc   r~   playbook_dirr   zansible-playbookc                 S   s    g | ]\}}d | d| qS )r   r   r)   r   r)   r)   r*   r   !  s     z&ansible_controller.<locals>.<listcomp>)cwd)r'   r-   r/   r   r   )rl   r   
repositoryr;   r   r   rA   r)   r)   r*   rw     s   

rw   )2__doc__rN   r#   r0   rU   re   copyr   loggingr   textwrapr   typingr   cloudinit.cloudr   cloudinit.configr   cloudinit.config.schemar   r	   cloudinit.distrosr
   r   cloudinit.settingsr   cloudinit.subpr   r   cloudinit.utilr   r   r   __annotations__rI   r   rt   ABCr   rP   rk   rL   rM   r|   dictrs   r   rv   ru   rw   r)   r)   r)   r*   <module>   s\    
+.0	%		