コード例 #1
0
ファイル: Logger.py プロジェクト: tim-rj/sonic-ztp
    def setlogFile(self, log_file=None):
        '''!
        Set the log file to store all logs generated during ZTP

        @param log_file (str) log file
        @exception Raise TypeError if incorrect parameter type
        '''

        rsyslog_conf_file = getCfg("rsyslog-ztp-log-file-conf",
                                   '/etc/rsyslog.d/10-ztp.conf')
        if log_file is None or (isString(log_file) and log_file == ''):
            if os.path.isfile(rsyslog_conf_file):
                os.remove(rsyslog_conf_file)
            return

        if not isString(log_file):
            raise TypeError("Log file must be a string")

        self.__log_file = log_file
        change = True
        if os.path.isfile(rsyslog_conf_file):
            fh = open(rsyslog_conf_file, 'r')
            if fh.readline().strip(
            ) == ':programname, contains, "sonic-ztp"  ' + log_file:
                change = False
            fh.close()

        if change:
            fh = open(rsyslog_conf_file, 'w')
            fh.write(':programname, contains, "sonic-ztp"  ' + log_file)
            fh.close()
            runCommand('systemctl restart rsyslog', capture_stdout=False)
コード例 #2
0
ファイル: ZTPObjects.py プロジェクト: tim-rj/sonic-ztp
    def __init__(self, url_data, destination=None):
        '''!
            Constructor for the URL class.

            @param url_data (dict) Information to be used to download the file
            @param destination (str, optional) When specified, this represents the filename used to save the \n
                                               downloaded file as. If destination value is available in url_data,
                                               this parameter is ignored.
        '''
        argError = False
        self.__destination = None
        if isString(url_data):
            self.__source = url_data
            self.__destination = destination
        elif isinstance(url_data, dict) is False or \
             url_data.get('source') is None or \
             isString(url_data.get('source')) is False:
            argError = True
        elif isinstance(url_data, dict):
            self.__source = url_data.get('source')
            if url_data.get('destination') is None:
                self.__destination = destination
            else:
                self.__destination = url_data.get('destination')
            if self.__destination is not None and isString(
                    self.__destination) is False:
                argError = True

        if argError:
            logger.debug('URL provided with invalid argument types.')
            raise TypeError('URL provided with invalid argument types.')

        self.url_data = url_data
        if isinstance(url_data, dict):
            self.objDownload = Downloader(self.__source, \
                                          self.__destination, \
                                          incl_http_headers=getField(self.url_data, 'include-http-headers', bool, None), \
                                          is_secure=getField(self.url_data, 'secure', bool, None), \
                                          curl_args=self.url_data.get('curl-arguments'), \
                                          encrypted=getField(self.url_data, 'encrypted', bool, None), \
                                          timeout=getField(self.url_data, 'timeout', int, None))
        else:
            self.objDownload = Downloader(self.__source, self.__destination)
コード例 #3
0
    def __buildDefaults(self, section):
        '''!
         Helper API to include missing objects in a configuration section and validate their values.
         Below are the objects that are validated and added if not present: \n
           - ignore-result\n
           - reboot-on-success\n
           - reboot-on-failure\n
           - halt-on-failure\n
           - timestamp\n

         Below are the objects whose value is validated:\n
           - status
           - suspend-exit-code

         If the specified value is invalid  of if the object is not specified, its value is read from ztp_cfg.json

         @param section (dict) Configuration Section input data read from JSON file.

        '''
        default_objs = [
            'ignore-result', 'reboot-on-success', 'reboot-on-failure',
            'halt-on-failure'
        ]
        # Loop through objects and update them with default values
        for key in default_objs:
            _val = getField(section, key, bool, getCfg(key))
            section[key] = _val

        # set status
        if section.get('status') is None:
            section['status'] = 'BOOT'
            section['timestamp'] = getTimestamp()
        elif isString(section.get('status')) is False or \
            section.get('status') not in ['BOOT', 'IN-PROGRESS', 'SUSPEND', 'DISABLED', 'FAILED', 'SUCCESS']:
            logger.warning(
                'Invalid value (%s) used for configuration section status. Setting it to DISABLED.'
                % section.get('status'))
            section['status'] = 'DISABLED'
            section['timestamp'] = getTimestamp()

        # Validate suspend-exit code
        if section.get('suspend-exit-code') is not None:
            suspend_exit_code = getField(section, 'suspend-exit-code', int,
                                         None)
            if suspend_exit_code is None or suspend_exit_code < 0:
                del section['suspend-exit-code']

        # Add timestamp if missing
        if section.get('timestamp') is None:
            section['timestamp'] = getTimestamp()
