U
    L¬÷dñN  ã                	   @   s~  U d 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
mZmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ d
ZedƒZdgZdddeeeedƒgeg dœZeed< eeƒZ dZe e¡ZdZe e¡Ze de ¡Z dZ!dZ"dZ#dZ$e %e&¡Z'dd„ Z(dd„ Z)dd„ Z*d0d d!„Z+d1d"d#„Z,d2d$d%„Z-e.e.dd&œd'd(„Z/d3d)d*„Z0d+d,„ Z1e.eee2dd-œd.d/„Z3dS )4z-Mounts: Configure mount points and swap filesé    N)Ú
whitespace)Údedent)ÚsubpÚ
type_utilsÚutil)ÚCloud)ÚConfig)Ú
MetaSchemaÚget_meta_doc)ÚPER_INSTANCEaÐ	  This module can add or remove mountpoints from ``/etc/fstab`` as well as
configure swap. The ``mounts`` config key takes a list of fstab entries to add.
Each entry is specified as a list of ``[ fs_spec, fs_file, fs_vfstype,
fs_mntops, fs-freq, fs_passno ]``. For more information on these options,
consult the manual for ``/etc/fstab``. When specifying the ``fs_spec``, if the
device name starts with one of ``xvd``, ``sd``, ``hd``, or ``vd``, the leading
``/dev`` may be omitted.

Any mounts that do not appear to either an attached block device or network
resource will be skipped with a log like "Ignoring nonexistent mount ...".

Cloud-init will attempt to add the following mount directives if available and
unconfigured in `/etc/fstab`::

    mounts:
        - ["ephemeral0", "/mnt", "auto","defaults,nofail,x-systemd.requires=cloud-init.service", "0", "2"]
        - ["swap", "none", "swap", "sw", "0", "0"]

In order to remove a previously listed mount, an entry can be added to
the `mounts` list containing ``fs_spec`` for the device to be removed but no
mountpoint (i.e. ``[ swap ]`` or ``[ swap, null ]``).

The ``mount_default_fields`` config key allows default values to be specified
for the fields in a ``mounts`` entry that are not specified, aside from the
``fs_spec`` and the ``fs_file`` fields. If specified, this must be a list
containing 6 values. It defaults to::

    mount_default_fields: [none, none, "auto","defaults,nofail,x-systemd.requires=cloud-init.service", "0", "2"]

Non-systemd init systems will vary in ``mount_default_fields``.

Swap files can be configured by setting the path to the swap file to create
with ``filename``, the size of the swap file with ``size`` maximum size of
the swap file if using an ``size: auto`` with ``maxsize``. By default no
swap file is created.

.. note::
    If multiple mounts are specified where a subsequent mount's mountpoint is
    inside of a previously declared mount's mountpoint (i.e. the 1st mount has
    a mountpoint of ``/abc`` and the 2nd mount has a mountpoint of
    ``/abc/def``) then this will not work as expected - ``cc_mounts`` first
    creates the directories for all the mountpoints **before** it starts to
    perform any mounts and so the sub-mountpoint directory will not be created
    correctly inside the parent mountpoint.

    For systems using util-linux's ``mount`` program this issue can be
    worked around by specifying ``X-mount.mkdir`` as part of a ``fs_mntops``
    value for the subsequent mount entry.
a<      # Mount ephemeral0 with "noexec" flag, /dev/sdc with mount_default_fields,
    # and /dev/xvdh with custom fs_passno "0" to avoid fsck on the mount.
    # Also provide an automatically sized swap with a max size of 10485760
    # bytes.
    mounts:
        - [ /dev/ephemeral0, /mnt, auto, "defaults,noexec" ]
        - [ sdc, /opt/data ]
        - [ xvdh, /opt/data, auto, "defaults,nofail", "0", "0" ]
    mount_default_fields: [None, None, auto, "defaults,nofail", "0", "2"]
    swap:
        filename: /my/swapfile
        size: auto
        maxsize: 10485760
    ÚallZ	cc_mountsZMountsz%Configure mount points and swap filesz®        # Create a 2 GB swap file at /swapfile using human-readable values
        swap:
            filename: /swapfile
            size: 2G
            maxsize: 2G
        )ÚidÚnameÚtitleZdescriptionÚdistrosZexamplesZ	frequencyZactivate_by_schema_keysÚmetaz&^([x]{0,1}[shv]d[a-z][0-9]*|sr[0-9]+)$z^.+:.*z[%s]+z
/etc/fstabzcomment=cloudconfigé   i   @c                 C   s8   | dkrdS dD ]"}|   |¡r|  d¡dkr dS qdS )N)ZamiÚrootÚswapT)Ú	ephemeralZebsú:éÿÿÿÿF)Ú
startswithÚfind)r   Zenumname© r   ú</usr/lib/python3/dist-packages/cloudinit/config/cc_mounts.pyÚis_meta_device_nameˆ   s    r   c                 C   s   t  | ¡rdS dS )NTF)ÚNETWORK_NAME_REÚmatch)r   r   r   r   Úis_network_device”   s    
r   c                 C   sH   t |ƒd|f d|f g}|D ]$}d| |f }tj |¡r|  S qd S )Nzp%sz-part%sz%s%s)ÚstrÚosÚpathÚexists)Údevice_pathÚpartition_numberZpotential_suffixesÚsuffixZpotential_partition_devicer   r   r   Ú_get_nth_partition_for_device›   s    ý
r'   c                 C   sX   t j | ¡ d¡d }t j d|¡}|d k	rLt j |t j |¡ d¡d ¡}t j |¡S )Nú/r   z/sys/block/)r!   r"   ÚrealpathÚsplitÚjoinr#   )r$   Úpartition_pathZdevice_nameZsys_pathr   r   r   Ú_is_block_device¨   s     ÿr-   c                 C   s
  t  d| ¡ | }|dkr&d}t  d¡ t| ƒr2| S t |¡\}}|}|rj| ||¡}||krjt  d||¡ t|ƒr¦||ƒ}|s‚d S | d¡s–d|f }t  d||¡ nt 	| ¡rºd|f }d }|d krÒt
|d	ƒ}nt
||ƒ}|d krèd S t||ƒr|d k	r|S |S d S )
Nz+Attempting to determine the real name of %sr   Ú
ephemeral0z2Adjusted mount option from ephemeral to ephemeral0zMapped device alias %s to %sr(   z/dev/%szMapped metadata name %s to %sé   )ÚLOGÚdebugr   r   Zexpand_dotted_devnameÚgetr   r   ÚDEVICE_NAME_REr   r'   r-   )Z	startnameZtransformerÚaliasesZdevnamer$   r%   Zorigr,   r   r   r   Úsanitize_devname²   sH    




 ÿ
r5   c              	   C   sd  | d krt  ¡ d } | d }d|| dœ}|d kr>|d kr>|}nd|r–t |¡}|j|j }||d< |d kr|tt|d ƒ|ƒ}q¢||d kr¢t|d ƒ}n|d kr¢|}||d< | dt k r¼| }n,| d	t k rÒdt }nt	t
 | t ¡ƒt }t||ƒ}||d
< i }	| ¡ D ]0\}
}t|tƒr,d|t  |	|
< n||	|
< qt d|	d
 |	d |	d |	d |	d ¡ |S )NÚtotalé   Zna)ÚavailÚmax_inÚmemr8   é   gÍÌÌÌÌÌì?Úmaxé   Úsizez%s MBzCsuggest %s swap for %s memory with '%s' disk given max=%s [max=%s]'r:   r9   )r   Úread_meminfor!   ÚstatvfsÚf_frsizeÚf_bfreeÚminÚintÚGBÚroundÚmathZsqrtÚitemsÚ
isinstanceÚMBr0   r1   )ÚmemsizeÚmaxsizeÚfsysZsugg_maxÚinfor@   r8   Zminsizer>   ZpinfoÚkÚvr   r   r   Úsuggested_swapsizeã   sL    


