
"T`|8                 @   s.  d  Z  d d l Z d d l Z d d l m Z d d l m Z d d l m Z d Z d Z	 d Z
 i  Z d	 Z d
 Z d Z d Z d Z d Z d Z e j e  Z e j d  Z e j d  Z e
 d d d  Z d d   Z d d   Z d d d  Z Gd d   d e  Z d d d d  Z d d    Z  d S)!a  
.. _cc_rsyslog:

Rsyslog
-------
**Summary:** configure system loggig via rsyslog

This module configures remote system logging using rsyslog.

The rsyslog config file to write to can be specified in ``config_filename``,
which defaults to ``20-cloud-config.conf``. The rsyslog config directory to
write config files to may be specified in ``config_dir``, which defaults to
``/etc/rsyslog.d``.

A list of configurations for rsyslog can be specified under the ``configs`` key
in the ``rsyslog`` config. Each entry in ``configs`` is either a string or a
dictionary. Each config entry contains a configuration string and a file to
write it to. For config entries that are a dictionary, ``filename`` sets the
target filename and ``content`` specifies the config string to write. For
config entries that are only a string, the string is used as the config string
to write. If the filename to write the config to is not specified, the value of
the ``config_filename`` key is used. A file with the selected filename will be
written inside the directory specified by ``config_dir``.

The command to use to reload the rsyslog service after the config has been
updated can be specified in ``service_reload_command``. If this is set to
``auto``, then an appropriate command for the distro will be used. This is the
default behavior. To manually set the command, use a list of command args (e.g.
``[systemctl, restart, rsyslog]``).

Configuration for remote servers can be specified in ``configs``, but for
convenience it can be specified as key value pairs in ``remotes``. Each key
is the name for an rsyslog remote entry. Each value holds the contents of the
remote config for rsyslog. The config consists of the following parts:

    - filter for log messages (defaults to ``*.*``)
    - optional leading ``@`` or ``@@``, indicating udp and tcp respectively
      (defaults to ``@``, for udp)
    - ipv4 or ipv6 hostname or address. ipv6 addresses must be in ``[::1]``
      format, (e.g. ``@[fd00::1]:514``)
    - optional port number (defaults to ``514``)

This module will provide sane defaults for any part of the remote entry that is
not specified, so in most cases remote hosts can be specified just using
``<name>: <address>``.

For backwards compatibility, this module still supports legacy names for the
config entries. Legacy to new mappings are as follows:

    - ``rsyslog`` -> ``rsyslog/configs``
    - ``rsyslog_filename`` -> ``rsyslog/config_filename``
    - ``rsyslog_dir`` -> ``rsyslog/config_dir``

.. note::
    The legacy config format does not support specifying
    ``service_reload_command``.

**Internal name:** ``cc_rsyslog``

**Module frequency:** per instance

**Supported distros:** all

**Config keys**::

    rsyslog:
        config_dir: config_dir
        config_filename: config_filename
        configs:
            - "*.* @@192.158.1.1"
            - content: "*.*   @@192.0.2.1:10514"
              filename: 01-example.conf
            - content: |
                *.*   @@syslogd.example.com
        remotes:
            maas: "192.168.1.1"
            juju: "10.0.4.1"
        service_reload_command: [your, syslog, restart, command]

**Legacy config keys**::

    rsyslog:
        - "*.* @@192.158.1.1"
    rsyslog_dir: /etc/rsyslog-config.d/
    rsyslog_filename: 99-local.conf
    N)log)subp)utilz20-cloud-config.confz/etc/rsyslog.dZautoconfigsZconfig_filenameZ
config_dirZservice_reload_commandZrsyslog_filenameZrsyslog_dirremotesz[ ]*[#]+[ ]*z_^(?P<proto>[@]{0,2})(([\[](?P<bracket_addr>[^\]]*)[\]])|(?P<addr>[^:]*))([:](?P<port>[0-9]+))?$Fc             C   sY   d } |  t  k r< | r* d d | g } qB d | d g } n |  } t j | d d d  S)NrsyslogZ	systemctlzreload-or-try-restartserviceZrestartZcaptureT)
DEF_RELOADr   )commandsystemdr   cmd r   =/usr/lib/python3/dist-packages/cloudinit/config/cc_rsyslog.pyreload_syslog   s    r   c             C   s  |  j  d i   } t |  j  d  t  rs t |  j  d  i } t |  k rY |  t | t <t |  k rs |  t | t <t g  t f t t t	 f t t
 t	 f t t t	 t f f t t t f f } xA | D]9 \ } } } | | k s t | | |  r | | | <q W| S)Nr   )get
isinstancelistKEYNAME_CONFIGSKEYNAME_LEGACY_FILENAMEKEYNAME_FILENAMEKEYNAME_LEGACY_DIRKEYNAME_DIRDEF_DIRstrDEF_FILENAMEKEYNAME_RELOADr	   KEYNAME_REMOTESDEF_REMOTESdict)cfgmycfgZfillupkeydefaultZvtypesr   r   r   load_config   s      r#   c       
      C   sH  g  } x;t  |   D]-\ } } t | t  rp d | k rQ t j d | d  q | d } | j d |  } n | } | } | j   } | s t j d | d  q t j j	 | |  } d } | | k r d } | j
 |  y9 d }	 | j d	  s d	 }	 t j | | |	 d
 | Wq t k
 r?t j t d |  Yq Xq W| S)Ncontentz%No 'content' entry in config entry %s   filenamezEntry %s has an empty filenameZabwb 
