o
    !dpR                     @   s  d dl Z d dlZd dlZd dlZd dlZd dl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mZmZ d dlmZ d dlmZ eeZdZe jddZd	Zd
ZedejZedZ edZ!dZ"d# Z$dd Z%dd Z&G dd deZ'dd Z(dd Z)dS )    N)ClientError)shlex_quoteurlopenensure_text_type)BasicCommand)!create_client_from_parsed_globalszOpsWorks-Instance   )minutesz/AWS/OpsWorks/z7arn:aws:iam::aws:policy/AWSOpsWorksInstanceRegistrationz^(?!-)[a-z0-9-]{1,63}(?<!-)$z^i-[0-9a-f]+$z^\d+\.\d+\.\d+\.\d+$z@http://169.254.169.254/latest/dynamic/instance-identity/documenta  
set -e
umask 007
AGENT_TMP_DIR=$(mktemp -d /tmp/opsworks-agent-installer.XXXXXXXXXXXXXXXX)
curl --retry 5 -L %(agent_installer_url)s | tar xz -C $AGENT_TMP_DIR
cat >$AGENT_TMP_DIR/opsworks-agent-installer/preconfig <<EOF
%(preconfig)s
EOF
exec sudo /bin/sh -c "OPSWORKS_ASSETS_DOWNLOAD_BUCKET=%(assets_download_bucket)s $AGENT_TMP_DIR/opsworks-agent-installer/boot-registration; rm -rf $AGENT_TMP_DIR"
c                 C   s   |  dt d S )Nzbuilding-command-table.opsworks)registerinject_commands)cli r   Busr/lib/python3.10/site-packages/awscli/customizations/opsworks.py
initialize=      r   c                 K   s   t || d< d S )Nr
   )OpsWorksRegister)Zcommand_tablesessionkwargsr   r   r   r   A   r   r   c                       s  e Zd ZdZed Zdddddddd	gd
ddddddddddddddddddddddddddd d!d"d#d d$d"d%dd&d'd(d)gZ fd*d+Z	d,d- Z
d.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? ZedEdAdBZedCdD Z  ZS )Fr   r
   z
        Registers an EC2 instance or machine with AWS OpsWorks.

        Registering a machine using this command will install the AWS OpsWorks
        agent on the target machine and register it with an existing OpsWorks
        stack.
    zstack-idTzZA stack ID. The instance will be registered with the
                         given stack.)namerequired	help_textzinfrastructure-classec2on-premiseszzSpecifies whether to register an EC2 instance (`ec2`)
                         or an on-premises instance (`on-premises`).)r   r   choicesr   zoverride-hostnamehostnamezrThe instance hostname. If not provided, the current
                         hostname of the machine will be used.)r   destr   zoverride-private-ip
private_ipaA  An IP address. If you set this parameter, the given IP
                         address will be used as the private IP address within
                         OpsWorks.  Otherwise the private IP address will be
                         determined automatically. Not to be used with EC2
                         instances.zoverride-public-ip	public_ipa?  An IP address. If you set this parameter, the given IP
                         address will be used as the public IP address within
                         OpsWorks.  Otherwise the public IP address will be
                         determined automatically. Not to be used with EC2
                         instances.zoverride-sshsshzmIf you set this parameter, the given command will be
                         used to connect to the machine.zssh-usernameusernamezXIf provided, this username will be used to connect to
                         the host.zssh-private-keyprivate_keyzhIf provided, the given private key file will be used
                         to connect to the machine.local
store_truezIf given, instead of a remote machine, the local
                         machine will be imported. Cannot be used together
                         with `target`.)r   actionr   zuse-instance-profilezRUse the instance profile instead of creating an IAM
                         user.target?z
[<target>]zEither the EC2 instance ID or the hostname of the
                         instance or machine to be registered with OpsWorks.
                         Cannot be used together with `--local`.)r   Zpositional_argnargsZsynopsisr   c                    s>   t t| | d | _d | _d | _d | _d | _d | _d | _	d S N)
