def read_uuid():
    uuid = ''
    uuid_file_path = '/sys/class/dmi/id/product_uuid'
    try:
        with open(uuid_file_path) as f:
            uuid = f.readline().strip()
    except Exception as e:
        raise LadLoggingConfigException(
            'read_uuid() failed: Unable to open uuid file {0}'.format(
                uuid_file_path))
    if not uuid:
        raise LadLoggingConfigException(
            'read_uuid() failed: Empty content in uuid file {0}'.format(
                uuid_file_path))
    return uuid
示例#2
0
    def __generate_mdsd_syslog_config(self):
        """
        Helper method to generate oms_mdsd_syslog_config
        """
        if self._syslog_disabled:
            return ''

        # For basic syslog conf (single dest table): Source name is unified as 'mdsd.syslog' and
        # dest table (eventName) is 'LinuxSyslog'. This is currently the only supported syslog conf scheme.
        syslog_routeevents = mxt.per_RouteEvent_tmpl.format(
            event_name='LinuxSyslog', opt_store_type='')
        # Add RouteEvent elements for specified "sinks" for "syslogEvents" feature
        # Also add EventStreamingAnnotation for EventHub sinks
        syslog_eh_urls = ''
        for sink_name in LadUtil.getSinkList(self._syslogEvents):
            if sink_name == 'LinuxSyslog':
                raise LadLoggingConfigException(
                    "'LinuxSyslog' can't be used as a sink name. "
                    "It's reserved for default Azure Table name for syslog events."
                )
            routeevent, eh_url = self.__generate_routeevent_and_eh_url_for_extra_sink(
                sink_name, syslog_src_name)
            syslog_routeevents += routeevent
            syslog_eh_urls += eh_url

        mdsd_event_source = ''
        if syslog_routeevents:  # Do not add MdsdEventSource element if there's no associated RouteEvent generated.
            mdsd_event_source = mxt.per_MdsdEventSource_tmpl.format(
                source=syslog_src_name, routeevents=syslog_routeevents)

        return mxt.top_level_tmpl_for_logging_only.format(
            sources=mxt.per_source_tmpl.format(name=syslog_src_name),
            events=mdsd_event_source,
            eh_urls=syslog_eh_urls)
 def __throw_if_output_is_none(output):
     """
     Helper to check if output is already generated (not None) and throw if it's not (None).
     :return: None
     """
     if output is None:
         raise LadLoggingConfigException('LadConfigAll.get_*_config() should be called after '
                                         'LadConfigAll.generate_mdsd_omsagent_syslog_config() is called')
示例#4
0
 def __generate_routeevent_and_eh_url_for_extra_sink(
         self, sink_name, src_name):
     """
     Helper method to generate one RouteEvent element for each extra sink given.
     Also generates an EventStreamingAnnotation element for EventHub sinks.
     :param str sink_name: The name of the sink for the RouteEvent.
     :param str src_name: The name of the ingested source that should be used for EventStreamingAnnotation.
     :rtype str,str:
     :return: A pair of the XML RouteEvent element string for the sink and the EventHubStreamingAnnotation
              XML string.
     """
     sink = self._sinksConfig.get_sink_by_name(sink_name)
     if not sink:
         raise LadLoggingConfigException(
             'Sink name "{0}" is not defined in sinksConfig'.format(
                 sink_name))
     sink_type = sink['type']
     if not sink_type:
         raise LadLoggingConfigException(
             'Sink type for sink "{0}" is not defined in sinksConfig'.
             format(sink_name))
     if sink_type == 'JsonBlob':
         return mxt.per_RouteEvent_tmpl.format(event_name=sink_name,
                                               opt_store_type='storeType="JsonBlob"'),\
                ''  # No EventStreamingAnnotation for JsonBlob
     elif sink_type == 'EventHub':
         if 'sasURL' not in sink:
             raise LadLoggingConfigException(
                 'sasURL is not specified for EventHub sink_name={0}'.
                 format(sink_name))
         # For syslog/filelogs (ingested events), the source name should be used for EventStreamingAnnotation name.
         eh_url = mxt.per_eh_url_tmpl.format(
             eh_name=src_name,
             key_path=self._pkey_path,
             enc_eh_url=self._encrypt_secret(self._cert_path,
                                             sink['sasURL']))
         return '', eh_url  # No RouteEvent for logging event's EventHub sink
     else:
         raise LadLoggingConfigException(
             '{0} sink type (for sink_name={1}) is not supported'.format(
                 sink_type, sink_name))