コード例 #4
0
    def updateStatus(self, obj, status):
        '''!
         Update status of configuration section. Also update the timestamp indicating date/time when it is updated. The changes
         are also saved to the JSON file on disk which corresponds to the configuration section.

         @param status (str) Value to be stored as status

        '''
        if isinstance(obj, dict) and isString(status):
            self.objJson.set(obj, 'status', status)
            self.objJson.set(obj, 'timestamp', getTimestamp(), True)
        else:
            logger.error('Invalid argument type.')
            raise TypeError('Invalid argument type')
コード例 #5
0
    def pluginArgs(self, section_name):
        '''!
         Resolve the plugin arguments used to be passed as command line arguments to
         the plugin used to process configuration section

         @param section_name (str) Configuration section name whose plugin arguments needs to be resolved.

         @return
              Concatenated string of all the argements defined \n
              If no arguments are defined or error encountered: \n
                None
        '''

        if isString(section_name) is False:
            raise TypeError('Invalid argument used as section name')
        elif self.ztpDict.get(section_name) is None:
            logger.error('Configuration Section %s not found.' % section_name)
            return None

        # Obtain plugin data
        plugin_data = self.ztpDict.get(section_name).get('plugin')

        # Get the location of this configuration section's input data parsed from the input ZTP JSON file
        plugin_input = getCfg(
            'ztp-tmp-persistent') + '/' + section_name + '/' + getCfg(
                'section-input-file')

        plugin_args = ''
        ignore_section_data_arg = getField(plugin_data, 'ignore-section-data',
                                           bool, False)
        _plugin_json_args = getField(plugin_data, 'args', str, None)

        if ignore_section_data_arg is False:
            plugin_args = plugin_input

        if _plugin_json_args is not None:
            plugin_args = plugin_args + ' ' + _plugin_json_args

        logger.debug('Plugin arguments for %s evaluated to be %s.' %
                     (section_name, plugin_args))
        return plugin_args
コード例 #6
0
ファイル: Logger.py プロジェクト: tim-rj/sonic-ztp
    def setLevel(self, log_level):
        '''!
        Set the current level of logging.

        @param log_level (int) log level which will be shown on stdout (DEBUG, INFO, WARNING, ERROR or CRITICAL)
        @exception Raise TypeError if incorrect parameter type
        '''

        if not isString(log_level) and not type(log_level) == int:
            raise TypeError("Log Level must be a number or a string")

        if type(log_level) == int:
            self.__log_level = log_level
        else:
            self.__log_level = self.__str_to_int_level(log_level)

        if type(log_level) == int:
            if (self.__log_level > self.DEBUG) or (self.__log_level <
                                                   self.CRITICAL):
                self.__log_level = self.INFO

        syslog.setlogmask(syslog.LOG_UPTO(self.__log_level))
コード例 #7
0
ファイル: ZTPObjects.py プロジェクト: tim-rj/sonic-ztp
    def __init__(self, dyn_url_data, destination=None):
        '''!
            Constructor for the DynamicURL class.

            @param dyn_url_data (dict) Information to be used to download the file
            @param destination (str, optional) When specified, this represents the filename used to save the \n
                                               downloaded file as. If destination value is available in url_data,
                                               this parameter is ignored.

            @exception Raise ValueError if insufficient input is provided.
            @exception Raise TypeError if invalid input is provided or if switch identifier could not be resolved.

            Switch identifier string is resolved as part of the constructor.
        '''
        if dyn_url_data is None or isinstance(dyn_url_data, dict) is False or \
           dyn_url_data.get('source') is None or isinstance(dyn_url_data.get('source'), dict) is False or \
           dyn_url_data.get('source').get('identifier') is None:
            logger.debug('DynamicURL provided with invalid argument types.')
            raise TypeError('DynamicURL provided with invalid argument types')

        self.__destination = None
        if dyn_url_data.get('destination') is not None:
            self.__destination = dyn_url_data.get('destination')
        elif destination is not None:
            self.__destination = destination

        if self.__destination is not None and \
           isString(self.__destination) is False:
            logger.debug('DynamicURL provided with invalid argument types.')
            raise TypeError('DynamicURL provided with invalid argument types')

        self.dyn_url_data = dyn_url_data
        source = dyn_url_data.get('source')

        self.__source = ''
        if source.get('prefix') is not None:
            if isString(source.get('prefix')):
                self.__source = source.get('prefix')
            else:
                raise TypeError(
                    'DynamicURL provided with invalid argument types.')

        objIdentifier = Identifier(source.get('identifier'))
        identifier = objIdentifier.getIdentifier()
        if identifier is None:
            raise ValueError(
                'DynamicURL source identifier could not be evaluated.')
        else:
            self.__source = self.__source + identifier

        if source.get('suffix') is not None:
            if isString(source.get('suffix')):
                self.__source = self.__source + source.get('suffix')
            else:
                raise TypeError(
                    'DynamicURL provided with invalid argument types.')

        self.objDownload = Downloader(self.__source, \
                                      self.__destination, \
                                      incl_http_headers=getField(self.dyn_url_data, 'include-http-headers', bool, None), \
                                      is_secure=getField(self.dyn_url_data, 'secure', bool, None), \
                                      curl_args=self.dyn_url_data.get('curl-arguments'), \
                                      encrypted=getField(self.dyn_url_data, 'encrypted', bool, None), \
                                      timeout=getField(self.dyn_url_data, 'timeout', int, None))
