U
    Ӈgda                     @   s   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
mZmZmZmZ d dlmZ d dlmZmZ e eZdZG dd	 d	e
jZdS )
    N)datetime)AnyDictOptional)distroshelpers	lifecyclesubputil)HostnameConf)
PER_ALWAYSPER_INSTANCEa7  # This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}

c                       sb  e Zd ZdZdZdZdZdZdeediZ	dZ
d	Zd
d Zdd ZdDddZejdddZdd Zdd Zdd ZdEddZdd Zeeeeddd Zd!d" ZdFd#d$Zd%d&d'd(Zed)d* Zed+ fd,d-Z fd.d/Z ed0 fd1d2Z! fd3d4Z"dG fd5d6	Z#dHd9d:Z$e%d;d< Z&e'dd=eeed>d?d@Z(e%ee)e dAdBdCZ*  Z+S )IDistrozpy3-pipz/usr/share/bkeymaps/z&/etc/profile.d/50-cloud-init-locale.shz/etc/network/interfacesz/etc/shadowZeni)Zeni_pathZ
eni_headerz/var/lib/dhcpzdhclient\.leasesc                 C   s6   t j| ||| t|| _d| _d| _d|d< d S )NzC.UTF-8ZalpineZsshdZssh_svcname)r   r   __init__r   ZRunners_runnerdefault_localeZosfamily)selfnameZcfgpaths r   :/usr/lib/python3/dist-packages/cloudinit/distros/alpine.pyr   .   s
    zDistro.__init__c                 C   s   | j S )zgThe default locale for Alpine Linux is different than
        cloud-init's DataSource default.
        )r   r   r   r   r   
get_locale8   s    zDistro.get_localeNc                 C   sB   |s
| j }|s| j}ddddd| ddg}t|d|d d S )	N#z?# This file is created by cloud-init once per new instance bootzexport CHARSET=UTF-8zexport LANG=%szexport LC_COLLATE=C 
  )r   locale_conf_fnr
   
write_filejoin)r   ZlocaleZout_fnlinesr   r   r   apply_locale>   s    	zDistro.apply_locale)pkglistc                 C   s   |    | jd|d d S )Nadd)pkgs)update_package_sourcespackage_command)r   r"   r   r   r   install_packagesQ   s    zDistro.install_packagesc                 C   sz   d }z|  |}W n: tk
rL   t| jdd}|r8ntd Y d S Y nX |sZtd}|| t	|t
|d d S )Ncreate_hostname_fileTz8create_hostname_file is False; hostname file not createdr   r   )_read_hostname_confIOErrorr
   Zget_cfg_option_boolZ_cfgLOGinfor   Zset_hostnamer   str)r   hostnamefilenameconfr(   r   r   r   _write_hostnameU   s&      
zDistro._write_hostnamec                 C   s   |  | j}| j|fS N)_read_hostnameZhostname_conf_fn)r   Zsys_hostnamer   r   r   _read_system_hostnamek   s    zDistro._read_system_hostnamec                 C   s   t t|}|  |S r2   )r   r
   load_text_fileparse)r   r/   r0   r   r   r   r)   o   s    zDistro._read_hostname_confc                 C   s:   d }z|  |}|j}W n tk
r,   Y nX |s6|S |S r2   )r)   r.   r*   )r   r/   defaultr.   r0   r   r   r   r3   t   s    

zDistro._read_hostnamec                 C   s   dS )Nz	127.0.1.1r   r   r   r   r   _get_localhost_ip   s    zDistro._get_localhost_ip)layoutmodelvariantoptionsc                 C   s   |sd}t | t|tj| j|}tj|sPd| }t | t||sjd}t | t|tj|d| }tj|sd| }t | t||rt 	d |rt 	d t

d||g d S )	NzKeyboard layout not specified.z,Keyboard layout directory %s does not exist.zKeyboard variant not specified.z
%s.bmap.gzz(Keyboard variant file %s does not exist.z+Keyboard model is ignored for Alpine Linux.z.Keyboard options are ignored for Alpine Linux.zsetup-keymap)r+   errorRuntimeErrorospathr   keymap_pathisdirisfilewarningr	   )r   r9   r:   r;   r<   msgZkeymap_layout_pathZkeymap_variant_pathr   r   r   
set_keymap   s@    


 


zDistro.set_keymapc                 C   s   t j|| |d d S )N)tzZtz_file)r   Zset_etc_timezoneZ_find_tz_file)r   rG   r   r   r   set_timezone   s    zDistro.set_timezonec                 C   s   |d krg }dg}| d |r6t|tr6| | n|rNt|trN|| |r\| | |dkrr|ddg td|}|| tj|dd d S )	NZapkz--quietZupgradez--update-cachez--availablez%s-%sF)capture)append
isinstancer-   listextendr
   Zexpand_package_listr	   )r   commandargsr$   cmdr"   r   r   r   r&      s    