示例#5
0
def syslog_name_to_rsyslog_name(syslog_name):
    """
    Convert a syslog name (e.g., "LOG_USER") to the corresponding rsyslog name (e.g., "user")
    :param str syslog_name: A syslog name for a facility (e.g., "LOG_USER") or a severity (e.g., "LOG_ERR")
    :rtype: str
    :return: Corresponding rsyslog name (e.g., "user" or "error")
    """
    if syslog_name == '*':
        # We accept '*' as a facility name (also as a severity name, though it's not required)
        # to allow customers to collect for reserved syslog facility numeric IDs (12-15)
        return '*'
    if syslog_name not in syslog_name_to_rsyslog_name_map:
        raise LadLoggingConfigException(
            'Invalid syslog name given: {0}'.format(syslog_name))
    return syslog_name_to_rsyslog_name_map[syslog_name]
示例#6
0
    def __generate_mdsd_filelog_config(self):
        """
        Helper method to generate oms_mdsd_filelog_config
        """
        if not self._fileLogs:
            return ''

        # Per-file source name is 'mdsd.filelog<.path.to.file>' where '<.path.to.file>' is a full path
        # with all '/' replaced by '.'.
        filelogs_sources = ''
        filelogs_mdsd_event_sources = ''
        filelogs_eh_urls = ''
        for file_key in sorted(self._file_table_map):
            if not self._file_table_map[file_key] and not self._file_sinks_map[
                    file_key]:
                raise LadLoggingConfigException(
                    'Neither "table" nor "sinks" defined for file "{0}"'.
                    format(file_key))
            source_name = 'mdsd.filelog{0}'.format(file_key.replace('/', '.'))
            filelogs_sources += mxt.per_source_tmpl.format(name=source_name)
            per_file_routeevents = ''
            if self._file_table_map[file_key]:
                per_file_routeevents += mxt.per_RouteEvent_tmpl.format(
                    event_name=self._file_table_map[file_key],
                    opt_store_type='')
            if self._file_sinks_map[file_key]:
                for sink_name in self._file_sinks_map[file_key].split(','):
                    routeevent, eh_url = self.__generate_routeevent_and_eh_url_for_extra_sink(
                        sink_name, source_name)
                    per_file_routeevents += routeevent
                    filelogs_eh_urls += eh_url
            if per_file_routeevents:  # Do not add MdsdEventSource element if there's no associated RouteEvent generated.
                filelogs_mdsd_event_sources += \
                    mxt.per_MdsdEventSource_tmpl.format(source=source_name, routeevents=per_file_routeevents)
        return mxt.top_level_tmpl_for_logging_only.format(
            sources=filelogs_sources,
            events=filelogs_mdsd_event_sources,
            eh_urls=filelogs_eh_urls)
    def __init__(self, ext_settings, ext_dir, waagent_dir, deployment_id,
                 fetch_uuid, encrypt_string, logger_log, logger_error):
        """
        Constructor.
        :param ext_settings: A LadExtSettings (in Utils/lad_ext_settings.py) obj wrapping the Json extension settings.
        :param ext_dir: Extension directory (e.g., /var/lib/waagent/Microsoft.OSTCExtensions.LinuxDiagnostic-2.3.xxxx)
        :param waagent_dir: WAAgent directory (e.g., /var/lib/waagent)
        :param deployment_id: Deployment ID string (or None) that should be obtained & passed by the caller
                              from waagent's HostingEnvironmentCfg.xml.
        :param fetch_uuid: A function which fetches the UUID for the VM
        :param encrypt_string: A function which encrypts a string, given a cert_path
        :param logger_log: Normal logging function (e.g., hutil.log) that takes only one param for the logged msg.
        :param logger_error: Error logging function (e.g., hutil.error) that takes only one param for the logged msg.
        """
        self._ext_settings = ext_settings
        self._ext_dir = ext_dir
        self._waagent_dir = waagent_dir
        self._deployment_id = deployment_id
        self._fetch_uuid = fetch_uuid
        self._encrypt_secret = encrypt_string
        self._logger_log = logger_log
        self._logger_error = logger_error
        self._telegraf_me_url = metrics_constants.lad_metrics_extension_influx_udp_url
        self._telegraf_mdsd_url = metrics_constants.telegraf_influx_url
        self._enable_metrics_extension = False

        # Generated logging configs place holders
        self._fluentd_syslog_src_config = None
        self._fluentd_tail_src_config = None
        self._fluentd_out_mdsd_config = None
        self._rsyslog_config = None
        self._syslog_ng_config = None
        self._telegraf_config = None
        self._telegraf_namespaces = None

        self._mdsd_config_xml_tree = ET.ElementTree(
            ET.fromstring(mxt.entire_xml_cfg_tmpl))
        self._sink_configs = LadUtil.SinkConfiguration()
        self._sink_configs.insert_from_config(
            self._ext_settings.read_protected_config('sinksConfig'))
        # If we decide to also read sinksConfig from ladCfg, do it first, so that private settings override

        # Get encryption settings
        handlerSettings = ext_settings.get_handler_settings()

        if handlerSettings['protectedSettings'] is None:
            errorMsg = "Settings did not contain protectedSettings. For information on protected settings, " \
                          "visit https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/diagnostics-linux#protected-settings."
            self._logger_error(errorMsg)
            raise LadLoggingConfigException(errorMsg)

        if handlerSettings['protectedSettingsCertThumbprint'] is None:
            errorMsg = "Settings did not contain protectedSettingsCertThumbprint. For information on protected settings, " \
                          "visit https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/diagnostics-linux#protected-settings."
            self._logger_error(errorMsg)
            raise LadLoggingConfigException(errorMsg)

        thumbprint = handlerSettings['protectedSettingsCertThumbprint']

        self._cert_path = os.path.join(waagent_dir, thumbprint + '.crt')
        self._pkey_path = os.path.join(waagent_dir, thumbprint + '.prv')