superr   __init___stack_ec2_instance_prov_params_use_address_use_hostname_name_for_iam
access_key)selfr   	__class__r   r   r)   }   s   
zOpsWorksRegister.__init__c                 C   s"   | j d| _t| j d|| _d S )Niamopsworks)_sessioncreate_clientr4   r   r5   r1   argsZparsed_globalsr   r   r   _create_clients   s   
z OpsWorksRegister._create_clientsc                 C   sL   |  || | | | | | | | | | | | | d S r'   )r:   prevalidate_argumentsretrieve_stackvalidate_argumentsdetermine_detailscreate_iam_entitiessetup_target_machiner8   r   r   r   	_run_main   s   




zOpsWorksRegister._run_mainc                 C   s   |j s
|js
td|j r|jrtd|jr!t dkr!td|jr.|js*|jr.td|jdkrA|j	r:td|j
rAtd|jd	krM|jrMtd
|jr]t|js_td|j dS dS )zN
        Validates command line arguments before doing anything else.
        z%One of target or --local is required.z4Arguments target and --local are mutually exclusive.Linuxz6Non-Linux instances are not supported by AWS OpsWorks.zYArgument --override-ssh cannot be used together with --ssh-username or --ssh-private-key.r   z/--override-private-ip is not supported for EC2.z.--override-public-ip is not supported for EC2.r   z1--use-instance-profile is only supported for EC2.zxInvalid hostname: '%s'. Hostnames must consist of letters, digits and dashes only and must not start or end with a dash.N)r$   r!   
ValueErrorplatformsystemr   r   r    infrastructure_classr   r   use_instance_profiler   HOSTNAME_REmatchr1   r9   r   r   r   r;      sL   

z&OpsWorksRegister.prevalidate_argumentsc                    s  t d | jj jgdd d | _| jj| jd d| _ jdkr j	st d | j
jd| jd	 d
}dg i}g d| jv rP|d d| jd gd ndd  t jrd jg|d< n t jrx fdd  j| _n|d d jgd fdd|jdi |d D }|std j t|dkrtd jddd |D f |d | _dS dS dS )z
        Retrieves the stack from the API, thereby ensures that it exists.

        Provides `self._stack`, `self._prov_params`, `self._use_address`, and
        `self._ec2_instance`.
        z,Retrieving stack and provisioning parameters)ZStackIdsZStacksr   StackIdrK   r   z#Retrieving EC2 instance informationRegion)Zregion_nameZFiltersVpcIdzvpc-id)NameZValuesc                 S   s   d| vS )NrN   r   instancer   r   r   <lambda>   s    z1OpsWorksRegister.retrieve_stack.<locals>.<lambda>ZInstanceIdsc                    s    |  d jkp|  d jkS )NPrivateIpAddressPublicIpAddress)getr$   rP   r9   r   r   rR      s   ztag:Namec                    s4   g | ]}|d  D ] t  fddD r qqS )	Instancesc                 3   s    | ]}| V  qd S r'   r   ).0cir   r   	<genexpr>       z=OpsWorksRegister.retrieve_stack.<locals>.<listcomp>.<genexpr>)all)rX   r)