omodezFailed to write to %s)	enumerater   r   LOGwarningr   stripospathjoinappendendswithr   Z
write_file	ExceptionZlogexc)
r   	def_fnamecfg_dirfilesZcur_posZentr$   r&   r*   Zendlr   r   r   apply_rsyslog_changes   s8    	
r8   c             C   s  y% t  j |   \ } } | j   } Wn t k
 rF |  d  } } Yn X| j   j   } d  } t |  d k rz | } n1 t |  d k r | \ } } n t d |   t j |  } | s t d |   | j d  } | j d  p | j d  } | j d  }	 | j d	  r;| j	 d
  r;t d |   | rN| rN| } t
 d | d | d | d | d |	  }
 |
 j   |
 S)Nr%      zline had multiple spaces: %szInvalid host specification '%s'protoaddrZbracket_addrport[]z"host spec had invalid brackets: %snamematch)
COMMENT_REsplitr.   
ValueErrorlenHOST_PORT_REr@   group
startswithr3   SyslogRemotesLinevalidate)liner?   dataZcommentZtoksr@   Z	host_portr:   r;   r<   tr   r   r   parse_remotes_line   s4    	
rM   c               @   sO   e  Z d  Z d d d d d d d  Z d d   Z d d   Z d d	   Z d S)
rH   Nc             C   s   | s d } | |  _  | |  _ | s* d } | d k r? d } n | d k rQ d } | |  _ | |  _ | r{ t |  |  _ n	 d  |  _ d  S)Nz*.*udp@z@@tcp)r?   r@   r:   r;   intr<   )selfr?   r@   r:   r;   r<   r   r   r   __init__F  s    					zSyslogRemotesLine.__init__c             C   sq   |  j  rX y t |  j   Wn; t k
 rW } z t d |  j   |  WYd  d  } ~ Xn X|  j sm t d   d  S)Nzport '%s' is not an integerzaddress is required)r<   rQ   rC   r;   )rR   er   r   r   rI   Z  s    		zSyslogRemotesLine.validatec             C   s&   d |  j  |  j |  j |  j |  j f S)Nz.[name=%s match=%s proto=%s address=%s port=%s])r?   r@   r:   r;   r<   )rR   r   r   r   __repr__f  s    zSyslogRemotesLine.__repr__c             C   s   |  j  d } |  j d k r) | d 7} n |  j d k rB | d 7} d |  j k ri | d |  j d 7} n | |  j 7} |  j r | d	 |  j 7} |  j r | d
 |  j 7} | S)N rN   rO   rP   z@@:r=   r>   z:%sz # %s)r@   r:   r;   r<   r?   )rR   Zbufr   r   r   __str__k  s    
		zSyslogRemotesLine.__str__)__name__
__module____qualname__rS   rI   rU   rX   r   r   r   r   rH   E  s
   rH   c             C   s   |  s
 d  Sg  } | d  k	 r) | j  |  x |  j   D]v \ } } | sK q6 y# | j  t t | d |   Wq6 t k
 r } z t j d | | |  WYd  d  } ~ Xq6 Xq6 W| d  k	 r | j  |  d j |  d S)Nr?   z!failed loading remote %s: %s [%s]r)   )r2   itemsr   rM   rC   r,   r-   r1   )r   headerfooterlinesr?   rJ   rT   r   r   r   remotes_to_rsyslog_cfg  s    #-r`   c       
      C   sM  d | k r  | j  d |   d  St |  } | t } | t rc | j t | t d d d d  | d s~ | j  d  d  St d | t d	 | t d
 | t  } | s | j  d  d  Sy) t	 d | t
 d | j j    f } Wn> t j k
 r%}	 z d } | j d |	  WYd  d  }	 ~	 Xn X| rI| j   | j  d |  |  d  S)Nr   z;Skipping module named %s, no 'rsyslog' key in configurationr]   z# begin remotesr^   z# end remotesr   z.Empty config rsyslog['configs'], nothing to dor5   r6   z0restart of syslog not necessary, no changes mader
   r   FzFailed to reload syslogz%s configured %s files)debugr#   r   r   r2   r`   r8   r   r   r   r   ZdistroZuses_systemdr   ZProcessExecutionErrorr-   Zcycle_logging)
r?   r   Zcloudr   Z_argsr    r   ZchangesZ	restartedrT   r   r   r   handle  s@    	







#
rb   )!__doc__r/   reZ	cloudinitr   Zloggingr   r   r   r   r	   r   r   r   r   r   r   r   r   Z	getLoggerrY   r,   compilerA   rE   r   r#   r8   rM   objectrH   r`   rb   r   r   r   r   <module>^   s6   W	(%: