
    d{6                         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c mZ d dlmc mc mZ d dlmZ d dlmZ  G d de      Zy# e$ r d dlmZ d dlmc mZ d dlmZ d dlmZ Y .w xY w)    N)array_to_bytes)OSUtilError)DefaultOSUtilc                        e Zd Z fdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd ZddZddZd ZddZ fdZddZd Zd Zd Z fdZ xZS )BigIpOSUtilc                 *    t         t        |           y )N)superr   __init__)self	__class__s    E/usr/lib/python3/dist-packages/azurelinuxagent/common/osutil/bigip.pyr
   zBigIpOSUtil.__init__/   s    k4)+    c                     t        dd      D ]_  }t        j                  d       t        j                  dd      }|dk(  rt        j                  d        nt        j                  d	       a dk(  ry
t        d      )aW  Wait for mcpd to become available

        All configuration happens in mcpd so we need to wait that this is
        available before we go provisioning the system. I call this method
        at the first opportunity I have (during the DVD mounting call).
        This ensures that the rest of the provisioning does not need to wait
        for mcpd to be available unless it absolutely wants to.

        :return bool: Returns True upon success
        :raises OSUtilError: Raises exception if mcpd does not come up within
                             roughly 50 minutes (100 * 30 seconds)
           d   zChecking to see if mcpd is upzU/usr/bin/tmsh -a show sys mcp-state field-fmt 2>/dev/null | grep phase | grep runningFchk_errr   zmcpd is up!   Tz5mcpd hasn't completed initialization! Cannot proceed!)rangeloggerinfo	shellutilruntimesleepr   )r   retriesrcs      r   _wait_until_mcpd_is_initializedz+BigIpOSUtil._wait_until_mcpd_is_initialized2   s|     Q} 	GKK78v  AF  GBQwM*JJrN	 7C
 	
r   c                 h    d}t        j                  |      }|dk7  rt        j                  d       |S )Nz/usr/bin/tmsh save sys configr   z,WARNING: Cannot save sys config on 1st boot.)r   r   r   error)r   cmdr   s      r   _save_sys_configzBigIpOSUtil._save_sys_configO   s.    -]]37LLGH	r   c                 0    t        j                  dd      S )Nz/usr/bin/bigstart restart sshdFr   )r   r   r   s    r   restart_ssh_servicezBigIpOSUtil.restart_ssh_serviceV   s    }}=uMMr   c                 b    t        j                  dj                  | j                        d      S )Nz/sbin/service {0} stopFr   r   r   formatservice_namer$   s    r   stop_agent_servicezBigIpOSUtil.stop_agent_serviceY   s&    }}5<<T=N=NOY^__r   c                 b    t        j                  dj                  | j                        d      S )Nz/sbin/service {0} startFr   r'   r$   s    r   start_agent_servicezBigIpOSUtil.start_agent_service\   s&    }}6==d>O>OPZ_``r   c                 b    t        j                  dj                  | j                        d      S )Nz/sbin/chkconfig --add {0}Fr   r'   r$   s    r   register_agent_servicez"BigIpOSUtil.register_agent_service_   &    }}8??@Q@QR\abbr   c                 b    t        j                  dj                  | j                        d      S )Nz/sbin/chkconfig --del {0}Fr   r'   r$   s    r   unregister_agent_servicez$BigIpOSUtil.unregister_agent_serviceb   r/   r   c                 (    | j                  ddg      S )Nz/sbin/pidofdhclient)_get_dhcp_pidr$   s    r   get_dhcp_pidzBigIpOSUtil.get_dhcp_pide   s    !!=*"=>>r   c                      y)a>  Set the static hostname of the device

        Normally, tmsh is used to set the hostname for the system. For our
        purposes at this time though, I would hesitate to trust this function.

        Azure(Stack) uses the name that you provide in the Web UI or ARM (for
        example) as the value of the hostname argument to this method. The
        problem is that there is nowhere in the UI that specifies the
        restrictions and checks that tmsh has for the hostname.

        For example, if you set the name "bigip1" in the Web UI, Azure(Stack)
        considers that a perfectly valid name. When WAAgent gets around to
        running though, tmsh will reject that value because it is not a fully
        qualified domain name. The proper value should have been bigip.xxx.yyy

        WAAgent will not fail if this command fails, but the hostname will not
        be what the user set either. Currently we do not set the hostname when
        WAAgent starts up, so I am passing on setting it here too.

        :param hostname: The hostname to set on the device
        N r   hostnames     r   set_hostnamezBigIpOSUtil.set_hostnameh   s    , r   c                      y)zSets the DHCP hostname

        See `set_hostname` for an explanation of why I pass here

        :param hostname: The hostname to set on the device
        Nr7   r8   s     r   set_dhcp_hostnamezBigIpOSUtil.set_dhcp_hostname   s     r   c                     | j                  |      rt        j                  d|       ydddd|ddd	d