conditionsrZ   r   
<listcomp>   s    z3OpsWorksRegister.retrieve_stack.<locals>.<listcomp>ZReservationsz&Did not find any instance matching %s.   z)Found multiple instances matching %s: %s.z, c                 s   s    | ]}|d  V  qdS )Z
InstanceIdNr   )rX   r[   r   r   r   r\     r]   z2OpsWorksRegister.retrieve_stack.<locals>.<genexpr>Nr   )LOGdebugr5   Zdescribe_stacksstack_idr*   Z&describe_stack_provisioning_parametersr,   rF   r!   r6   r7   appendINSTANCE_ID_RErI   r$   IP_ADDRESS_REr-   describe_instancesrC   lenjoinr+   )r1   r9   r   Z	desc_args	instancesr   )r9   r`   r   r<      sd   






zOpsWorksRegister.retrieve_stackc                    s    j r!| jj| jd dd }t fdd|D r!td j   jdkrA jrCt	t
tt d }|| jd	 krEtd
dS dS dS )zS
        Validates command line arguments using the retrieved information.
        rK   rL   rW   c                 3   s"    | ]} j  |d  kV  qdS )ZHostnameN)r   lower)rX   rQ   rV   r   r   r\     s    z6OpsWorksRegister.validate_arguments.<locals>.<genexpr>z@Invalid hostname: '%s'. Hostnames must be unique within a stack.r   regionrM   z1The stack's and the instance's region must match.N)r   r5   ri   r*   anyrC   rF   r!   jsonloadsr   r   IDENTITY_URLread)r1   r9   rl   rn   r   rV   r   r=   	  s4   z#OpsWorksRegister.validate_argumentsc                 C   s   | j s6|jrn/|jdkr-d| jv r| jd | _ nd| jv r)td | jd | _ ntd|jdkr6|j| _ |jrC|j| _	|j| _
dS |jrPd| _	t | _
dS d| _	|j| _
dS )a  
        Determine details (like the address to connect to and the hostname to
        use) from the given arguments and the retrieved data.

        Provides `self._use_address` (if not provided already),
        `self._use_hostname` and `self._name_for_iam`.
        r   rT   rS   zYInstance does not have a public IP address. Trying to use the private address to connect.z1The instance does not seem to have an IP address.r   N)r-   r!   rF   r+   rc   warningrC   r$   r   r.   r/   socketgethostnamerJ   r   r   r   r>      s0   




z"OpsWorksRegister.determine_detailsc                 C   sP  |j rtd d| _dS td dt| jd  }z| jj|td td| W n& t	yQ } z|j
di d	d
krFtd| n W Y d}~nd}~ww td dtt| jd dtt| jdf }tdD ]D}||rxd| nd }z
| jj|td W n& t	y } z|j
di d	d
krtd| n W Y d}~qod}~ww td|  ntdtd | jj||d z
| jjt|d W n@ t	y } z3|j
di d	dkrtdt| | jjt| | jd t|d tdt| n W Y d}~nd}~ww tdt| td  | jj|d!d" | _dS )#zp
        Creates an IAM group, user and corresponding credentials.

        Provides `self.access_key`.
        zSkipping IAM entity creationNz#Creating the IAM group if necessaryzOpsWorks-%srK   )	GroupNamePathzCreated IAM group %sErrorZCodeZEntityAlreadyExistszIAM group %s exists, continuingzCreating an IAM userzOpsWorks-%s-%srO         z+%s )UserNamerx   z/IAM user %s already exists, trying another namezCreated IAM user %sz&Couldn't find an unused IAM user name.z3Adding the user to the group and attaching a policy)rw   r}   )Z	PolicyArnr}   ZAccessDeniedzFUnauthorized to attach policy %s to user %s. Trying to put user policyZArn)Z
PolicyNameZPolicyDocumentr}   zPut policy %s to user %szAttached policy %s to user %szCreating an access key)r}   Z	AccessKey)rG   rc   rd   r0   clean_for_iamr*   r4   Zcreate_groupIAM_PATHr   responserU   shorten_namer/   rangeZcreate_userrC   Zadd_user_to_groupZattach_user_policyIAM_POLICY_ARNZput_user_policyIAM_USER_POLICY_NAME_iam_policy_documentIAM_USER_POLICY_TIMEOUTZcreate_access_key)r1   r9   Z
group_nameeZbase_usernameZtry_r   r   r   r   r?   G  s   


	




z$OpsWorksRegister.create_iam_entitiesc                 C   sj   t | jd | | || jd d d }|jr(td tdd|g d	S td | 	|| d	S )
zz
        Setups the target machine by copying over the credentials and starting
        the installation process.
        ZAgentInstallerUrl
Parametersassets_download_bucket)Zagent_installer_urlZ	preconfigr   zRunning the installer locally/bin/sh-cz6Connecting to the target machine to run the installer.N)
REMOTE_SCRIPTr,   _to_ruby_yaml_pre_config_documentr!   rc   rd   
subprocess
check_callr   )r1   r9   remote_scriptr   r   r   r@     s   	

z%OpsWorksRegister.setup_target_machinec              	   C   sD  t  dkr]zOtjddd}|| |  |jr|j}n!d}|jr*|d|j 7 }|jr4|d|j 7 }|d| j	 7 }|d	7 }|d|j
 7 }tj|d
d W t|j
 dS t|j
 w |jritt|j}n ddg}|jrx|d|jg |jr|d|jg || j	 dd|g}|ddd |D  t| dS )zA
        Runs a (sh) script on a remote machine via SSH.
        WindowswtF)deleteZplinkz -l "%s"z -i "%s"z "%s"z -mT)shellr   z-ttz-lz-ir   r    c                 s   s    | ]}t |V  qd S r'   )r   )rX   wordr   r   r   r\     r]   z'OpsWorksRegister.ssh.<locals>.<genexpr>N)rD   rE   tempfileNamedTemporaryFilewritecloser   r   r    r-   r   r   r   osremoveshlexsplitstrextendrf   rk   )r1   r9   r   Zscript_filecallZremote_callr   r   r   r     s8   

zOpsWorksRegister.sshc                 C   s   t dd| jd i| jd }| jr | jd |d< | jd |d< | jr(| j|d< |jr0|j|d	< |jr8|j|d
< |jdk|d< t	d| |S )Nre   rK   r   ZAccessKeyIdZaccess_key_idZSecretAccessKeyZsecret_access_keyr   r   r   r   importzUsing pre-config: %rr   )
dictr*   r,   r0   r.   r   r   rF   rc   rd   )r1   r9   
parametersr   r   r   r     s$   


z%OpsWorksRegister._pre_config_documentNc                 C   sN   dd| d}|d urt j  | }dd|dii|d< |gdd	}t|S )
Nzopsworks:RegisterInstanceZAllow)ZActionZEffectResourceZDateLessThanzaws:CurrentTimez%Y-%m-%dT%H:%M:%SZ	Conditionz
2012-10-17)Z	StatementVersion)datetimeutcnowstrftimerp   dumps)Zarntimeout	statementZvalid_untilZpolicy_documentr   r   r   r     s   
z%OpsWorksRegister._iam_policy_documentc                 C   s   d dd t|  D S )N
c                 s   s&    | ]\}}d |t |f V  qdS )z:%s: %sN)rp   r   )rX   kvr   r   r   r\     s    z1OpsWorksRegister._to_ruby_yaml.<locals>.<genexpr>)rk   sorteditems)r   r   r   r   r   	  s   

zOpsWorksRegister._to_ruby_yamlr'   )__name__
__module____qualname__NAMEtextwrapdedentstripZDESCRIPTIONZ	ARG_TABLEr)   r:   rA   r;   r<   r=   r>   r?   r@   r   r   staticmethodr   r   __classcell__r   r   r2   r   r   E   sp    	.

'L'\(r   c                 C   s   t dd| S )z9
    Cleans a name to fit IAM's naming requirements.
    z[^A-Za-z0-9+=,.@_-]+-)resub)r   r   r   r   r~     s   r~   c                 C   sD   t | |kr| S t|d d\}}| d||  d | | d  S )z<
    Shortens a name to the given number of characters.
          Nz...)rj   divmod)r   
max_lengthqr_   r   r   r   r     s   "r   )*r   rp   loggingr   rD   r   r   ru   r   r   r   Zbotocore.exceptionsr   Zawscli.compatr   r   r   Zawscli.customizations.commandsr   Zawscli.customizations.utilsr   	getLoggerr   rc   r   	timedeltar   r   r   compileIrH   rg   rh   rr   lstripr   r   r   r   r~   r   r   r   r   r   <module>   sH   


   M