Esempio n. 1
0
    def test_download(self, tmpdir):
        '''!
        Test the download method with destination specified in constructor
        '''

        url = URL('http://localhost://2000/foo.txt')
        assert (url != None)
        result = url.download()
        assert (result == (20, None))

        d = tmpdir.mkdir("valid")
        fh = d.join("input.json")
        content = 'Hello the world test_download!'
        fh.write(content)
        url = URL('file://' + str(fh), self.__filename('test.txt'))
        (rc, fname) = url.download()
        assert (rc == 0)
        assert (fname == self.__filename('test.txt'))
        assert (self.__read_file(fname) == content)
Esempio n. 2
0
    def test_download4(self, tmpdir):
        '''!
        Test the download method with destination not specified in url_data and optional destination specified
        '''

        dt = tmpdir.mkdir("valid")
        fh = dt.join("input.txt")
        content = 'Hello the world test_download4!'
        fh.write(content)
        dl = [('source', 'file://' + str(fh))]
        d = dict(dl)
        url = URL(d, self.__filename('test.txt'))
        (rc, fname) = url.download()
        assert (rc == 0)
        assert (fname == self.__filename('test.txt'))
        assert (self.__read_file(fname) == content)
Esempio n. 3
0
    def __init__(self, json_src_file=None, json_dst_file=None):
        '''!
         Constructor for ZTPJson class.

         As part of the object instantiation, ZTP JSON file is read and split into individual configuration sections.
         The contents of ZTP JSON are saved as a dictionary to be used. Missing objects are added assuming default values. A list of
         configuration sections defined in the ZTP JSON is collected.

         @param json_src_file (str, optional) Configuration section input.json file to be prcoessed. If not specified,
                                              /etc/sonic/ztp_data.json file is used.
         @param json_dst_file (str, optional) Destination file to which processed JSON data is saved to. If not specified,
                                              json_src_file is used as destination file.


         @exception Raise ValueError if any error or exception encountered while processing the json_src_file

        '''
        # Call base class constructor
        ConfigSection.__init__(self, json_src_file, json_dst_file)

        # Raise exception if top level ztp section is not found
        self.ztpDict = self.jsonDict.get('ztp')
        if self.ztpDict is None or isinstance(self.ztpDict, dict) is False:
            raise ValueError('ztp section not found in JSON data')

        # Read ZTP JSON version
        if self.ztpDict.get('ztp-json-version') is None:
            self.ztpDict['ztp-json-version'] = getCfg('ztp-json-version',
                                                      'Not Available')

        # Check for presence of url or dynamic-url and download the actual json content
        reloadZTPJson = False
        try:
            if self.ztpDict.get('dynamic-url'):
                dyn_url_data = self.ztpDict.get('dynamic-url')
                if isinstance(dyn_url_data, dict):
                    dyn_url_data['destination'] = self.json_dst_file
                objDynamicURL = DynamicURL(dyn_url_data, self.json_dst_file)
                rc, filename = objDynamicURL.download()
                if rc == 0:
                    reloadZTPJson = True
                else:
                    raise ValueError(
                        'url section provided in ztp section could not be resolved'
                    )
            elif self.ztpDict.get('url'):
                url_data = self.ztpDict.get('url')
                if isinstance(url_data, dict):
                    url_data['destination'] = self.json_dst_file
                objURL = URL(url_data, self.json_dst_file)
                rc, filename = objURL.download()
                if rc == 0:
                    reloadZTPJson = True
                else:
                    raise ValueError(
                        'dynamic-url section provided in ztp section could not be resolved'
                    )
        except:
            raise ValueError(
                'url/dynamic-url sections provided in ztp section could not be interpreted'
            )

        if reloadZTPJson is True and os.path.isfile(self.json_dst_file):
            ConfigSection.__init__(self, self.json_dst_file,
                                   self.json_dst_file)
            self.ztpDict = self.jsonDict.get('ztp')
            if self.ztpDict is None or isinstance(self.ztpDict, dict) is False:
                raise ValueError('ztp section not found in JSON data')

            # Read ZTP JSON version
            if self.ztpDict.get('ztp-json-version') is None:
                self.ztpDict['ztp-json-version'] = getCfg(
                    'ztp-json-version', 'Not Available')

        # Insert default values
        self.__buildDefaults()

        # Cleanup previous ZTP run files
        if self.ztpDict['status'] == 'BOOT':
            self.__cleanup()

        # Identify valid configuration sections
        self.section_names = sorted(self.ztpDict.keys())

        for k, v in self.ztpDict.items():
            # Remove leaf objects as they are not configuration sections
            if isinstance(v, dict) is False:
                self.section_names.remove(k)
                continue
            # Insert default values in configuration sections
            self._ConfigSection__buildDefaults(v)
            # Split confguration sections to individual files
            self.__writeConfigSections(k, v)

        # Write ZTP JSON data to file
        self.objJson.writeJson()
        # Update the shadow ZTP JSON file with new information
        self.__writeShadowJSON()
Esempio n. 4
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