o
    3'fH                     @   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mZm	Z	m
Z
mZ ddlmZmZ ddlmZ ddlmZ ddlmZ ddlmZ d	d
geg dZeed< dZeeZdZeeZdZdZdZ dZ!e"e#Z$dd Z%dd Z&dd Z'dIddZ(dIddZ)de*de	e* dee*e*f d e+fd!d"Z,dJd#d$Z-d%e*d&e*d dfd'd(Z.dKd)d*Z/d+d, Z0d e
ee* ee*e*f ee* f fd-d.Z1d/ee	ee	e*    dee*e*f d0ee*e*f d1ee	e*  d2ed eee*  fd3d4Z2d/eee*  d eee*  fd5d6Z3d/eee*  d7e*dee*e*f d0ee*e*f d2ed eee*  fd8d9Z4d:eee*  d eee*  fd;d<Z5d:eee*  d dfd=d>Z6d?e+d@e+dAee* d dfdBdCZ7dDe*dEed2edFe8d df
dGdHZ9dS )Lz-Mounts: Configure mount points and swap files    N)DictListOptionalTuplecast)subputil)Cloud)Config)
MetaSchema)PER_INSTANCE	cc_mountsall)iddistros	frequencyactivate_by_schema_keysmetaz&^([x]{0,1}[shv]d[a-z][0-9]*|sr[0-9]+)$z^.+:.*z
/etc/fstabzcomment=cloudconfig   i   @c                 C   s8   | dv rdS dD ]}|  |r| ddkr dS qdS )N)amirootswapT)	ephemeralebs:F)
startswithfind)name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_numberpotential_suffixessuffixpotential_partition_devicer    r    r!   _get_nth_partition_for_deviceA   s   r/   c                 C   sX   t j| dd }t jd|}|d ur&t j|t j|dd }t j|S )N/r   z/sys/block/)r'   r(   realpathsplitjoinr)   )r*   partition_pathdevice_namesys_pathr    r    r!   _is_block_deviceN   s   r7   c                 C   s  t d|  | }|dkrd}t d t| r| S t|\}}|}|r5|||}||kr5t d|| t|rS||}|sAd S |dsKd|f }t d|| n
t	| r]d|f }d }|d u rit
|d	}nt
||}|d u rtd S t||r|d u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 %sr0   z/dev/%szMapped metadata name %s to %s   )LOGdebugr%   r   expand_dotted_devnamegetr"   r   DEVICE_NAME_REr$   r/   r7   )	startnametransformeraliasesdevnamer*   r+   origr4   r    r    r!   sanitize_devnameX   sF   





