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)
def test_constructor1(self): '''! Test when we call the constructor function with incomplete or wrong parameters ''' with pytest.raises(TypeError): url = URL() with pytest.raises(TypeError): url = URL(123) with pytest.raises(TypeError): url = URL([1]) with pytest.raises(TypeError): url = URL([1, 2, 3]) with pytest.raises(TypeError): url = URL((1)) with pytest.raises(TypeError): url = URL((1, 2, 3)) url = URL('http://localhost://2000/foo.txt') assert (url != None)
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)
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()
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
def test_constructor2(self): '''! Test when we call the constructor function with incomplete or wrong parameters ''' url = URL('http://localhost://2000/foo.txt') assert (url != None) assert (url.getSource() == 'http://localhost://2000/foo.txt') dl = [('foo', 'http://server:8080/file.txt')] d = dict(dl) with pytest.raises(TypeError): url = URL(d) dl = [('source', 'http://server:8080/file.txt')] d = dict(dl) url = URL(d) assert (url != None) dl = [('foo', 'http://server:8080/file.txt')] d = dict(dl) with pytest.raises(TypeError): url = URL(d) dl = [('source', 123)] d = dict(dl) with pytest.raises(TypeError): url = URL(d) url = URL('http://localhost://2000/foo.txt', 123) assert (url != None) with pytest.raises(TypeError): url = URL(None) dl = [('source', 'http://server:8080/file.txt'), ('destination', 123)] d = dict(dl) with pytest.raises(TypeError): url = URL(d) dl = [('source', 'http://server:8080/file.txt'), ('destination', 'abc')] d = dict(dl) url = URL(d) assert (url != None) dl = [('source', 'http://server:8080/file.txt')] d = dict(dl) url = URL(d, 'abc') assert (url != None) dl = [('source', 'http://server:8080/file.txt')] d = dict(dl) with pytest.raises(TypeError): url = URL(d, 123)