diff options
| author | John Estabrook <jestabro@vyos.io> | 2022-03-10 10:07:31 -0600 | 
|---|---|---|
| committer | John Estabrook <jestabro@vyos.io> | 2022-03-10 12:11:07 -0600 | 
| commit | c1e04cea0817db07b22a8bd8e6b2f2c0a1e682f4 (patch) | |
| tree | 3f238ec7e17d3ae895b8db1093c608ee488bc6e1 | |
| parent | ef4870e66f8c1cd6df5fba2abbfdde0eac152e0a (diff) | |
| download | vyos-1x-c1e04cea0817db07b22a8bd8e6b2f2c0a1e682f4.tar.gz vyos-1x-c1e04cea0817db07b22a8bd8e6b2f2c0a1e682f4.zip | |
Revert "component_version: T4291: consolidate read/write functions"
This reverts commit 534f677d36285863decb2cdff179687b4fd690cb.
Revert while investigating failure in vyos-configtest.
| -rw-r--r-- | python/vyos/component_version.py | 174 | ||||
| -rw-r--r-- | python/vyos/component_versions.py | 57 | ||||
| -rw-r--r-- | python/vyos/formatversions.py | 109 | ||||
| -rw-r--r-- | python/vyos/migrator.py | 26 | ||||
| -rw-r--r-- | python/vyos/systemversions.py | 46 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_component_version.py | 6 | ||||
| -rwxr-xr-x | src/helpers/system-versions-foot.py | 19 | 
7 files changed, 248 insertions, 189 deletions
| diff --git a/python/vyos/component_version.py b/python/vyos/component_version.py deleted file mode 100644 index b1554828d..000000000 --- a/python/vyos/component_version.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library.  If not, see <http://www.gnu.org/licenses/>. - -""" -Functions for reading/writing component versions. - -The config file version string has the following form: - -VyOS 1.3/1.4: - -// Warning: Do not remove the following line. -// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" -// Release version: 1.3.0 - -VyOS 1.2: - -/* Warning: Do not remove the following line. */ -/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pppoe-server@2:pptp@1:qos@1:quagga@7:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@2:zone-policy@1" === */ -/* Release version: 1.2.8 */ - -""" - -import os -import re -import sys -import fileinput -from vyos.xml import component_version -from vyos.version import get_version - -def from_string(string_line, vintage='vyos'): -    """ -    Get component version dictionary from string. -    Return empty dictionary if string contains no config information -    or raise error if component version string malformed. -    """ -    version_dict = {} - -    if vintage == 'vyos': -        if re.match(r'// vyos-config-version:.+', string_line): -            if not re.match(r'// vyos-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s*', string_line): -                raise ValueError(f"malformed configuration string: {string_line}") - -            for pair in re.findall(r'([\w,-]+)@(\d+)', string_line): -                version_dict[pair[0]] = int(pair[1]) - -    elif vintage == 'vyatta': -        if re.match(r'/\* === vyatta-config-version:.+=== \*/$', string_line): -            if not re.match(r'/\* === vyatta-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s+=== \*/$', string_line): -                raise ValueError(f"malformed configuration string: {string_line}") - -            for pair in re.findall(r'([\w,-]+)@(\d+)', string_line): -                version_dict[pair[0]] = int(pair[1]) -    else: -        raise ValueError("Unknown config string vintage") - -    return version_dict - -def from_file(config_file_name='/opt/vyatta/etc/config/config.boot', -                      vintage='vyos'): -    """ -    Get component version dictionary parsing config file line by line -    """ -    f = open(config_file_name, 'r') -    for line_in_config in f: -        version_dict = from_string(line_in_config, vintage=vintage) -        if version_dict: -            return version_dict - -    # no version information -    return {} - -def from_system(): -    """ -    Get system component version dict. -    """ -    return component_version() - -def legacy_from_system(): -    """ -    legacy function; imported as-is. - -    Get component versions from running system; critical failure if -    unable to read migration directory. -    """ -    import vyos.defaults - -    system_versions = {} - -    try: -        version_info = os.listdir(vyos.defaults.directories['current']) -    except OSError as err: -        print("OS error: {}".format(err)) -        sys.exit(1) - -    for info in version_info: -        if re.match(r'[\w,-]+@\d+', info): -            pair = info.split('@') -            system_versions[pair[0]] = int(pair[1]) - -    return system_versions - -def format_string(ver: dict) -> str: -    """ -    Version dict to string. -    """ -    keys = list(ver) -    keys.sort() -    l = [] -    for k in keys: -        v = ver[k] -        l.append(f'{k}@{v}') -    sep = ':' -    return sep.join(l) - -def system_footer(vintage='vyos') -> str: -    """ -    Version footer as string. -    """ -    ver_str = format_string(from_system()) -    release = get_version() -    if vintage == 'vyos': -        ret_str = (f'// Warning: Do not remove the following line.\n' -                +  f'// vyos-config-version: "{ver_str}"\n' -                +  f'// Release version: {release}\n') -    elif vintage == 'vyatta': -        ret_str = (f'/* Warning: Do not remove the following line. */\n' -                +  f'/* === vyatta-config-version: "{ver_str}" === */\n' -                +  f'/* Release version: {release} */\n') -    else: -        raise ValueError("Unknown config string vintage") - -    return ret_str - -def write_footer(file_name, vintage='vyos'): -    """ -    Write version footer to file. -    """ -    footer = system_footer(vintage=vintage) -    if file_name: -        with open(file_name, 'a') as f: -            f.write(footer) -    else: -        sys.stdout.write(footer) - -def remove_footer(file_name): -    """ -    Remove old version footer. -    """ -    for line in fileinput.input(file_name, inplace=True): -        if re.match(r'/\* Warning:.+ \*/$', line): -            continue -        if re.match(r'/\* === vyatta-config-version:.+=== \*/$', line): -            continue -        if re.match(r'/\* Release version:.+ \*/$', line): -            continue -        if re.match('// vyos-config-version:.+', line): -            continue -        if re.match('// Warning:.+', line): -            continue -        if re.match('// Release version:.+', line): -            continue -        sys.stdout.write(line) diff --git a/python/vyos/component_versions.py b/python/vyos/component_versions.py new file mode 100644 index 000000000..90b458aae --- /dev/null +++ b/python/vyos/component_versions.py @@ -0,0 +1,57 @@ +# Copyright 2017 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library.  If not, see <http://www.gnu.org/licenses/>. + +""" +The version data looks like: + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: +"cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@1:dhcp-server@4:firewall@5:ipsec@4:nat@4:qos@1:quagga@2:system@8:vrrp@1:wanloadbalance@3:webgui@1:webproxy@1:zone-policy@1" +=== */ +/* Release version: 1.2.0-rolling+201806131737 */ +""" + +import re + +def get_component_version(string_line): +    """ +    Get component version dictionary from string +    return empty dictionary if string contains no config information +    or raise error if component version string malformed +    """ +    return_value = {} +    if re.match(r'/\* === vyatta-config-version:.+=== \*/$', string_line): + +        if not re.match(r'/\* === vyatta-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s+=== \*/$', string_line): +            raise ValueError("malformed configuration string: " + str(string_line)) + +        for pair in re.findall(r'([\w,-]+)@(\d+)', string_line): +            if pair[0] in return_value.keys(): +                raise ValueError("duplicate unit name: \"" + str(pair[0]) + "\" in string: \"" + string_line + "\"") +            return_value[pair[0]] = int(pair[1]) + +    return return_value + + +def get_component_versions_from_file(config_file_name='/opt/vyatta/etc/config/config.boot'): +    """ +    Get component version dictionary parsing config file line by line +    """ +    f = open(config_file_name, 'r') +    for line_in_config in f: +        component_version = get_component_version(line_in_config) +        if component_version: +            return component_version +    raise ValueError("no config string in file:", config_file_name) diff --git a/python/vyos/formatversions.py b/python/vyos/formatversions.py new file mode 100644 index 000000000..29117a5d3 --- /dev/null +++ b/python/vyos/formatversions.py @@ -0,0 +1,109 @@ +# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library.  If not, see <http://www.gnu.org/licenses/>. + +import sys +import os +import re +import fileinput + +def read_vyatta_versions(config_file): +    config_file_versions = {} + +    with open(config_file, 'r') as config_file_handle: +        for config_line in config_file_handle: +            if re.match(r'/\* === vyatta-config-version:.+=== \*/$', config_line): +                if not re.match(r'/\* === vyatta-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s+=== \*/$', config_line): +                    raise ValueError("malformed configuration string: " +                            "{}".format(config_line)) + +                for pair in re.findall(r'([\w,-]+)@(\d+)', config_line): +                    config_file_versions[pair[0]] = int(pair[1]) + + +    return config_file_versions + +def read_vyos_versions(config_file): +    config_file_versions = {} + +    with open(config_file, 'r') as config_file_handle: +        for config_line in config_file_handle: +            if re.match(r'// vyos-config-version:.+', config_line): +                if not re.match(r'// vyos-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s*', config_line): +                    raise ValueError("malformed configuration string: " +                            "{}".format(config_line)) + +                for pair in re.findall(r'([\w,-]+)@(\d+)', config_line): +                    config_file_versions[pair[0]] = int(pair[1]) + +    return config_file_versions + +def remove_versions(config_file): +    """ +    Remove old version string. +    """ +    for line in fileinput.input(config_file, inplace=True): +        if re.match(r'/\* Warning:.+ \*/$', line): +            continue +        if re.match(r'/\* === vyatta-config-version:.+=== \*/$', line): +            continue +        if re.match(r'/\* Release version:.+ \*/$', line): +            continue +        if re.match('// vyos-config-version:.+', line): +            continue +        if re.match('// Warning:.+', line): +            continue +        if re.match('// Release version:.+', line): +            continue +        sys.stdout.write(line) + +def format_versions_string(config_versions): +    cfg_keys = list(config_versions.keys()) +    cfg_keys.sort() + +    component_version_strings = [] + +    for key in cfg_keys: +        cfg_vers = config_versions[key] +        component_version_strings.append('{}@{}'.format(key, cfg_vers)) + +    separator = ":" +    component_version_string = separator.join(component_version_strings) + +    return component_version_string + +def write_vyatta_versions_foot(config_file, component_version_string, +                                 os_version_string): +    if config_file: +        with open(config_file, 'a') as config_file_handle: +            config_file_handle.write('/* Warning: Do not remove the following line. */\n') +            config_file_handle.write('/* === vyatta-config-version: "{}" === */\n'.format(component_version_string)) +            config_file_handle.write('/* Release version: {} */\n'.format(os_version_string)) +    else: +        sys.stdout.write('/* Warning: Do not remove the following line. */\n') +        sys.stdout.write('/* === vyatta-config-version: "{}" === */\n'.format(component_version_string)) +        sys.stdout.write('/* Release version: {} */\n'.format(os_version_string)) + +def write_vyos_versions_foot(config_file, component_version_string, +                               os_version_string): +    if config_file: +        with open(config_file, 'a') as config_file_handle: +            config_file_handle.write('// Warning: Do not remove the following line.\n') +            config_file_handle.write('// vyos-config-version: "{}"\n'.format(component_version_string)) +            config_file_handle.write('// Release version: {}\n'.format(os_version_string)) +    else: +        sys.stdout.write('// Warning: Do not remove the following line.\n') +        sys.stdout.write('// vyos-config-version: "{}"\n'.format(component_version_string)) +        sys.stdout.write('// Release version: {}\n'.format(os_version_string)) + diff --git a/python/vyos/migrator.py b/python/vyos/migrator.py index 266a2e58e..a2e0daabd 100644 --- a/python/vyos/migrator.py +++ b/python/vyos/migrator.py @@ -17,8 +17,10 @@ import sys  import os  import json  import subprocess +import vyos.version  import vyos.defaults -import vyos.component_version as component_version +import vyos.systemversions as systemversions +import vyos.formatversions as formatversions  class MigratorError(Exception):      pass @@ -40,13 +42,13 @@ class Migrator(object):          cfg_file = self._config_file          component_versions = {} -        cfg_versions = component_version.from_file(cfg_file, vintage='vyatta') +        cfg_versions = formatversions.read_vyatta_versions(cfg_file)          if cfg_versions:              self._config_file_vintage = 'vyatta'              component_versions = cfg_versions -        cfg_versions = component_version.from_file(cfg_file, vintage='vyos') +        cfg_versions = formatversions.read_vyos_versions(cfg_file)          if cfg_versions:              self._config_file_vintage = 'vyos' @@ -150,11 +152,19 @@ class Migrator(object):          """          Write new versions string.          """ +        versions_string = formatversions.format_versions_string(cfg_versions) + +        os_version_string = vyos.version.get_version() +          if self._config_file_vintage == 'vyatta': -            component_version.write_footer(self._config_file, vintage='vyatta') +            formatversions.write_vyatta_versions_foot(self._config_file, +                                                      versions_string, +                                                      os_version_string)          if self._config_file_vintage == 'vyos': -            component_version.write_footer(self._config_file, vintage='vyos') +            formatversions.write_vyos_versions_foot(self._config_file, +                                                    versions_string, +                                                    os_version_string)      def save_json_record(self, component_versions: dict):          """ @@ -185,7 +195,7 @@ class Migrator(object):              # This will force calling all migration scripts:              cfg_versions = {} -        sys_versions = component_version.from_system() +        sys_versions = systemversions.get_system_component_version()          # save system component versions in json file for easy reference          self.save_json_record(sys_versions) @@ -201,7 +211,7 @@ class Migrator(object):          if not self._changed:              return -        component_version.remove_footer(cfg_file) +        formatversions.remove_versions(cfg_file)          self.write_config_file_versions(rev_versions) @@ -222,7 +232,7 @@ class VirtualMigrator(Migrator):          if not self._changed:              return -        component_version.remove_footer(cfg_file) +        formatversions.remove_versions(cfg_file)          self.write_config_file_versions(cfg_versions) diff --git a/python/vyos/systemversions.py b/python/vyos/systemversions.py new file mode 100644 index 000000000..f2da76d4f --- /dev/null +++ b/python/vyos/systemversions.py @@ -0,0 +1,46 @@ +# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library.  If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import sys +import vyos.defaults +from vyos.xml import component_version + +# legacy version, reading from the file names in +# /opt/vyatta/etc/config-migrate/current +def get_system_versions(): +    """ +    Get component versions from running system; critical failure if +    unable to read migration directory. +    """ +    system_versions = {} + +    try: +        version_info = os.listdir(vyos.defaults.directories['current']) +    except OSError as err: +        print("OS error: {}".format(err)) +        sys.exit(1) + +    for info in version_info: +        if re.match(r'[\w,-]+@\d+', info): +            pair = info.split('@') +            system_versions[pair[0]] = int(pair[1]) + +    return system_versions + +# read from xml cache +def get_system_component_version(): +    return component_version() diff --git a/smoketest/scripts/cli/test_component_version.py b/smoketest/scripts/cli/test_component_version.py index 21cc1c761..777379bdd 100755 --- a/smoketest/scripts/cli/test_component_version.py +++ b/smoketest/scripts/cli/test_component_version.py @@ -16,7 +16,7 @@  import unittest -from vyos.component_version import legacy_from_system, from_system +from vyos.systemversions import get_system_versions, get_system_component_version  # After T3474, component versions should be updated in the files in  # vyos-1x/interface-definitions/include/version/ @@ -24,8 +24,8 @@ from vyos.component_version import legacy_from_system, from_system  # that in the xml cache.  class TestComponentVersion(unittest.TestCase):      def setUp(self): -        self.legacy_d = legacy_from_system() -        self.xml_d = from_system() +        self.legacy_d = get_system_versions() +        self.xml_d = get_system_component_version()      def test_component_version(self):          self.assertTrue(set(self.legacy_d).issubset(set(self.xml_d))) diff --git a/src/helpers/system-versions-foot.py b/src/helpers/system-versions-foot.py index b44408542..2aa687221 100755 --- a/src/helpers/system-versions-foot.py +++ b/src/helpers/system-versions-foot.py @@ -16,13 +16,24 @@  # along with this library.  If not, see <http://www.gnu.org/licenses/>.  import sys +import vyos.formatversions as formatversions +import vyos.systemversions as systemversions  import vyos.defaults -from vyos.component_version import write_footer +import vyos.version + +sys_versions = systemversions.get_system_component_version() + +component_string = formatversions.format_versions_string(sys_versions) + +os_version_string = vyos.version.get_version()  sys.stdout.write("\n\n")  if vyos.defaults.cfg_vintage == 'vyos': -    write_footer(None, vintage='vyos') +    formatversions.write_vyos_versions_foot(None, component_string, +                                            os_version_string)  elif vyos.defaults.cfg_vintage == 'vyatta': -    write_footer(None, vintage='vyatta') +    formatversions.write_vyatta_versions_foot(None, component_string, +                                              os_version_string)  else: -    write_footer(None, vintage='vyatta') +    formatversions.write_vyatta_versions_foot(None, component_string, +                                              os_version_string) | 
