def __init__(self, dm: DataModel, rule_lists: List[NacmRuleList]): self.root = [] # type: List[RuleTreeNode] for rl in rule_lists: for rule in filter(lambda r: r.type == NacmRuleType.NACM_RULE_DATA, rl.rules): try: ii = dm.parse_instance_id(rule.type_data.path) except NonexistentSchemaNode as e: error(epretty(e, __name__)) ii = [] nl = self.root node_match_prev = None for isel in ii: node_match = (list(filter(lambda x: x.isel == isel, nl)) or [None])[0] if node_match is None: new_elem = RuleTreeNode() new_elem.isel = isel new_elem.up = node_match_prev if isel is ii[-1]: new_elem.rule = rule nl.append(new_elem) node_match_prev = new_elem nl = new_elem.children else: if isel is ii[-1]: node_match.rule = rule node_match_prev = node_match nl = node_match.children
def get_data_model(model_name: str) -> DataModel: lib = ntc_rosetta_yang.OPENCONFIG_LIB path = ntc_rosetta_yang.OPENCONFIG_PATH with open(lib, "r") as f: lib_data = json.load(f) extra_modules = [ { "name": "ietf-yang-library", "revision": "2016-06-21", "conformance-type": "implement", }, { "name": "ntc-rosetta-conf", "revision": "2019-06-26", "conformance-type": "implement", }, ] lib_data["ietf-yang-library:modules-state"]["module"].extend(extra_modules) path.append(pathlib.Path(__file__).parent.joinpath("yang")) tmp_file = pathlib.Path(tempfile.gettempdir()).joinpath(str(uuid.uuid4())) with open(tmp_file, "w") as f: json.dump(lib_data, f) return DataModel.from_file(tmp_file, path)
def __init__( self, dm: DataModel, candidate: Dict[str, Any], running: Optional[Dict[str, Any]] = None, replace: bool = False, ) -> None: n = dm.from_raw(candidate) if running is not None: o = dm.from_raw(running) else: o = None super().__init__( None, None, instance.InstanceRoute(), dm, dm.schema, {}, n, o, replace )
def _get_ntc_data_model() -> DataModel: base = pathlib.Path(__file__).parent lib = f"{base}/ntc-yang-models/models/ntc-models-library.json" path = [ base.joinpath("ntc-yang-models/models/arp"), base.joinpath("ntc-yang-models/models/ietf"), base.joinpath("ntc-yang-models/models/system"), base.joinpath("ntc-yang-models/models/types"), base.joinpath("ntc-yang-models/models/vlan"), base.joinpath("ntc-yang-models/models/vrf"), ] return DataModel.from_file(lib, path)
def _extract_shema(dm: DataModel, path: str) -> schemanode.SchemaNode: try: schema = dm.get_schema_node(path) if not schema: raise LinterException( Message( f"Yangify.path couldn't be found in model: {path}", MessageType.SCHEMA_NOT_FOUND, ) ) except InvalidSchemaPath: raise LinterException( Message(f"Yangify.path is invalid: {path}", MessageType.SCHEMA_INVALID) ) except Exception: raise return schema
def _get_openconfig_data_model() -> DataModel: base = pathlib.Path(__file__).parent lib = f"{base}/openconfig.json" path = [ base.joinpath("YangModels/standard/ietf/RFC"), base.joinpath("openconfig/release/models"), base.joinpath("openconfig/release/models/acl"), base.joinpath("openconfig/release/models/aft"), base.joinpath("openconfig/release/models/bgp"), base.joinpath("openconfig/release/models/interfaces"), base.joinpath("openconfig/release/models/isis"), base.joinpath("openconfig/release/models/mpls"), base.joinpath("openconfig/release/models/multicast"), base.joinpath("openconfig/release/models/network-instance"), base.joinpath("openconfig/release/models/local-routing"), base.joinpath("openconfig/release/models/ospf"), base.joinpath("openconfig/release/models/policy"), base.joinpath("openconfig/release/models/policy-forwarding"), base.joinpath("openconfig/release/models/rib"), base.joinpath("openconfig/release/models/segment-routing"), base.joinpath("openconfig/release/models/types"), base.joinpath("openconfig/release/models/vlan"), ] return DataModel.from_file(lib, path)
def obj_from_raw(library: str, paths: List[str], raw: Dict[str, Any]) -> instance.RootNode: dm = DataModel.from_file(library, paths) return dm.from_raw(raw)
from yangify import parser from yangify.parser.text_tree import parse_indented_config from yangson.datamodel import DataModel from yangson.exceptions import SchemaError from yangson.exceptions import SemanticError LIB = "../yang/yang-library-data.json" MODELS = [ "../yang/yang-modules/ietf", "../yang/yang-modules/openconfig", "../yang/yang-modules/ntc", ] dm = DataModel.from_file(LIB, MODELS) class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = {} self.root_native["show run"] = parse_indented_config( self.native["show run"].splitlines()) self.root_native["lldp_data"] = self.native["lldp_data"] self.native = self.root_native parser = argparse.ArgumentParser( description="Yangify parser Tutorial. Use at least one of the options." ) parser.add_argument("--vlans",
def __init__(self, data_model: DataModel, schema_path: str): self.data_model = data_model self.sch_pth = schema_path self.schema_node = data_model.get_data_node(self.sch_pth)
def init(self): # Create pidfile self.fl = os.open(self.config.glob["PIDFILE"], os.O_WRONLY + os.O_CREAT, 0o666) try: os.lockf(self.fl, os.F_TLOCK, 0) os.write(self.fl, str(os.getpid()).encode()) os.fsync(self.fl) except BlockingIOError: os.close(self.fl) self.fl = -1 raise JetconfInitError("Jetconf already running (pidfile exists)") # Import backend modules backend_package = self.config.glob["BACKEND_PACKAGE"] try: _be_installed = import_module(backend_package) del _be_installed except ImportError as e: raise JetconfInitError( "Cannot import backend package \"{}\", reason: {}".format( backend_package, ErrorHelpers.epretty(e))) try: usr_state_data_handlers = import_module(backend_package + ".usr_state_data_handlers") except ImportError: usr_state_data_handlers = None try: usr_conf_data_handlers = import_module(backend_package + ".usr_conf_data_handlers") except ImportError: usr_conf_data_handlers = None try: usr_op_handlers = import_module(backend_package + ".usr_op_handlers") except ImportError: usr_op_handlers = None try: usr_action_handlers = import_module(backend_package + ".usr_action_handlers") except ImportError: usr_action_handlers = None try: usr_datastore = import_module(backend_package + ".usr_datastore") except ImportError: usr_datastore = None try: self.usr_init = import_module(backend_package + ".usr_init") except ImportError: self.usr_init = None # Load data model yang_mod_dir = self.config.glob["YANG_LIB_DIR"] yang_lib_str = resource_string( backend_package, "yang-library-data.json").decode("utf-8") try: datamodel = DataModel(yang_lib_str, [yang_mod_dir]) except ModuleNotFound as e: raise JetconfInitError( "Cannot find YANG module \"{} ({})\" in YANG library".format( e.name, e.rev)) # Datastore init datastore = usr_datastore.UserDatastore( datamodel, self.config.glob["DATA_JSON_FILE"], with_nacm=self.config.nacm["ENABLED"]) self.datastore = datastore try: datastore.load() except (FileNotFoundError, YangsonException) as e: raise JetconfInitError( "Cannot load JSON data file \"{}\", reason: {}".format( self.config.glob["DATA_JSON_FILE"], ErrorHelpers.epretty(e))) # Validate datastore on startup try: datastore.get_data_root().validate(ValidationScope.all, ContentType.config) except (SchemaError, SemanticError) as e: raise JetconfInitError( "Initial validation of datastore failed, reason: {}".format( ErrorHelpers.epretty(e))) # Register handlers for configuration data if usr_conf_data_handlers is not None: usr_conf_data_handlers.register_conf_handlers(datastore) # Register handlers for state data if usr_state_data_handlers is not None: usr_state_data_handlers.register_state_handlers(datastore) # Register handlers for operations op_internal.register_op_handlers(datastore) if usr_op_handlers is not None: usr_op_handlers.register_op_handlers(datastore) # Register handlers for actions if usr_action_handlers is not None: usr_action_handlers.register_action_handlers(datastore) # Init backend package if self.usr_init is not None: try: self.usr_init.jc_startup() self.backend_initiated = True except Exception as e: raise JetconfInitError( "Backend initialization failed, reason: {}".format( ErrorHelpers.epretty(e))) # Create HTTP server self.rest_srv = RestServer() self.rest_srv.register_api_handlers(datastore)
import json from yangson.datamodel import DataModel MODULE_DIR = "yang-data" YANG_LIBRARY = "yang-library-data.json" DATA_FILE = "data.json" with open(YANG_LIBRARY) as ylfile: yl = ylfile.read() dm = DataModel(yl, [MODULE_DIR]) with open(DATA_FILE, "rt") as fp: json_data = dm.from_raw(json.load(fp)) json_data.validate() print("end")
from yangson.datamodel import DataModel from yangson.instance import InstanceRoute module_dir = "../yang-data/" yang_library_file = "../yang-data/yang-library-data.json" with open(yang_library_file) as ylfile: yl = ylfile.read() dm = DataModel(yl, [module_dir]) with open("data.json", "rt") as fp: json_data = dm.from_raw(json.load(fp)) handler_sn = dm.get_data_node("/dns-server:dns-server-state/zone") handler_generated = [{ 'domain': 'example.com', 'class': 'IN', 'server-role': 'master', 'serial': 2010111201 }] cooked_val = handler_sn.from_raw(handler_generated) ii_str_abs = "/dns-server:dns-server-state/zone=example.com/class" ii_abs = dm.parse_resource_id(ii_str_abs) print("Absolute II: {}".format(ii_abs)) ii_rel = InstanceRoute(ii_abs[2:]) print("Relative II (hardcoded for now): {}".format(ii_rel)) handler_n = handler_sn.orphan_instance(cooked_val)
def _get_openconfig_data_model() -> DataModel: return DataModel.from_file(OPENCONFIG_LIB, OPENCONFIG_PATH)
import pytest from yangify import parser, translator from yangify.parser.text_tree import parse_indented_config from yangify.translator.config_tree import ConfigTree from yangson.datamodel import DataModel logging_format = ( "%(asctime)s - %(name)30s - %(levelname)8s - %(funcName)20s() - %(message)s" ) logging.basicConfig(format=logging_format, level=logging.ERROR) BASE = pathlib.Path(__file__).parent dm = DataModel.from_file(f"{BASE}/../impl/yang-library-data.json", [f"{BASE}/../impl/yang-modules"]) class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = parse_indented_config( self.root_native.splitlines()) self.native = self.root_native interfaces = ios_if_parser.Interfaces vlans = ios_vlans_parser.Vlans class JunosParser(parser.RootParser): class Yangify(parser.ParserData):
def load_data_model(module_dir: str, yang_library_file: str) -> DataModel: with open(yang_library_file) as ylfile: yl = ylfile.read() dm = DataModel(yl, [module_dir]) return dm
def main(): config_file = "config.yaml" # Check for Python version if sys.version_info < (3, 5): print("Jetconf requires Python version 3.5 or higher") sys.exit(1) # Get Jetconf version jetconf_version = get_distribution("jetconf").version # Parse command line arguments try: opts, args = getopt.getopt(sys.argv[1:], "c:vh") except getopt.GetoptError: print("Error: invalid argument detected.") print_help() sys.exit(1) for opt, arg in opts: if opt == "-c": config_file = arg elif opt == "-v": print("Jetconf version {}".format(jetconf_version)) sys.exit(0) elif opt == "-h": print_help() sys.exit(0) # Load configuration try: load_config(config_file) except FileNotFoundError: print("Configuration file does not exist") sys.exit(1) except ParserError as e: print("Configuration syntax error: " + str(e)) sys.exit(1) # Validate configuration try: validate_config() except ValueError as e: print("Error: " + str(e)) sys.exit(1) # Set logging level log_level = { "error": logging.ERROR, "warning": logging.WARNING, "info": logging.INFO, "debug": logging.INFO }.get(CONFIG_GLOBAL["LOG_LEVEL"], logging.INFO) logging.root.handlers.clear() # Daemonize if CONFIG_GLOBAL["LOGFILE"] not in ("-", "stdout"): # Setup basic logging logging.basicConfig(format="%(asctime)s %(levelname)-8s %(message)s", level=log_level, filename=CONFIG_GLOBAL["LOGFILE"]) # Go to background pid = os.fork() if pid != 0: sys.exit(0) os.setsid() os.umask(0) pid = os.fork() if pid != 0: sys.exit(0) # Close standard file descriptors os.close(sys.stdin.fileno()) os.close(sys.stdout.fileno()) os.close(sys.stderr.fileno()) fd_null = os.open("/dev/null", os.O_RDWR) os.dup(fd_null) os.dup(fd_null) else: # Setup color logging log_formatter = colorlog.ColoredFormatter( "%(asctime)s %(log_color)s%(levelname)-8s%(reset)s %(message)s", datefmt=None, reset=True, log_colors={ 'DEBUG': 'cyan', 'INFO': 'green', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'red', }, secondary_log_colors={}, style='%') log_handler = colorlog.StreamHandler() log_handler.setFormatter(log_formatter) log_handler.stream = sys.stdout logger = colorlog.getLogger() logger.addHandler(log_handler) logger.setLevel(log_level) # Print version info("Jetconf version {}".format(jetconf_version)) # Print configuration print_config() # Create pidfile fl = os.open(CONFIG_GLOBAL["PIDFILE"], os.O_WRONLY + os.O_CREAT, 0o666) try: os.lockf(fl, os.F_TLOCK, 0) os.write(fl, str(os.getpid()).encode()) os.fsync(fl) except BlockingIOError: error("Jetconf daemon already running (pidfile exists). Exiting.") sys.exit(1) # Set signal handlers def sig_exit_handler(signum, frame): os.close(fl) os.unlink(CONFIG_GLOBAL["PIDFILE"]) info("Exiting.") sys.exit(0) signal.signal(signal.SIGTERM, sig_exit_handler) signal.signal(signal.SIGINT, sig_exit_handler) # Import backend modules backend_package = CONFIG_GLOBAL["BACKEND_PACKAGE"] try: usr_state_data_handlers = import_module(backend_package + ".usr_state_data_handlers") usr_conf_data_handlers = import_module(backend_package + ".usr_conf_data_handlers") usr_op_handlers = import_module(backend_package + ".usr_op_handlers") usr_datastore = import_module(backend_package + ".usr_datastore") except ImportError as e: error(ErrorHelpers.epretty(e)) error("Cannot import backend package \"{}\". Exiting.".format( backend_package)) sys.exit(1) # Load data model yang_mod_dir = CONFIG_GLOBAL["YANG_LIB_DIR"] yang_lib_str = resource_string(backend_package, "yang-library-data.json").decode("utf-8") datamodel = DataModel(yang_lib_str, [yang_mod_dir]) # Datastore init datastore = usr_datastore.UserDatastore(datamodel, CONFIG_GLOBAL["DATA_JSON_FILE"], with_nacm=CONFIG_NACM["ENABLED"]) try: datastore.load() except (FileNotFoundError, YangsonException) as e: error("Could not load JSON datastore " + CONFIG_GLOBAL["DATA_JSON_FILE"]) error(ErrorHelpers.epretty(e)) sig_exit_handler(0, None) # Validate datastore on startup try: datastore.get_data_root().validate(ValidationScope.all, ContentType.config) except (SchemaError, SemanticError) as e: error("Initial validation of datastore failed") error(ErrorHelpers.epretty(e)) sig_exit_handler(0, None) # Register handlers for configuration data usr_conf_data_handlers.register_conf_handlers(datastore) # Register handlers for state data usr_state_data_handlers.register_state_handlers(datastore) # Register handlers for operations op_internal.register_op_handlers(datastore) usr_op_handlers.register_op_handlers(datastore) # Create HTTP server rest_srv = RestServer() rest_srv.register_api_handlers(datastore) rest_srv.register_static_handlers() # Run HTTP server rest_srv.run()
import pathlib from typing import Any, Dict, Iterator, Tuple, cast from yangify import parser from yangson.datamodel import DataModel BASE = pathlib.Path(__file__).parent dm = DataModel.from_file(f"{BASE}/yang/simple/yang-library-data.json", [f"{BASE}/yang/simple/"]) test_data = { "element1": { "config": { "description": "this is element1.config.description" }, "state": { "description": "this is element1.state.description" }, }, "element2": { "config": { "description": "this is element2.config.description" }, "state": { "description": "this is element2.state.description" }, }, }