コード例 #8
0
    def plugin(self, section_name):
        '''!
         Resolve the plugin used to process a configuration section. If the plugin is specified
         as a url object, the plugin is downloaded.

         @param section_name (str) Configuration section name whose plugin needs to be resolved.

         @return
              If plugin is resolved using configuration section data: \n
                Expanded file path to plugin file used to process configuration section. \n
              If plugin is not found or error encountered: \n
                None
        '''

        if isString(section_name) is False:
            raise TypeError('Invalid argument used as section name')
        elif self.ztpDict.get(section_name) is None:
            logger.error('Configuration Section %s not found.' % section_name)
            return None

        plugin_data = self.ztpDict.get(section_name).get('plugin')
        name = None
        if plugin_data is not None and isinstance(plugin_data, dict):
            logger.debug(
                'User defined plugin detected for configuration section %s.' %
                section_name)
            plugin_file = getCfg(
                'ztp-tmp-persistent') + '/' + section_name + '/' + 'plugin'
            try:
                # Re-use the plugin if already present
                if os.path.isfile(plugin_file) is True:
                    return plugin_file

                if plugin_data.get('dynamic-url'):
                    dyn_url_data = plugin_data.get('dynamic-url')
                    if isinstance(dyn_url_data, dict) and dyn_url_data.get(
                            'destination') is not None:
                        objDynUrl = DynamicURL(dyn_url_data)
                    else:
                        objDynUrl = DynamicURL(dyn_url_data, plugin_file)
                    rc, plugin_file = objDynUrl.download()
                    return plugin_file
                elif plugin_data.get('url'):
                    url_data = plugin_data.get('url')
                    if isinstance(
                            url_data,
                            dict) and url_data.get('destination') is not None:
                        objUrl = URL(url_data)
                    else:
                        objUrl = URL(url_data, plugin_file)
                    updateActivity(
                        'Downloading plugin \'%s\' for configuration section %s'
                        % (objUrl.getSource(), section_name))
                    rc, plugin_file = objUrl.download()
                    if rc != 0:
                        logger.error(
                            'Failed to download plugin \'%s\' for configuration section %s.'
                            % (objUrl.getSource(), section_name))
                    return plugin_file
                elif plugin_data.get('name') is not None:
                    name = plugin_data.get('name')
            except (TypeError, ValueError, OSError, IOError) as e:
                logger.error(
                    'Exception [%s] encountered while determining plugin for configuration section %s.'
                    % (str(e), section_name))
                return None
        elif plugin_data is not None and isString(plugin_data):
            name = plugin_data
        elif plugin_data is not None:
            logger.error(
                'Invalid plugin data type used for configuration section %s.' %
                section_name)
            return None

        # plugin name is not provided in section data, use section name as plugin name
        if name is None:
            res = re.split("^[0-9]+-", section_name, maxsplit=1)
            if len(res) > 1:
                name = res[1]
            else:
                name = res[0]
        logger.debug(
            'ZTP provided plugin %s is being used for configuration section %s.'
            % (name, section_name))
        if os.path.isfile(getCfg('plugins-dir') + '/' + name) is True:
            return getCfg('plugins-dir') + '/' + name
        return None