示例#8
0
    def __init__(self, syslogEvents, fileLogs, sinksConfig, pkey_path,
                 cert_path, encrypt_secret):
        """
        Constructor to receive/store necessary LAD settings for the desired configuration generation.

        :param dict syslogEvents: LAD 3.0 "ladCfg" - "syslogEvents" JSON object, or a False object if it's not given
                             in the extension settings. An example is as follows:

                             "ladCfg": {
                                 "syslogEvents" : {
                                     "sinks": "SyslogSinkName0",
                                     "syslogEventConfiguration": {
                                         "facilityName1": "minSeverity1",
                                         "facilityName2": "minSeverity2"
                                     }
                                 }
                             }

                             Only the JSON object corresponding to "syslogEvents" key should be passed.

                             facilityName1/2 is a syslog facility name (e.g., "LOG_USER", "LOG_LOCAL0").
                             minSeverity1/2 is a syslog severity level (e.g., "LOG_ERR", "LOG_CRIT") or "NONE".
                                 "NONE" means no logs from the facility will be captured (thus it's equivalent to
                                  not specifying the facility at all).

        :param dict fileLogs: LAD 3.0 "fileLogs" JSON object, or a False object if it's not given in the ext settings.
                         An example is as follows:

                         "fileLogs": {
                             "fileLogConfiguration": [
                                 {
                                     "file": "/var/log/mydaemonlog",
                                     "table": "MyDaemonEvents",
                                     "sinks": "FilelogSinkName1",
                                 },
                                 {
                                     "file": "/var/log/myotherdaemonelog",
                                     "table": "MyOtherDaemonEvents",
                                     "sinks": "FilelogSinkName2"
                                 }
                             ]
                         }

                         Only the JSON array corresponding to "fileLogConfiguration" key should be passed.

                         "file" is the full path of the log file to be watched and captured. "table" is for the
                         Azure storage table into which the lines of the watched file will be placed (one row per line).
        :param LadUtil.SinkConfiguration sinksConfig:  SinkConfiguration object that's created out of "sinksConfig"
                    LAD 3.0 JSON setting. Refer to LadUtil.SinkConfiguraiton documentation.
        :param str pkey_path: Path to the VM's private key that should be passed to mdsd XML for decrypting encrypted
                    secrets (EH SAS URL)
        :param str cert_path: Path to the VM's certificate that should be used to encrypt secrets (EH SAS URL)
        :param encrypt_secret: Function to encrypt a secret (string, 2nd param) with the provided cert path param (1st)
        """
        self._syslogEvents = syslogEvents
        self._fileLogs = fileLogs
        self._sinksConfig = sinksConfig
        self._pkey_path = pkey_path
        self._cert_path = cert_path
        self._encrypt_secret = encrypt_secret
        self._fac_sev_map = None

        try:
            # Create facility-severity map. E.g.: { "LOG_USER" : "LOG_ERR", "LOG_LOCAL0", "LOG_CRIT" }
            if self._syslogEvents:
                self._fac_sev_map = self._syslogEvents[
                    'syslogEventConfiguration']
            self._syslog_disabled = not self._fac_sev_map  # A convenience predicate

            if self._fileLogs:
                # Convert the 'fileLogs' JSON object array into a Python dictionary of 'file' - 'table'
                # E.g., [{ 'file': '/var/log/mydaemonlog1', 'table': 'MyDaemon1Events', 'sinks': 'File1Sink'},
                #        { 'file': '/var/log/mydaemonlog2', 'table': 'MyDaemon2Events', 'sinks': 'File2SinkA,File2SinkB'}]
                self._file_table_map = dict([
                    (entry['file'], entry['table'] if 'table' in entry else '')
                    for entry in self._fileLogs
                ])
                self._file_sinks_map = dict([
                    (entry['file'], entry['sinks'] if 'sinks' in entry else '')
                    for entry in self._fileLogs
                ])

            self._rsyslog_config = None
            self._syslog_ng_config = None
            self._mdsd_syslog_config = None
            self._mdsd_telegraf_config = None
            self._mdsd_filelog_config = None
        except KeyError as e:
            raise LadLoggingConfigException(
                "Invalid setting name provided (KeyError). Exception msg: {0}".
                format(e))