rD   original	sanitized
fstab_devsreturnc                 C   sP   || krt d| | |du rt d|  dS ||v r&t d|||  dS dS )z*Get if the sanitized device name is valid.zchanged %s => %sNz+Ignoring nonexistent default named mount %sFz&Device %s already defined in fstab: %sT)r:   r;   )rE   rF   rG   r    r    r!   sanitized_devname_is_valid   s   rI   c              	   C   s`  | d u r
t  d } | d }d|| d}|d u r|d u r|}n2|rKt|}|j|j }||d< |d u r>tt|d |}n||d krJt|d }n|d u rQ|}||d< | dt k r^| }n| d	t k ridt }nt	t
| t t }t||}||d
< i }	| D ]\}
}t|trd|t  |	|
< q||	|
< qtd|	d
 |	d |	d |	d |	d  |S )Ntotal   na)availmax_inmemrM      g?max   sizez%s MBzCsuggest %s swap for %s memory with '%s' disk given max=%s [max=%s]'rO   rN   )r   read_meminfor'   statvfsf_frsizef_bfreeminintGBroundmathsqrtitems
isinstanceMBr:   r;   )memsizemaxsizefsyssugg_maxinforU   rM   minsizerS   pinfokvr    r    r!   suggested_swapsize   sN   




rj   fnamerS   c                    s  d  fdd}t j| }t| t|d dkr0tddd| g td	d
| g dkrAt dk rA|| |d nz|| |d W n tjy^   t	
d || |d Y nw t j| rkt| d z
td| g W dS  tjy   t|   w )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r%ddd|  dd	| g}ntd
z
tj|dd W d S  tjyP } zt  | ||| t|   d }~ww )Nz3Creating swapfile in '%s' on fstype '%s' using '%s'	fallocatez-lz%sMddzif=/dev/zerozof=%szbs=1Mzcount=%sz:Missing dependency: 'dd' and 'fallocate' are not availableT)capture)r:   r;   r   ProcessExecutionErrorre   r   del_file)rk   rS   methodcmdeerrmsgfstyper    r!   create_swap   s4   
z$create_swapfile.<locals>.create_swapr9   btrfstruncatez-s0chattrz+Cxfs)rP      rm   rl   z4fallocate swap creation failed, will attempt with ddi  mkswapN)r'   r(   dirnamer   
ensure_dirget_mount_infor   kernel_versionro   r:   re   r)   chmodrp   )rk   rS   rw   swap_dirr    rt   r!   create_swapfile   s0   


r   c                 C   s   t j| }t| dkr2zt d }W n ty%   t	d Y dS w t
| t|||d}tt|d }|sCt	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
    autorJ   z)Not creating swap: failed to read meminfoN)rc   rb   ra   r   z'Not creating swap: suggested size was 0zSetting up swap file)msgfuncargs)r'   r(   r   r&   lowerr   rT   IOErrorr:   r;   r   rj   rY   log_timer   )rk   rS   rb   r   ra   mibsizer    r    r!   setup_swapfile  s.   


r   c              
   C   sZ  t | tstd dS | dd}| dd}| dd}|r"|s)td dS tj|rstjd	s=td
| |S z$t	
d	 D ]}||d rYtd| |  W S qEtd| W n tyr   td| | Y S w z t |tr|dkrt	|}t |trt	|}t|||dW S  ty } ztd| W Y d}~dS d}~ww )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.imgrS   r   rb   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/swapsr   )rk   rS   rb   zfailed to setup swap: %s)r_   dictr:   warningr=   r;   r'   r(   r)   r   load_text_file
splitlinesr   	Exceptionr&   human2bytesr   )swapcfgrk   rS   rb   liners   r    r    r!   handle_swapcfg5  sP   






r   c                  C   sl   g } i }g }t jtr1tt D ]}t|v r|| q|	 }|r0|||d < | | q| ||fS )as  Parse /etc/fstab.

    Parse fstab, ignoring any lines containing "comment=cloudconfig".
    :return: A 3-tuple containing:
        - A list of lines exactly as they appear in fstab
        - A dictionary with key being the first token in the line
          and value being the entire line
        - A list of any lines that were ignored due to "comment=cloudconfig"
    r   )
r'   r(   r)   
FSTAB_PATHr   r   r   MNT_COMMENTappendr2   )fstab_linesrG   fstab_removedr   toksr    r    r!   parse_fstabe  s   



r   mountsdevice_aliasesdefault_fieldscloudc                 C   s   g }| D ]Y}t |tstd| qt|d }t||j|d}t|||r0|g|dd  }	n|}	t|	D ]\}
}|du rE||
 |	|
< q6t|	|
 |	|
< q6|	|t	|	d 7 }	|
|	 q|S )a  Sanitize mounts to ensure we can work with devices in config.

    Specifically:
     - Ensure the mounts configuration is a list of lists
     - Transform and sanitize device names
     - Ensure all tokens are strings
     - Add default options to any lines without options
    z%Mount option not a list, ignoring: %sr   rA   r9   N)r_   listr:   r   r&   rD   device_name_to_devicerI   	enumeratelenr   )r   rG   r   r   r   updated_linesr   startsanitized_devnameupdated_lineindextokenr    r    r!   sanitize_mounts_configuration  s&   
r   c                 C   sl   g }g }| ddd D ]#}|d du s|d |v r)t d|d  ||d  q|| q|ddd S )zRemove any entries that have a device name that doesn't exist.

    If the second field of a mount line is None (not the string, the value),
    we skip it along with any other entries that came before it that share
    the same device name.
    Nr   r9   r   z$Skipping nonexistent device named %s)r:   r;   r   )r   actlistdev_denylistr   r    r    r!   remove_nonexistent_devices  s   r   default_mount_optionsc           	         s   t | }ddd|ddgg dfD ]5  d }t||j|d}t|||s&qtt| d< t fd	d
| D }|rAt	d| q|
  q|S )zAdd default mounts to the user provided mount configuration.

    Add them only if no other entry has the same device name
    r8   z/mntr   rz   2)r   noner   swrz   rz   r   r   c                 3   s     | ]}|d   d  kV  qdS )r   Nr    ).0cfgmdefault_mountr    r!   	<genexpr>  s    
z,add_default_mounts_to_cfg.<locals>.<genexpr>z-Not including %s, already previously included)copydeepcopyrD   r   rI   r   r&   anyr:   r;   r   )	r   r   rG   r   r   
new_mountsr   rF   default_already_existsr    r   r!   add_default_mounts_to_cfg  s&   
r   r   c                 C   s   dd | D S )z=Add "comment=cloudconfig" to the mount options of each entry.c                 S   s8   g | ]}|d d |d  dt  g |dd   qS )N   ,rP   )r   r   entryr    r    r!   
<listcomp>  s    *zadd_comment.<locals>.<listcomp>r    r   r    r    r!   add_comment  s   r   c                 C   s(   t dd | D rtddg dS dS )z1Call 'swapon -a' if any entry has a swap fs type.c                 s   s    | ]	}|d  dkV  qdS )rK   r   Nr    r   r    r    r!   r     s    z*activate_swap_if_needed.<locals>.<genexpr>swapon-aN)r   r   r   r    r    r!   activate_swap_if_needed  s   r   uses_systemdchanges_madedirsc                 C   sf   d}|rd}ndd t   D }tt||}|r/tddg | r1tddg d	S d	S d	S )
zCall 'mount -a' if needed.

    If changes were made, always call 'mount -a'. Otherwise, call 'mount -a'
    if any of the directories in the mount list are not already mounted.
    FTc                 S   s   h | ]
}d |v r|d  qS )
mountpointr    )r   valr    r    r!   	<setcomp>  s
    z"mount_if_needed.<locals>.<setcomp>mountr   	systemctlzdaemon-reloadN)r   r   valuesboolset
differencer   )r   r   r   do_mountmount_pointsr    r    r!   mount_if_needed  s   
r   r   cfgr   c              	      s  |j  }|r	dnd}ddd|ddg}|d|}|dg }td	| t \}	}
}|d
i }t||
|||}t|||
||}t|}t	|}t
|di }|r^||dddddg t|dkrktd dS dd |D }dd |D }|D ]}zt| W q{ ty   ttd| Y q{w dd |D  dd |D  fddD fdd D  }|	| dd|	 }tt| |rtd| ntd t| t|t|| dS )z Handle the mounts configuration.z:defaults,nofail,x-systemd.after=cloud-init.service,_netdevzdefaults,nobootwaitNr   rz   r   mount_default_fieldsr   zmounts configuration is %sr   r   r   r   r   z No modifications to fstab neededc                 S   s   g | ]}d  |qS )	)r3   r   r    r    r!   r   5  s    zhandle.<locals>.<listcomp>c                 S   s"   g | ]}|d   dr|d  qS )r9   r0   )r   )r   dr    r    r!   r   7  s   " z Failed to make '%s' config-mountc                 S      g | ]}| d dqS r   r   replacer   nr    r    r!   r   ?      c                 S   r   r   r   r   r    r    r!   r   @  r   c                       g | ]}| vrd | qS )z- r    )r   drop)saddsr    r!   r   B  s    c                    r   )z+ r    )r   add)sdropsr    r!   r   B  s    z%s

zChanges to fstab: %szNo changes to /etc/fstab made.)distror   r=   r:   r;   r   r   r   r   r   r   r   r   r   r   r   logexcextendr3   
write_filer   r   r   r   )r   r   r   r   r   r   hardcoded_defaultsr   r   r   rG   r   r   updated_cfgswapfile	cfg_linesr   r   sopscontentsr    )r   r   r!   handle  s`   





r   )N)NNN)NN):__doc__r   loggingr\   r'   retypingr   r   r   r   r   	cloudinitr   r   cloudinit.cloudr	   cloudinit.configr
   cloudinit.config.schemar   cloudinit.settingsr   r   __annotations__DEVICE_NAME_FILTERcompiler>   NETWORK_NAME_FILTERr#   r   r   r`   rZ   	getLogger__name__r:   r"   r%   r/   r7   rD   r&   r   rI   rj   r   r   r   r   r   r   r   r   r   r   r   r   r    r    r    r!   <module>   s   





1


9
>"(0




".




"$
"