diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | python/vyos/defaults.py | 2 | ||||
-rw-r--r-- | python/vyos/systemversions.py | 28 | ||||
-rw-r--r-- | schema/interface_definition.rnc | 17 | ||||
-rw-r--r-- | schema/interface_definition.rng | 18 | ||||
-rwxr-xr-x | scripts/build-command-templates | 2 | ||||
-rwxr-xr-x | scripts/build-component-versions | 47 |
7 files changed, 119 insertions, 3 deletions
@@ -1,6 +1,7 @@ TMPL_DIR := templates-cfg OP_TMPL_DIR := templates-op BUILD_DIR := build +DATA_DIR := data CFLAGS := src = $(wildcard interface-definitions/*.xml.in) @@ -77,8 +78,13 @@ op_mode_definitions: rm -f $(OP_TMPL_DIR)/reset/vpn/node.def rm -f $(OP_TMPL_DIR)/show/system/node.def +.PHONY: component_versions +.ONESHELL: +component_versions: $(BUILD_DIR) $(obj) + $(CURDIR)/scripts/build-component-versions $(BUILD_DIR)/interface-definitions $(DATA_DIR) + .PHONY: all -all: clean interface_definitions op_mode_definitions +all: clean interface_definitions op_mode_definitions component_versions .PHONY: clean clean: diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py index dedb929b4..a2ad142bc 100644 --- a/python/vyos/defaults.py +++ b/python/vyos/defaults.py @@ -29,6 +29,8 @@ cfg_vintage = 'vyatta' commit_lock = '/opt/vyatta/config/.lock' +version_file = '/usr/share/vyos/component-versions.json' + https_data = { 'listen_addresses' : { '*': ['_'] } } diff --git a/python/vyos/systemversions.py b/python/vyos/systemversions.py index 9b3f4f413..5c4deca29 100644 --- a/python/vyos/systemversions.py +++ b/python/vyos/systemversions.py @@ -16,12 +16,15 @@ import os import re import sys +import json + import vyos.defaults def get_system_versions(): """ - Get component versions from running system; critical failure if - unable to read migration directory. + Get component versions from running system: read vyatta directory + structure for versions, then read vyos JSON file. It is a critical + error if either migration directory or JSON file is unreadable. """ system_versions = {} @@ -36,4 +39,25 @@ def get_system_versions(): pair = info.split('@') system_versions[pair[0]] = int(pair[1]) + version_dict = {} + path = vyos.defaults.version_file + + if os.path.isfile(path): + with open(path, 'r') as f: + try: + version_dict = json.load(f) + except ValueError as err: + print(f"\nValue error in {path}: {err}") + sys.exit(1) + + for k, v in version_dict.items(): + if not isinstance(v, int): + print(f"\nType error in {path}; expecting Dict[str, int]") + sys.exit(1) + existing = system_versions.get(k) + if existing is None: + system_versions[k] = v + elif v > existing: + system_versions[k] = v + return system_versions diff --git a/schema/interface_definition.rnc b/schema/interface_definition.rnc index 02175fec8..0ce8226cd 100644 --- a/schema/interface_definition.rnc +++ b/schema/interface_definition.rnc @@ -24,9 +24,16 @@ # Interface definition starts with interfaceDefinition tag that may contain node tags start = element interfaceDefinition { + syntaxVersion*, node* } +# interfaceDefinition may contain syntax version attribute lists. +syntaxVersion = element syntaxVersion +{ + (componentAttr & versionAttr) +} + # node tag may contain node, leafNode, or tagNode tags # Those are intermediate configuration nodes that may only contain # other nodes and must not have values @@ -97,6 +104,16 @@ properties = element properties (element keepChildOrder { empty })? } +componentAttr = attribute component +{ + text +} + +versionAttr = attribute version +{ + text +} + # All nodes must have "name" attribute nodeNameAttr = attribute name { diff --git a/schema/interface_definition.rng b/schema/interface_definition.rng index 195ef27f4..bfd8d376f 100644 --- a/schema/interface_definition.rng +++ b/schema/interface_definition.rng @@ -29,10 +29,22 @@ <start> <element name="interfaceDefinition"> <zeroOrMore> + <ref name="syntaxVersion"/> + </zeroOrMore> + <zeroOrMore> <ref name="node"/> </zeroOrMore> </element> </start> + <!-- interfaceDefinition may contain syntax version attribute lists. --> + <define name="syntaxVersion"> + <element name="syntaxVersion"> + <interleave> + <ref name="componentAttr"/> + <ref name="versionAttr"/> + </interleave> + </element> + </define> <!-- node tag may contain node, leafNode, or tagNode tags Those are intermediate configuration nodes that may only contain @@ -184,6 +196,12 @@ </interleave> </element> </define> + <define name="componentAttr"> + <attribute name="component"/> + </define> + <define name="versionAttr"> + <attribute name="version"/> + </define> <!-- All nodes must have "name" attribute --> <define name="nodeNameAttr"> <attribute name="name"/> diff --git a/scripts/build-command-templates b/scripts/build-command-templates index 4fcdb8ade..dbf4ad9c5 100755 --- a/scripts/build-command-templates +++ b/scripts/build-command-templates @@ -295,4 +295,6 @@ root = xml.getroot() nodes = root.iterfind("*") for n in nodes: + if n.tag == "syntaxVersion": + continue process_node(n, [output_dir]) diff --git a/scripts/build-component-versions b/scripts/build-component-versions new file mode 100755 index 000000000..5362dbdd4 --- /dev/null +++ b/scripts/build-component-versions @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import sys +import os +import argparse +import json + +from lxml import etree as ET + +parser = argparse.ArgumentParser() +parser.add_argument('INPUT_DIR', type=str, + help="Directory containing XML interface definition files") +parser.add_argument('OUTPUT_DIR', type=str, + help="Output directory for JSON file") + +args = parser.parse_args() + +input_dir = args.INPUT_DIR +output_dir = args.OUTPUT_DIR + +version_dict = {} + +for filename in os.listdir(input_dir): + filepath = os.path.join(input_dir, filename) + print(filepath) + try: + xml = ET.parse(filepath) + except Exception as e: + print("Failed to load interface definition file {0}".format(filename)) + print(e) + sys.exit(1) + + root = xml.getroot() + version_data = root.iterfind("syntaxVersion") + for ver in version_data: + component = ver.get("component") + version = int(ver.get("version")) + + v = version_dict.get(component) + if v is None: + version_dict[component] = version + elif version > v: + version_dict[component] = version + +out_file = os.path.join(output_dir, 'component-versions.json') +with open(out_file, 'w') as f: + json.dump(version_dict, f, indent=4, sort_keys=True) |