d	ddddddg}| j                  |dj	                  |             | j                          y)a?  Create user account using tmsh

        Our policy is to create two accounts when booting a BIG-IP instance.
        The first account is the one that the user specified when they did
        the instance creation. The second one is the admin account that is,
        or should be, built in to the system.

        :param username: The username that you want to add to the system
        :param expiration: The expiration date to use. We do not use this
                           value.
        :param comment: description of the account.  We do not use this value.
        z%User {0} already exists, skip useraddN/usr/bin/tmshcreateauthuserzpartition-accessadd{zall-partitionsroleadmin}shellbashz!Failed to create user account:{0}err_msgr   )get_userentryr   r    _run_command_raising_OSUtilErrorr(   r"   )r   username
expirationcommentr!   s        r   useraddzBigIpOSUtil.useradd   s     h'KK?J&&(DVX]_bdtFGS#w@--c;^;e;efn;o-pr   c           	          | j                  dddd|d|gdj                  |             | j                  d      }|t        d	      | j                  dddddd|gd
       | j	                          y)a  Change a user's password with tmsh

        Since we are creating the user specified account and additionally
        changing the password of the built-in 'admin' account, both must
        be modified in this method.

        Note that the default method also checks for a "system level" of the
        user; based on the value of UID_MIN in /etc/login.defs. In our env,
        all user accounts have the UID 0. So we can't rely on this value.

        :param username: The username whose password to change
        :param password: The unencrypted password to set for the user
        :param crypt_id: If encrypting the password, the crypt_id that was used
        :param salt_len: If encrypting the password, the length of the salt
                         value used to do it.
        r>   modifyr@   rA   passwordzFailed to set password for {0}rI   rE   z'The 'admin' user account was not found!z Failed to set password for adminr   )rL   r(   rK   r   r"   )r   rM   rS   crypt_idsalt_len	userentrys         r   chpasswdzBigIpOSUtil.chpasswd   s    & 	--h*hW4;;HE 	. 	G &&w/	GHH--hXV6 	. 	8 	r   c                 V    | j                  ddg       | j                  dddd|g       y)aw  Deletes a user account.

        Note that the default method also checks for a "system level" of the
        user; based on the value of UID_MIN in /etc/login.defs. In our env,
        all user accounts have the UID 0. So we can't rely on this value.

        We also don't use sudo, so we remove that method call as well.

        :param username:
        :return:
        touchz/var/run/utmpr>   deleter@   rA   N)_run_command_without_raising)r   rM   s     r   del_accountzBigIpOSUtil.del_account   s1     	))7O*DE))?HffV^*_`r   c                     d}t        j                  |      D cg c]  }t        j                  ||       c}D ]&  }|dj	                  |j                  d            c S  t        d      c c}w )a.  Find BIG-IP's CD/DVD device

        This device is almost certainly /dev/cdrom so I added the ? to this pattern.
        Note that this method will return upon the first device found, but in my
        tests with 12.1.1 it will also find /dev/sr0 on occasion. This is NOT the
        correct CD/DVD device though.

        :todo: Consider just always returning "/dev/cdrom" here if that device device
               exists on all platforms that are supported on Azure(Stack)
        :param dev_dir: The root directory from which to look for devices
        z(sr[0-9]|hd[c-z]|cdrom[0-9]?)z/dev/{0}r   zFailed to get dvd device)oslistdirrematchr(   groupr   )r   dev_dirpattendevdvds        r   get_dvd_devicezBigIpOSUtil.get_dvd_device   si     257ZZ5HIcBHHVS)I 	7C!((166	7 455 Js   A.c                 J    | j                          t        t        |   di |S )a  Mount the DVD containing the provisioningiso.iso file

        This is the _first_ hook that WAAgent provides for us, so this is the
        point where we should wait for mcpd to load. I am just overloading
        this method to add the mcpd wait. Then I proceed with the stock code.

        :param max_retry: Maximum number of retries waagent will make when
                          mounting the provisioningiso.iso DVD
        :param chk_err: Whether to check for errors or not in the mounting
                        commands
        r7   )r   r	   r   	mount_dvd)r   kwargsr   s     r   ri   zBigIpOSUtil.mount_dvd   s&     	,,.[$1;F;;r   c                 .    t        j                  d       y)a_  Runs the eject command to eject the provisioning DVD

        BIG-IP does not include an eject command. It is sufficient to just
        umount the DVD disk. But I will log that we do not support this for
        future reference.

        :param chk_err: Whether or not to check for errors raised by the eject
                        command
        z'Eject is not supported on this platformN)r   warn)r   r   s     r   	eject_dvdzBigIpOSUtil.eject_dvd   s     	=>r   c                    d}d}t        j                         d   }|dk(  rd}nd}t        j                  t        j                  t        j                  t        j
                        }t        j                  dd||z  z        }t        j                  d	||z  |j                         d         }t        j                  |j                         d
|      }t        j                  d	|      d   }	|	||z  k(  rt        j                  d|       t!        |      }t#        d||z  |      D ]  }
| j%                  ||
      }d|v r n |j'                  d      t        j(                  |
dz   |
dz          fS )a  Return the interface name, and ip addr of the management interface.

        We need to add a struct_size check here because, curiously, our 64bit
        platform is identified by python in Azure(Stack) as 32 bit and without
        adjusting the struct_size, we can't get the information we need.

        I believe this may be caused by only python i686 being shipped with
        BIG-IP instead of python x86_64??
            r   64bit(       B    iLi  z9SIOCGIFCONF returned more than {0} up network interfaces.s   lozlatin-1      )platformarchitecturesocketAF_INET
SOCK_DGRAMIPPROTO_UDParraystructpackbuffer_infofcntlioctlfilenounpackr   rl   r   r   _format_single_interface_namedecode	inet_ntoa)r   ifaceexpected
python_arcstruct_sizesockbuffparamretretsizeis              r   get_first_ifzBigIpOSUtil.get_first_if  sg    **,Q/
 KK}}V^^#..#//1 {{3K)? @AD$[0 ,,.q13 kk$++-7==s+A.x+-.KK /19; d#q+0+> 	A66tQ?E ~	 ||I&(8(8ad1R4(IIIr   c                 8    |||dz    j                  dd      d   S )Nrp   ru   r   r   )split)r   r   offsets      r   r   z)BigIpOSUtil._format_single_interface_name0  s%    F6"9%++E15a88r   c                 V    dj                  |||      }t        j                  |d      S )z{Add specified route using tmsh.

        :param net:
        :param mask:
        :param gateway:
        :return:
        z-/usr/bin/tmsh create net route {0}/{1} gw {2}Fr   )r(   r   r   )r   netmaskgatewayr!   s        r   	route_addzBigIpOSUtil.route_add3  s+     !'T7!; 	}}S%00r   c                     t        dd      D ]8  }t        j                  j                  d      r nt	        j
                  d       : t        t        | #  |      S )zReturn device name attached to ide port 'n'.

        Include a wait in here because BIG-IP may not have yet initialized
        this list of devices.

        :param port_id:
        :return:
        r   r   z/sys/bus/vmbus/devices/
   )	r   r^   pathexistsr   r   r	   r   device_for_ide_port)r   port_idr   r   s      r   r   zBigIpOSUtil.device_for_ide_port?  sM     Q} 	Gww~~78

2	 [$;GDDr   )NN)   r   )z/dev)T)__name__
__module____qualname__r
   r   r"   r%   r*   r,   r.   r1   r5   r:   r<   rP   rW   r\   rg   ri   rm   r   r   r   r   __classcell__)r   s   @r   r   r   -   s|    ,
:N`acc?0.!Fa62<
?(JT9
1E Er   r   )r   r   r^   ry   r`   r{   r   r   azurelinuxagent.common.futurer   azurelinuxagent.common.loggercommonr   &azurelinuxagent.common.utils.shellutilutilsr    azurelinuxagent.common.exceptionr   %azurelinuxagent.common.osutil.defaultr   ImportErrorazurelinuxagent.loggerazurelinuxagent.utils.shellutilazurelinuxagent.exception%azurelinuxagent.distro.default.osutilr   r7   r   r   <module>r      sl   $   	  	    8D22>><CaE- aE  D+775CDs   !A  A87A8