Example #1
0
    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
Example #2
0
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)
Example #3
0
    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)
Example #5
0
 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
Example #6
0
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)
Example #7
0
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)
Example #8
0
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)
Example #10
0
    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)
Example #11
0
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")
Example #12
0
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)
Example #14
0
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):
Example #15
0
 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
Example #16
0
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()
Example #17
0
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"
        },
    },
}