diff --git a/.version b/.version index ef538c2..389f774 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -3.1.2 +4.0 \ No newline at end of file diff --git a/README.md b/README.md index b80871a..13f0c08 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Netsim Wrapper +## TODO: need to update badges + [![License: Apache 2.0](https://img.shields.io/badge/License-Apache2-yellow.svg)](https://opensource.org/licenses/Apache-2.0) [![Version: 3.1.2](https://img.shields.io/badge/Version-3.1.2-parrotgreen.svg)](https://github.com/NSO-developer/netsim-wrapper) [![Downloads](https://pepy.tech/badge/netsim-wrapper)](https://pepy.tech/project/netsim-wrapper) @@ -7,6 +9,8 @@ ncs-netsim is a great tool, but it lack of following features which are developed as part of netsim-wrapper +## TODO: changing options + - netsim-wrapper features - delete-devices \ - create-network-from [ yaml | json ] \ diff --git a/templates/create_device_from.json b/examples-templates/create_device_from.json similarity index 100% rename from templates/create_device_from.json rename to examples-templates/create_device_from.json diff --git a/templates/create_device_from.yaml b/examples-templates/create_device_from.yaml similarity index 100% rename from templates/create_device_from.yaml rename to examples-templates/create_device_from.yaml diff --git a/templates/create_network_from.json b/examples-templates/create_network_from.json similarity index 100% rename from templates/create_network_from.json rename to examples-templates/create_network_from.json diff --git a/templates/create_network_from.yaml b/examples-templates/create_network_from.yaml similarity index 100% rename from templates/create_network_from.yaml rename to examples-templates/create_network_from.yaml diff --git a/netsim_wrapper/common/__init__.py b/netsim_wrapper/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netsim_wrapper/common/log.py b/netsim_wrapper/common/log.py new file mode 100644 index 0000000..b051a26 --- /dev/null +++ b/netsim_wrapper/common/log.py @@ -0,0 +1,32 @@ +""" +Application logging operations +""" + +import logging + +from functools import lru_cache + + +class SingletonMeta(type): + __call__ = lru_cache(maxsize=None)(type.__call__) + + +class Logger(metaclass=SingletonMeta): + """ + Logger with singleton metaclass + """ + format = '%(levelname)-8s | %(asctime)s | %(module)-8s:%(lineno)-4d | %(message)s' + log = logging.basicConfig(level=logging.INFO, format=format) or logging.getLogger() + + def __init__(self, level=logging.INFO) -> None: + self.level = level + self.log = self.get_log + + @property + def get_log(self): + """ + Fetching logger with logging level + """ + logging.basicConfig(level=self.level, format=format) + return logging.getLogger() + diff --git a/netsim_wrapper/common/system.py b/netsim_wrapper/common/system.py new file mode 100644 index 0000000..65dfb13 --- /dev/null +++ b/netsim_wrapper/common/system.py @@ -0,0 +1,74 @@ +""" +The module is for system operations exit, unlink +""" + +from pathlib import Path +from sys import exit as sys_exit +import subprocess + +from .log import Logger + + +class System: + def __init__(self) -> None: + super(System, self).__init__() + self.log = Logger().log + self.log.debug("class: {} initialize".format(__class__.__name__)) + + @property + def exit(self): + self.log.debug('exit method called') + sys_exit() + + def delete(self, fpath): + """ + Delete file if exist + """ + path = Path(fpath).absolute() + if path.exists(): + path.unlink() + self.log.debug('deleted file: {}'.format(fpath)) + + def is_file(self, fpath): + """ + Given path is it a file + """ + path = Path(fpath).absolute() + return path.is_file() + + def is_dir(self, fpath): + """ + Given path is it a folder + """ + path = Path(fpath).absolute() + return path.is_dir() + + def call(self, cmd): + """ + System subprocess call + """ + try: + self.log.debug("call cmd: {}".format(' '.join(cmd))) + subprocess.call(cmd, shell=True) + except EnvironmentError as e: + self.log.error("failed to run command: {}".format(cmd)) + self.log.error(e) + + def run(self, cmd, error=True): + """ + System subprocess open and communicate + """ + self.log.debug("popen cmd: {}".format(' '.join(cmd))) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + out, err = out.decode('utf-8'), err.decode('utf-8') + if err == '' or 'env.sh' in err: + self.log.debug("`{}` ran successfully".format(' '.join(cmd))) + self.log.debug("out: {}".format(out)) + return out + if error: + self.log.error("an error occured while running command `{}`".format(' '.join(cmd))) + self.log.error('message: {}'.format(err)) + if 'command not found' in err or 'Unknown command' in err: + raise ValueError("command not found.") + return False diff --git a/netsim_wrapper/common/utils.py b/netsim_wrapper/common/utils.py new file mode 100644 index 0000000..b0ab378 --- /dev/null +++ b/netsim_wrapper/common/utils.py @@ -0,0 +1,41 @@ +""" +The module is for system operations (subprocess) and setting logger +""" + +from logging import INFO +from pathlib import Path + +from .system import System +from ..templates.json import Json +from ..templates.yaml import Yaml +from ..templates.xml import Xml + + +class Utils(System): + def __init__(self) -> None: + super(Utils, self).__init__() + self.log.debug("class: {} initialize".format(__class__.__name__)) + # self.json = Json(level=level) + # self.yaml = Yaml(level=level) + # self.xml = Xml(level=level) + + # def create(self, fpath): + # if not self.is_file(fpath): + # self.dump(fpath, {}) + + def rstrip_digits(self, given_string): + return given_string.rstrip('1234567890') + + def get_index(self, given_list, element): + try: + return given_list.index(element) + except ValueError: + return None + + def get_path(self): + path = None + # if len(cmd_lst) > index+1: + # path = cmd_lst[index+1] + # else: + # path = '{}/{}.{}'.format(self.path, filename, filetype) + return path diff --git a/netsim_wrapper/netsim.py b/netsim_wrapper/netsim.py new file mode 100644 index 0000000..5ec73e4 --- /dev/null +++ b/netsim_wrapper/netsim.py @@ -0,0 +1,139 @@ +from re import compile +from typing import Any +from logging import INFO + +from .common.utils import Utils + +class Netsim(Utils): + name = 'ncs-netsim' + command = ['ncs-netsim'] + options = [] + netsim_dir = 'netsim' + help = None + + def __init__(self) -> None: + super(Netsim, self).__init__() + self.help() + self.options() + + def ncs_netsim(self, cmd, print_result=True, throw_err=True) -> Any: + try: + output = self.run(cmd=self.command+cmd, error=throw_err) + if not output: + raise ValueError("something went wrong, try netsim-wrapper --help") + except ValueError as e: + if throw_err: + self.log.error(e) + self.exit + raise ValueError(e) + if print_result: + print(output.rsplit('\n')) + return output + + def help(self): + if self.help: + return + try: + self.help = self.run(self.command + ['--help']) + except ValueError as e: + self.log.error(e) + self.exit + except FileNotFoundError as e: + self.log.error('ncs-netsim command not found. please source ncsrc file') + self.exit + + def options(self): + if len(self.netsim_options): + return self.options + rgx_cmd = compile(r'^\s+([a-z-]+)') + rgx_opt = compile(r'^\s+\[(\S+)\s+\|\s+([a-z-]+).*?\]\s+([a-z]+)') + for line in self.help.split('\n'): + res = rgx_cmd.match(line) + if res: + self.options += list(res.groups()) + res = rgx_opt.match(line) + if res: + self.options += list(res.groups()) + self.options += ['cli', 'cli-c', 'cli-i', '--dir'] + + + + + +class Netsim(Utils): + name = 'ncs-netsim' + command = ['ncs-netsim'] + netsim_options = [] + netsim_dir = 'netsim' + + _instance = None + _ncs_netsim_help = None + + __stdout = subprocess.PIPE + __stderr = subprocess.PIPE + + _split = '#######' + + def __new__(cls, log_level=logging.INFO, log_format=None): + if cls._instance is None: + cls._instance = object.__new__(cls) + return cls._instance + + def __init__(self, log_level=logging.INFO, log_format=None, *args, **kwargs): + Utils.__init__(self, log_level, log_format) + + + @property + def __netsim_devices_created_by(self): + self._netsim_devices_created_by = {} + data = self.run_ncs_netsim__command(['list'], print_output=False).split('\n') + result = list(filter(lambda x: 'netconf' in x, data)) + for each in result: + each = each.split('/') + dev_name = each[-1].strip() + if dev_name == each[-2]: + self._netsim_devices_created_by[dev_name] = ['add-device', each[-2]] + else: + self._netsim_devices_created_by[dev_name] = ['add-to-network', each[-2]] + + + def _netsim_device_mapper(self, data): + _netsim_mapper = collections.OrderedDict() + for each_device in data: + device = each_device.split('=') + if len(device) > 1: + device = device[1].split('\n')[0] + _netsim_mapper[device] = self._netsim_device_keypair_mapper(device, each_device) + return _netsim_mapper + + def _netsim_device_keypair_mapper(self, device, data): + _mapper = {} + for each_line in data.split('\n'): + if len(each_line.split('[')) > 1: + key = (each_line.split('[')[0]).strip(' ') + value = each_line.split('=')[1] + _mapper[key] = value + _mapper['created_by'] = self._netsim_devices_created_by.get(device)[0] + _mapper['parent'] = self._netsim_devices_created_by.get(device)[1] + return _mapper + + def _dump_netsim_mapper(self, path, netsim_mapper): + fp = open(path, 'w') + fp.write('\n') + index = 0 + for device_name, device_dict in netsim_mapper.items(): + fp.write('## device {}\n'.format(device_name)) + for key, value in device_dict.items(): + if key in ['created_by', 'parent']: + continue + fp.write('{}[{}]={}\n'.format(key, index, value)) + fp.write('#######\n\n') + index += 1 + fp.close() + + + + def read_netsim(self, path): + data = open(path).read().split(self._split) + self.__netsim_devices_created_by + return self._netsim_device_mapper(data) diff --git a/netsim_wrapper/netsim2.py b/netsim_wrapper/netsim2.py index 05afe0b..e59c322 100644 --- a/netsim_wrapper/netsim2.py +++ b/netsim_wrapper/netsim2.py @@ -10,131 +10,6 @@ from operator import methodcaller -class Utils: - name = 'utils' - - _instance = None - def __new__(cls, log_level=logging.INFO, log_format=None): - if cls._instance is None: - cls._instance = object.__new__(cls) - return cls._instance - - def __init__(self, log_level=logging.INFO, log_format=None, *args, **kwargs): - self.__format = log_format - self.current_path = os.path.abspath('.') - self.logger = self.__set_logger_level(log_level) - self._setup_yaml - - def __set_logger_level(self, log_level): - if self.__format is None: - self.__format = '[ %(levelname)s ] :: [ %(name)s ] :: %(message)s' - logging.basicConfig(stream=sys.stdout, level=log_level, - format=self.__format, datefmt=None) - logger = logging.getLogger(self.name) - logger.setLevel(log_level) - return logger - - @property - def _setup_yaml(self): - represent_dict_order = lambda self, data: \ - self.represent_mapping( - 'tag:yaml.org,2002:map', - data.items() - ) - yaml.add_representer(collections.OrderedDict, represent_dict_order) - - def __del__(self): - self._instance = None - - @property - def _exit(self): - sys.exit() - - def _dump_yaml(self, filename, template): - try: - with open(filename, 'w') as f: - yaml.dump(template, f, sort_keys=False) - self.logger.info("please, find the {} file in current directory".format(filename)) - self.logger.info("update based on your requirement") - except EnvironmentError as e: - self.logger.error("error on createing of template..") - self.logger.error(e) - - def _dump_json(self, filename, template): - try: - with open(filename, 'w') as f: - json.dump(template, f, indent=2) - self.logger.info("please, find the {} file in current directory".format(filename)) - self.logger.info("update based on your requirement") - except EnvironmentError as e: - self.logger.error("error on createing of template..") - self.logger.error(e) - - def _load_yaml(self, path): - data = None - try: - with open(path) as f: - data = yaml.load(f, Loader=yaml.FullLoader) - except EnvironmentError as e: - self.logger.error("error while loading the {} file..".format(path)) - self.logger.error(e) - return data - - def _load_json(self, path): - data = None - try: - with open(path) as f: - data = json.load(f) - except EnvironmentError as e: - self.logger.error("error while loading the {} file..".format(path)) - self.logger.error(e) - return data - - def _create_file(self, path): - if not os.path.exists(path): - with open(path, "w") as fp: - json.dump({}, fp) - - def _delete_file(self, path): - if os.path.exists(path): - os.remove(path) - - def _rstrip_digits(self, given_string): - return given_string.rstrip('1234567890') - - def get_index(self, given_list, element): - try: - return given_list.index(element) - except ValueError: - return None - - def _load_path(self, cmd_lst, index, filename, filetype='yaml'): - if len(cmd_lst) > index+1: - path = cmd_lst[index+1] - else: - path = '{}/{}.{}'.format(self.current_path, filename, filetype) - return path - - def _dump_xml(self, filename, xml_data): - try: - with open(filename, 'w') as fp: - fp.write(xml_data) - except EnvironmentError as e: - self.logger.error("error on createing xml file") - self.logger.error(e) - - def _run_bash_commands(self, cmd): - try: - subprocess.call(cmd, shell=True) - except EnvironmentError as e: - self.logger.error("failed to run command: {}".format(cmd)) - self.logger.error(e) - - def _is_file(self, fname): - return os.path.isfile(fname) - - def _is_folder(self, fname): - return os.path.isdir(fname) class Netsim(Utils): name = 'ncs-netsim' @@ -211,68 +86,23 @@ def __netsim_devices_created_by(self): else: self._netsim_devices_created_by[dev_name] = ['add-to-network', each[-2]] - @property - def _build_network_template(self): - template = collections.OrderedDict() - template['nso-packages-path'] = '' # String - template['compile-neds'] = True # True/False - template['start-devices'] = True # True/False - template['add-to-nso'] = True # True/False - template['add-authgroup-to-nso'] = True # True/False - template['authgroup'] = collections.OrderedDict() # Dict - template['authgroup']['type'] = 'custom' # local/system/custom - template['authgroup']['path'] = '' - template['device-mode'] = collections.OrderedDict() - template['device-mode']['prefix-based'] = collections.OrderedDict() - template['device-mode']['prefix-based'][''] = collections.OrderedDict() - template['device-mode']['prefix-based']['']['count'] = 2 - template['device-mode']['prefix-based']['']['prefix'] = '' - template['load-day0-config'] = True - template['config-path'] = '' # config path - template['config-files'] = [] - template['config-files'].append('') # each file path - template['config-files'].append('') - return template - @property - def _build_device_template(self): - template = collections.OrderedDict() - template['nso-packages-path'] = '' # String - template['compile-neds'] = True # True/False - template['start-devices'] = True # True/False - template['add-to-nso'] = True # True/False - template['add-authgroup-to-nso'] = True # True/False - template['authgroup'] = collections.OrderedDict() - template['authgroup']['type'] = 'custom' # local/system/custom - template['authgroup']['path'] = '' - template['device-mode'] = collections.OrderedDict() - template['device-mode']['name-based'] = collections.OrderedDict() - template['device-mode']['name-based'][''] = [] - template['device-mode']['name-based'][''].append('device1') - template['device-mode']['name-based'][''].append('device2') - template['load-day0-config'] = True # True/False - template['config-path'] = '' # config path - template['config-files'] = [] - template['config-files'].append('') # each file path - template['config-files'].append('') - return template - - def _run_command(self, command, throw_err=True): - self.logger.debug("command `{}` running on ncs-netsim".format(' '.join(command))) - p = subprocess.Popen(command, stdout=self.__stdout, - stderr=self.__stderr) - out, err = p.communicate() - out, err = out.decode('utf-8'), err.decode('utf-8') - if err == '' or 'env.sh' in err: - self.logger.debug("`{}` ran successfully".format(' '.join(command))) - return out - if throw_err: - self.logger.error("an error occured while running command `{}`".format(' '.join(command))) - self.logger.error('message: {}'.format(err)) - if 'command not found' in err or 'Unknown command' in err: - raise ValueError("command not found.") - raise ValueError("try netsim-wrapper --help") - raise ValueError("{}\ntry netsim-wrapper --help".format(err)) + # def _run_command(self, command, throw_err=True): + # self.logger.debug("command `{}` running on ncs-netsim".format(' '.join(command))) + # p = subprocess.Popen(command, stdout=self.__stdout, + # stderr=self.__stderr) + # out, err = p.communicate() + # out, err = out.decode('utf-8'), err.decode('utf-8') + # if err == '' or 'env.sh' in err: + # self.logger.debug("`{}` ran successfully".format(' '.join(command))) + # return out + # if throw_err: + # self.logger.error("an error occured while running command `{}`".format(' '.join(command))) + # self.logger.error('message: {}'.format(err)) + # if 'command not found' in err or 'Unknown command' in err: + # raise ValueError("command not found.") + # raise ValueError("try netsim-wrapper --help") + # raise ValueError("{}\ntry netsim-wrapper --help".format(err)) def _netsim_device_mapper(self, data): _netsim_mapper = collections.OrderedDict() @@ -330,7 +160,7 @@ def read_netsim(self, path): class NetsimWrapper(Netsim): name = 'netsim-wrapper' options = [] - version = '3.1.2' + version = '3.1.2' # 4.0 _instance = None _netsim_wrapper_help = None diff --git a/netsim_wrapper/run.py b/netsim_wrapper/run.py new file mode 100644 index 0000000..e69de29 diff --git a/netsim_wrapper/templates/__init__.py b/netsim_wrapper/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/netsim_wrapper/templates/convert.py b/netsim_wrapper/templates/convert.py new file mode 100644 index 0000000..bb97c75 --- /dev/null +++ b/netsim_wrapper/templates/convert.py @@ -0,0 +1,31 @@ +from copy import copy +from typing import Union + + +def object2xml(data: Union[dict, bool], root='object'): + xml = f'<{root}>' + if isinstance(data, dict): + for key, value in data.items(): + xml += object2xml(value, key) + + elif isinstance(data, (list, tuple, set)): + for item in data: + xml += object2xml(item, 'item') + + else: + xml += str(data) + + xml += f'' + return xml + +def xml2dict(r,root=True): + if root: + return {r.tag : xml2dict(r, False)} + d=copy(r.attrib) + if r.text: + d["_text"]=r.text + for x in r.findall("./*"): + if x.tag not in d: + d[x.tag]=[] + d[x.tag].append(xml2dict(x,False)) + return d \ No newline at end of file diff --git a/netsim_wrapper/templates/json.py b/netsim_wrapper/templates/json.py new file mode 100644 index 0000000..95c2c04 --- /dev/null +++ b/netsim_wrapper/templates/json.py @@ -0,0 +1,40 @@ +""" +Custom JSON class from Template Abstrat Factory +""" + +from json import load, dump + +from .template import TemplateAbstractFactory + + +class Json(TemplateAbstractFactory): + """ + Custom JSON class + """ + def __init__(self) -> None: + super(Json, self).__init__() + self.log.debug("class: {} initialize".format(__class__.__name__)) + + def load(self, fpath): + data = None + try: + self.log.debug("method: {}.{}".format(__class__.__name__, __class__.__module__)) + with open(fpath) as f: + data = load(f) + except EnvironmentError as e: + self.log.error("error while loading json file: {}".format(fpath)) + self.log.error(e) + return data + + def dump(self, fpath, template): + try: + self.log.debug("method: {}.{}".format(__class__.__name__, __class__.__module__)) + with open(fpath, "w") as f: + dump(template, f, indent=2) + self.log.info("please, find the file in: {}".format(fpath)) + except EnvironmentError as e: + self.log.error("error while creating json template") + self.log.error(e) + + def template(self, type): + return super().template(type) diff --git a/netsim_wrapper/templates/template.py b/netsim_wrapper/templates/template.py new file mode 100644 index 0000000..246aae3 --- /dev/null +++ b/netsim_wrapper/templates/template.py @@ -0,0 +1,74 @@ +from collections import OrderedDict +from ..common.log import Logger +from abc import abstractmethod, ABC +from logging import INFO + + +class BaseTemplate: + def __init__(self) -> None: + super(BaseTemplate, self).__init__() + self.log = Logger().log + self.log.debug("class: {} initialize".format(__class__.__name__)) + @property + def network_template(self): + template = OrderedDict() + template['nso-packages-path'] = '' # String + template['compile-neds'] = True # True/False + template['start-devices'] = True # True/False + template['add-to-nso'] = True # True/False + template['add-authgroup-to-nso'] = True # True/False + template['authgroup'] = OrderedDict() # Dict + template['authgroup']['type'] = 'custom' # local/system/custom + template['authgroup']['path'] = '' + template['device-mode'] = OrderedDict() + template['device-mode']['prefix-based'] = OrderedDict() + template['device-mode']['prefix-based'][''] = OrderedDict() + template['device-mode']['prefix-based']['']['count'] = 2 + template['device-mode']['prefix-based']['']['prefix'] = '' + template['load-day0-config'] = True # True/False + template['config-path'] = '' # String + template['config-files'] = [] + template['config-files'].append('') # each file path + template['config-files'].append('') + return template + + @property + def device_template(self): + template = OrderedDict() + template['nso-packages-path'] = '' # String + template['compile-neds'] = True # True/False + template['start-devices'] = True # True/False + template['add-to-nso'] = True # True/False + template['add-authgroup-to-nso'] = True # True/False + template['authgroup'] = OrderedDict() + template['authgroup']['type'] = 'custom' # local/system/custom + template['authgroup']['path'] = '' + template['device-mode'] = OrderedDict() + template['device-mode']['name-based'] = OrderedDict() + template['device-mode']['name-based'][''] = [] + template['device-mode']['name-based'][''].append('device1') + template['device-mode']['name-based'][''].append('device2') + template['load-day0-config'] = True # True/False + template['config-path'] = '' # config path + template['config-files'] = [] + template['config-files'].append('') # each file path + template['config-files'].append('') + return template + + +class TemplateAbstractFactory(ABC, BaseTemplate): + def __init__(self) -> None: + super(TemplateAbstractFactory, self).__init__() + self.log.debug("class: {} initialize".format(__class__.__name__)) + + @abstractmethod + def load(self, fpath):... + + @abstractmethod + def dump(self, fpath, template):... + + def template(self, type): + if type == 'network': + return self.network_template + if type == 'device': + return self.device_template diff --git a/netsim_wrapper/templates/xml.py b/netsim_wrapper/templates/xml.py new file mode 100644 index 0000000..8e80495 --- /dev/null +++ b/netsim_wrapper/templates/xml.py @@ -0,0 +1,37 @@ +import xml.etree.ElementTree as ET + +from .convert import object2xml, xml2dict +from .template import TemplateAbstractFactory + + +class Xml(TemplateAbstractFactory): + def __init__(self) -> None: + super(Xml, self).__init__() + self.log.debug("class: {} initialize".format(__class__.__name__)) + + + def load(self, fpath): + data = None + try: + self.log.debug("method: {}.{}".format(__class__.__name__, __class__.__module__)) + with ET.parse(fpath) as tree: + data = tree.getroot() + data = xml2dict(data) + except EnvironmentError as e: + self.log.error("error while loading xml file: {}".format(fpath)) + self.log.error(e) + return data + + def dump(self, fpath, template): + try: + self.log.debug("method: {}.{}".format(__class__.__name__, __class__.__module__)) + with open(fpath, 'w') as fp: + fp.write(template) + self.log.info("please, find the file in: {}".format(fpath)) + except EnvironmentError as e: + self.log.error("error on createing xml file") + self.log.error(e) + + def template(self, type): + temp = super().template(type) + return object2xml(temp) diff --git a/netsim_wrapper/templates/yaml.py b/netsim_wrapper/templates/yaml.py new file mode 100644 index 0000000..17fb1a5 --- /dev/null +++ b/netsim_wrapper/templates/yaml.py @@ -0,0 +1,49 @@ +""" +Custom YAML class from Template Abstrat Factory +""" + +from collections import OrderedDict +from yaml import add_representer, dump, load, FullLoader + +from .template import TemplateAbstractFactory + + +class Yaml(TemplateAbstractFactory): + """ + Custom YAML class + """ + def __init__(self) -> None: + super(Yaml, self).__init__() + self.log.debug("class: {} initialize".format(__class__.__name__)) + self._setup_yaml + + @property + def _setup_yaml(self): + represent_dict_order = lambda self, data: self.represent_mapping( + "tag:yaml.org,2002:map", data.items() + ) + add_representer(OrderedDict, represent_dict_order) + + def load(self, fpath): + data = None + try: + self.log.debug("method: {}.{}".format(__class__.__name__, __class__.__module__)) + with open(fpath) as f: + data = load(f, Loader=FullLoader) + except EnvironmentError as e: + self.log.error("error while loading yaml file {}".format(fpath)) + self.log.error(e) + return data + + def dump(self, fpath, template): + try: + self.log.debug("method: {}.{}".format(__class__.__name__, __class__.__module__)) + with open(fpath, "w") as f: + dump(template, f, sort_keys=False) + self.log.info("please, find the file in: {}".format(fpath)) + except EnvironmentError as e: + self.log.error("error while createing yaml template") + self.log.error(e) + + def template(self, type): + return super().template(type) diff --git a/netsim_wrapper/wrapper.py b/netsim_wrapper/wrapper.py new file mode 100644 index 0000000..e69de29