úrQ   )Úfnamer>   Úreturnc                    s  d‰ ‡ ‡fdd„}t j | ¡}t |¡ t |¡d ‰ˆdkr`t ddd| g¡ t d	d
| g¡ ˆdkr‚t ¡ dk r‚|| |dƒ n>z|| |dƒ W n, tjk
r¾   t	 
d¡ || |dƒ Y nX t j | ¡rØt | d¡ zt d| g¡ W n$ tjk
r   t | ¡ ‚ Y nX dS )zSize is in MiB.z6Failed to create swapfile '%s' of size %sMB via %s: %sc              
      s¢   t  d| ˆ|¡ |dkr*ddd| | g}n|dkrHddd|  dd	| g}ztj|d
d W nB tjk
rœ } z"t  ˆ | |||¡ t | ¡ ‚ W 5 d }~X Y nX d S )Nz3Creating swapfile in '%s' on fstype '%s' using '%s'Ú	fallocatez-lz%sMÚddzif=/dev/zerozof=%szbs=1Mzcount=%sT)Zcapture)r0   r1   r   ÚProcessExecutionErrorrN   r   Údel_file)rR   r>   ÚmethodÚcmdÚe©ÚerrmsgZfstyper   r   Úcreate_swap!  s*    üû
z$create_swapfile.<locals>.create_swapr/   ZbtrfsÚtruncatez-sÚ0Zchattrz+CZxfs)r;   é   rU   rT   z4fallocate swap creation failed, will attempt with ddi€  ZmkswapN)r!   r"   Údirnamer   Ú
ensure_dirZget_mount_infor   Zkernel_versionrV   r0   rN   r#   ÚchmodrW   )rR   r>   r]   Úswap_dirr   r[   r   Úcreate_swapfile  s,    


re   c                 C   s¤   t j | ¡}t|ƒ ¡ dkrfzt ¡ d }W n  tk
rL   t 	d¡ Y dS X t 
|¡ t|||d}tt|d ƒƒ}|sˆt 	d¡ dS tjtj	dt| |gd	 | S )
z
    fname: full path string of filename to setup
    size: the size to create. set to "auto" for recommended
    maxsize: the maximum size
    Úautor6   z)Not creating swap: failed to read meminfoN)rM   rL   rK   r   z'Not creating swap: suggested size was 0zSetting up swap file)ÚmsgÚfuncÚargs)r!   r"   ra   r    Úlowerr   r?   ÚIOErrorr0   r1   rb   rQ   rD   Zlog_timere   )rR   r>   rL   rd   rK   Zmibsizer   r   r   Úsetup_swapfileV  s0    

  ÿ
ürl   c              
   C   sd  t | tƒst d¡ dS |  dd¡}|  dd¡}|  dd¡}|rD|sRt d¡ dS tj |¡rètj d	¡szt d
|¡ |S zHt	 
d	¡ ¡ D ](}| |d ¡rŠt d|¡ |  W S qŠt d|¡ W n$ tk
ræ   t d|¡ | Y S X zFt |tƒr
|dkr
t	 |¡}t |tƒr t	 |¡}t|||dW S  tk
r^ } zt d|¡ W 5 d}~X Y nX dS )zahandle the swap config, calling setup_swap if necessary.
    return None or (filename, size)
    z%input for swap config was not a dict.NÚfilenamez	/swap.imgr>   r   rL   zno need to setup swapz/proc/swapsz:swap file %s exists, but no /proc/swaps exists, being safeú zswap file %s already in usez+swap file %s exists, but not in /proc/swapsz.swap file %s exists. Error reading /proc/swapsrf   )rR   r>   rL   zfailed to setup swap: %s)rI   Údictr0   Úwarningr2   r1   r!   r"   r#   r   Ú	load_fileÚ
splitlinesr   Ú	Exceptionr    Zhuman2bytesrl   )ZswapcfgrR   r>   rL   ÚlinerZ   r   r   r   Úhandle_swapcfgx  sJ    


þ ÿ


ru   )r   ÚcfgÚcloudri   rS   c           $   	      s&  d}|j  ¡ }|rd}d d d|ddg}| d|¡}ddd|d	 ddgd
dd
dddgg}g }d|krj|d }t d|¡ g }	i }
g }tj t¡rðt	 
t¡ ¡ D ]R}t|kr´| |¡ qœzt |¡}W n tk
rÖ   Y nX ||
|d < |	 |¡ qœ| di ¡}tt|ƒƒD ]þ}t|| tƒs<t d|d t || ¡¡ qt|| d ƒ}t||j|d}||krtt d||¡ |d krt d|¡ qn ||
kr°t d||
| ¡ q||| d< tt|| ƒƒD ]6}|| | d krèqÌnt|| | ƒ|| |< qÌqtt|ƒƒD ]ª}tt|ƒƒD ]N}t|| ƒ|krN||  || ¡ n"|| | d kr$|| || |< q$|| d d krt|ƒD ],}|| d || d krŽd || d< qŽq|D ]Æ}|d }t||j|d}||krøt d||¡ |d krt d|¡ qÄn ||
kr4t d||
| ¡ qÄ||d< d}|D ]"}|d |d krDd} qhqD|r~t d|¡ qÄ| |¡ qÄg }|D ]0}|d d kr¸t d|d ¡ n
| |¡ q”t| d
i ¡ƒ}|rò| |dd
dddg¡ t|ƒdkrt d¡ d S g }d}d}g }|D ]Z}d|d	 tf |d	< |d d
krLd}|d  d ¡rj| |d ¡ | d! |¡¡ q"d"d#„ t	 ¡   ¡ D ƒ}|D ]N}zt	 !|¡ W n$ tk
rÎ   t	 "td$|¡ Y nX |s˜||kr˜d}q˜d%d#„ |D ƒ‰ d&d#„ |D ƒ‰‡ fd'd#„ˆD ƒ‡fd(d#„ˆ D ƒ }|	 #|¡ d)d* |	¡ } t	 $t| ¡ g }!|rd|! d+d,g¡ t|ƒdkr~t d-¡ nt d.|¡ d}|r¶|! d/d,g¡ |r¶|! d0d1g¡ d2}"|!D ]b}#d3d4 |#¡ }"zt% %|#¡ t |"d5¡ W n2 t%j&k
r   t |"d6¡ t	 "t|"d6¡ Y nX q¾d S )7Nzdefaults,nobootwaitz=defaults,nofail,x-systemd.requires=cloud-init.service,_netdevrf   r_   Ú2Zmount_default_fieldsr.   z/mnté   r   ZnoneÚswÚmountszmounts configuration is %sr   Údevice_aliasesz,Mount option %s not a list, got a %s insteadr/   )r4   zchanged %s => %sz#Ignoring nonexistent named mount %sz&Device %s already defined in fstab: %szchanged default device %s => %sz+Ignoring nonexistent default named mount %sFTz-Not including %s, already previously includedz$Skipping nonexistent device named %sz No modifications to fstab neededz%s,%sr7   r(   ú	c                 S   s    g | ]\}}d |kr|d  ‘qS )Z
mountpointr   )Ú.0rO   rP   r   r   r   Ú
<listcomp>I  s     zhandle.<locals>.<listcomp>z Failed to make '%s' config-mountc                 S   s   g | ]}t  d |¡‘qS ©rn   ©ÚWSÚsub©r~   Únr   r   r   r   W  s     c                 S   s   g | ]}t  d |¡‘qS r€   r   r„   r   r   r   r   X  s     c                    s   g | ]}|ˆ krd | ‘qS )z- r   )r~   Zdrop)Úsaddsr   r   r   Z  s      c                    s   g | ]}|ˆ krd | ‘qS )z+ r   )r~   Úadd)Úsdropsr   r   r   Z  s     z%s
Ú
Zswaponz-azNo changes to /etc/fstab made.zChanges to fstab: %sZmountZ	systemctlzdaemon-reloadz#Activating swap and mounts with: %szActivate mounts: %s:rn   ZPASSZFAIL)'ZdistroÚuses_systemdr2   r0   r1   r!   r"   r#   Ú
FSTAB_PATHr   rq   rr   ÚMNT_COMMENTÚappendr‚   r*   rs   ÚrangeÚlenrI   Úlistrp   r   Zobj_namer    r5   Zdevice_name_to_devicerN   ru   r   r+   r{   rH   rb   ZlogexcÚextendZ
write_filer   rV   )$r   rv   rw   ri   Zdef_mnt_optsrŠ   ZdefvalsZdefmntsZcfgmntZfstab_linesZ
fstab_devsZfstab_removedrt   Ztoksr|   ÚiÚstartZ	sanitizedÚjZdefmntZ
cfgmnt_hasZcfgmZactlistÚxZswapretZcc_linesZneedswapZneed_mount_allÚdirsZmount_pointsÚdZsopsÚcontentsZactivate_cmdsZfmtrY   r   )r†   rˆ   r   Úhandle¨  s>   
ÿþ
ý  ÿ


ý   ÿ


ý


ÿÿ

r™   )N)N)NNN)NN)4Ú__doc__ZloggingrG   r!   ÚreÚstringr   Útextwrapr   Z	cloudinitr   r   r   Zcloudinit.cloudr   Zcloudinit.configr   Zcloudinit.config.schemar	   r
   Zcloudinit.settingsr   ZMODULE_DESCRIPTIONZexampler   r   Ú__annotations__ZDEVICE_NAME_FILTERÚcompiler3   ZNETWORK_NAME_FILTERr   r‚   r‹   rŒ   rJ   rE   Z	getLoggerÚ__name__r0   r   r   r'   r-   r5   rQ   r    re   rl   ru   r   r™   r   r   r   r   Ú<module>	   sd   5ÿÿþí





1
9:
"0