zDistro.package_commandF)forcec                C   s$   | j jd| jdg|rtntd d S )Nzupdate-sourcesupdate)Zfreq)r   runr&   r   r   )r   rQ   r   r   r   r%      s    
zDistro.update_package_sourcesc                 C   s   | j sddg| _ | j S )z7Allow distro to determine the preferred ntp client listZchronyZntp)Z_preferred_ntp_clientsr   r   r   r   preferred_ntp_clients   s    
zDistro.preferred_ntp_clients)returnc                    s  t |rtd| dS d|kr2td |d= tdrLt j|f|S |	dd}dd	g}d
ddddd}ddi}|
d}|rt|tr|d}n"t|trtjd| dddd dd |D }d||d< |
dr||d  |r.|r.|D ]*}t |s| | td|| qd|krHt|d |d< g dddd}	t| D ]\}
}|
|kr|rt|tr|||
 |g n^|
|	kr|rt|tr|
dkr|d|	|
< n||	|
< n|
|krb|rb|||
  qb|
d s|
dr|d! || td"| zt| W n6 tjk
rx } ztd#| |W 5 d}~X Y nX |	d D ]b}td$| ztd%||g W n: tjk
r } zt td&|| |W 5 d}~X Y nX q|	d' rt j||	d' dd( |	d) }|	d* }d}| j}zt |}W n4 tk
rb } ztd+| |W 5 d}~X Y nX d}| D ](}|d,}|d- |krp|} qqp|rd.}d.|d/< d.|d0< d.|d1< d2}|dk	rt !|t !d3 j"}t||d4< |d.kr|d5 }|d6 }|dk	r2||d7< |d.kr*|d5 }|d8 }|#|d,|}td9|| zt j$||d:dd; W n6 t%k
r } zt td<| |W 5 d}~X Y nX nt td=|| dS )>z
        Add a user to the system using standard tools

        On Alpine this may use either 'useradd' or 'adduser' depending
        on whether the 'shadow' package is installed.

        Returns False if user already exists, otherwise True.
        z!User %s already exists, skipping.FZselinux_userz0Ignoring selinux_user parameter for Alpine LinuxZuseraddcreate_groupsTZadduserz-Dz-gz-hz-Gz-s-u)ZgecosZhomedirprimary_groupshelluidsystemz-Sgroups,z	The user z) has a 'groups' config value of type dictz22.3z=Use a comma-delimited string or array instead: group1,group2.)Z
deprecatedZdeprecated_versionZextra_messagec                 S   s   g | ]}|  qS r   )strip).0gr   r   r   
<listcomp>  s     z#Distro.add_user.<locals>.<listcomp>rX   z created group '%s' for user '%s'rZ   N)r\   
expiredateinactivepasswdZno_create_homez-HzAdding user %szFailed to create user %szAdding user to group %saddgroupz!Failed to add user %s to group %srd   )Zhashedrb   rc   &Failed to read %s file, file not found:r   r            zpassword agingz
1970-01-01   z & zacct expiration date   zinactivity periodzUpdating %s for user %swZomodeZpreserve_modeFailed to update %s filezFailed to update %s for user %s)&r
   is_userr+   r,   rD   r	   whichsuperadd_userpopgetrK   r-   splitdictr   Z	deprecater   rJ   is_groupcreate_groupdebugsorteditemsrM   ProcessExecutionErrorlogexcZ
set_passwd	shadow_fnr5   FileNotFoundError
splitlinesr   Zfromisoformatdaysreplacer   r*   )r   r   kwargsrV   Zadduser_cmdZadduser_optsZadduser_flagsr\   groupZunsupported_busybox_valueskeyvaleZ
addn_grouprb   rc   shadow_contentsshadow_fileoriginal_linelinenew_line_partsZupdate_typer   	__class__r   r   rs      s   	














   
  





    
   zDistro.add_userc              
      s   t jdrdt dkr&t |S dd|g}z,tj|ddgd\}}td|rZW d	S W n6 tj	k
r } zt
td
| |W 5 d}~X Y nX dS )zL
        Lock the password of a user, i.e., disable password logins
        /usr/bin/passwdbbsuidrd   z-lr      rcszis already lockedTz&Failed to disable password for user %sN)r?   r@   islinkreadlinkrr   lock_passwdr	   researchr}   r
   r~   r+   )r   r   rP   Z_outerrr   r   r   r   r     s    

zDistro.lock_passwd)r   c              
      s   t jdrdt dkr&t |S dd|g}z,tj|ddgd\}}td|rZW d	S W n6 tj	k
r } zt
td
| |W 5 d}~X Y nX dS )zM
        Unlock the password of a user, i.e., enable password logins
        r   r   rd   rW   r   r   r   zis already unlockedTz%Failed to unlock password for user %sN)r?   r@   r   r   rr   unlock_passwdr	   r   r   r}   r
   r~   r+   )r   r   rP   _r   r   r   r   r   r     s    
	
zDistro.unlock_passwdc              
      sZ  t jdrdt dkr&t |S d }| j}zt|}W n2 t	k
rp } zt
d| |W 5 d }~X Y nX d }| D ].}|d}|d |kr~t
d| |} qq~|rH|d dkr:d|d< ||d|d	}t
d
| ztj||ddd W n6 tk
r6 } ztt
d| |W 5 d }~X Y nX nt
d| ntt
d| d S )Nr   r   rf   rg   r   z'Found /etc/shadow line matching user %s   0r   zExpiring password for user %srm   Trn   ro   z'Password for user %s is already expiredzFailed to set 'expire' for %s)r?   r@   r   r   rr   expire_passwdr   r
   r5   r   r+   rD   r   rv   rz   r   r   r   r*   r~   )r   userr   r   r   r   r   r   r   r   r   r     sR    
  
zDistro.expire_passwdc                    s   t drt ||S d|g}|s(g }t|r@td| n@zt  | td| W n$ t j	k
r~   t
td| Y nX t|dkr|D ]<}t|std|| qt  d||g td|| qd S )	NZgroupaddre   z(Skipping creation of existing group '%s'zCreated new group %szFailed to create group %sr   zCUnable to add group member '%s' to group '%s'; user does not exist.zAdded user '%s' to group '%s')r	   rq   rr   ry   r
   rx   r+   rD   r,   r}   r~   lenrp   )r   r   membersZgroup_add_cmdmemberr   r   r   ry     s.    



zDistro.create_grouppoweroffnowc              
   C   sn   |dg}|dkr|dg7 }nNz| tt|d  W n2 tk
rh } ztd|f |W 5 d }~X Y nX |S )Nz-dr   r   <   z?power_state[delay] must be 'now' or '+m' (minutes). found '%s'.)rJ   r-   int
ValueError	TypeError)r   modeZdelaymessagerN   r   r   r   r   shutdown_command@  s    zDistro.shutdown_commandc                   C   s   dS )z1
        Alpine uses OpenRC, not systemd
        Fr   r   r   r   r   uses_systemdZ  s    zDistro.uses_systemdr   )actionservice
extra_argsc          	   
   G   s   ddg}ddg}t ||dg t ||dg t |d|g t |d|g t ||dg t ||dg t ||dg t ||d	g d
}t || }tj|d|dS )a<  
        Perform the requested action on a service. This handles OpenRC
        specific implementation details.

        OpenRC has two distinct commands relating to services,
        'rc-service' and 'rc-update' and the order of their argument
        lists differ.
        May raise ProcessExecutionError
        z
rc-servicez	--nocolorz	rc-updatestopstartdelr#   restartstatus)r   r   disableenabler   reloadz
try-reloadr   T)rI   r   )rL   r	   )	r   r   r   r   r   Zinit_cmdZ
update_cmdZcmdsrP   r   r   r   manage_servicea  s    
zDistro.manage_service)blockdevrU   c              	   C   s   t j| }| drt t | j}t t | j}t dv}|D ]j}|j	drJt 
|j}t|jrJt t |jj|krJt t |jj|krJt j|j} qqJW 5 Q R X |drtd| | |S dS )a  Returns underlying block device for a mapped device.

        If it is mapped, blockdev will usually take the form of
        /dev/mapper/some_name

        If blockdev is a symlink pointing to a /dev/dm-* device, return
        the device pointed to. Otherwise, return None.
        z/dev/mapperz/dev/zdm-z/dev/dm-z$%s is a mapped device pointing to %sN)r?   r@   realpath
startswithmajorstatst_rdevminorscandirr   lstatS_ISBLKst_moder+   rz   )r   r   r   r   itZdeventryresr   r   r   get_mapped_device}  s6    


  zDistro.get_mapped_device)N)N)NN)N)r   r   N),__name__
__module____qualname__Zpip_package_namerA   r   Znetwork_conf_fnr   NETWORK_FILE_HEADERZrenderer_configsZdhclient_lease_directoryZdhclient_lease_file_regexr   r   r!   r   ZPackageListr'   r1   r4   r)   r3   r8   r-   rF   rH   r&   r%   propertyrT   boolrs   r   r   r   ry   r   staticmethodr   classmethodr   r   r   __classcell__r   r   r   r   r       sV    


"

 [9#

  r   )Zloggingr?   r   r   r   typingr   r   r   Z	cloudinitr   r   r   r	   r
   Z"cloudinit.distros.parsers.hostnamer   Zcloudinit.settingsr   r   Z	getLoggerr   r+   r   r   r   r   r   r   <module>	   s   

