diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/op_mode/cpu.py | 82 | ||||
| -rwxr-xr-x | src/op_mode/cpu_summary.py | 48 | ||||
| -rwxr-xr-x | src/op_mode/memory.py (renamed from src/op_mode/show_ram.py) | 39 | ||||
| -rwxr-xr-x | src/op_mode/neighbor.py (renamed from src/op_mode/show_neigh.py) | 60 | ||||
| -rw-r--r-- | src/op_mode/route.py | 98 | ||||
| -rwxr-xr-x | src/op_mode/show_cpu.py | 72 | ||||
| -rwxr-xr-x | src/op_mode/version.py (renamed from src/op_mode/show_version.py) | 52 | 
7 files changed, 279 insertions, 172 deletions
| diff --git a/src/op_mode/cpu.py b/src/op_mode/cpu.py new file mode 100755 index 000000000..f9c425826 --- /dev/null +++ b/src/op_mode/cpu.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2016-2022 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +import sys + +import vyos.cpu +import vyos.opmode + +from jinja2 import Template + +cpu_template = Template(""" +{% for cpu in cpus %} +{% if 'physical id' in cpu %}CPU socket: {{cpu['physical id']}}{% endif %} +{% if 'vendor_id' in cpu %}CPU Vendor:       {{cpu['vendor_id']}}{% endif %} +{% if 'model name' in cpu %}Model:            {{cpu['model name']}}{% endif %} +{% if 'cpu cores' in cpu %}Cores:            {{cpu['cpu cores']}}{% endif %} +{% if 'cpu MHz' in cpu %}Current MHz:      {{cpu['cpu MHz']}}{% endif %} +{% endfor %} +""") + +cpu_summary_template = Template(""" +Physical CPU cores: {{count}} +CPU model(s): {{models | join(", ")}} +""") + +def _get_raw_data(): +    return vyos.cpu.get_cpus() + +def _format_cpus(cpu_data): +    env = {'cpus': cpu_data} +    return cpu_template.render(env).strip() + +def _get_summary_data(): +    count = vyos.cpu.get_core_count() +    cpu_data = vyos.cpu.get_cpus() +    models = [c['model name'] for c in cpu_data] +    env = {'count': count, "models": models} + +    return env + +def _format_cpu_summary(summary_data): +    return cpu_summary_template.render(summary_data).strip() + +def show(raw: bool): +    cpu_data = _get_raw_data() + +    if raw: +        return cpu_data +    else: +        return _format_cpus(cpu_data) + +def show_summary(raw: bool): +    cpu_summary_data = _get_summary_data() + +    if raw: +        return cpu_summary_data +    else: +        return _format_cpu_summary(cpu_summary_data) + + +if __name__ == '__main__': +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except ValueError as e: +        print(e) +        sys.exit(1) + diff --git a/src/op_mode/cpu_summary.py b/src/op_mode/cpu_summary.py deleted file mode 100755 index 3bdf5a718..000000000 --- a/src/op_mode/cpu_summary.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018-2022 VyOS maintainers and contributors -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 or later as -# published by the Free Software Foundation. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. - -import re -from vyos.util import colon_separated_to_dict - -FILE_NAME = '/proc/cpuinfo' - -def get_raw_data(): -    with open(FILE_NAME, 'r') as f: -        data_raw = f.read() - -    data = colon_separated_to_dict(data_raw) - -    # Accumulate all data in a dict for future support for machine-readable output -    cpu_data = {} -    cpu_data['cpu_number'] = len(data['processor']) -    cpu_data['models'] = list(set(data['model name'])) - -    # Strip extra whitespace from CPU model names, /proc/cpuinfo is prone to that -    cpu_data['models'] = list(map(lambda s: re.sub(r'\s+', ' ', s), cpu_data['models'])) - -    return cpu_data - -def get_formatted_output(): -    cpu_data = get_raw_data() - -    out = "CPU(s): {0}\n".format(cpu_data['cpu_number']) -    out += "CPU model(s): {0}".format(",".join(cpu_data['models'])) - -    return out - -if __name__ == '__main__': -    print(get_formatted_output()) - diff --git a/src/op_mode/show_ram.py b/src/op_mode/memory.py index 2b0be3965..a3870e498 100755 --- a/src/op_mode/show_ram.py +++ b/src/op_mode/memory.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2022 VyOS maintainers and contributors +# Copyright (C) 2021-2022 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -15,7 +15,12 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  # -def get_system_memory(): +import sys + +import vyos.opmode + + +def _get_system_memory():      from re import search as re_search      def find_value(keyword, mem_data): @@ -43,10 +48,10 @@ def get_system_memory():      return res -def get_system_memory_human(): +def _get_system_memory_human():      from vyos.util import bytes_to_human -    mem = get_system_memory() +    mem = _get_system_memory()      for key in mem:          # The Linux kernel exposes memory values in kilobytes, @@ -55,17 +60,31 @@ def get_system_memory_human():      return mem -def get_raw_data(): -    return get_system_memory_human() - -def get_formatted_output(): -    mem = get_raw_data() +def _get_raw_data(): +    return _get_system_memory_human() +def _get_formatted_output(mem):      out = "Total: {}\n".format(mem["total"])      out += "Free:  {}\n".format(mem["free"])      out += "Used:  {}".format(mem["used"])      return out +def show(raw: bool): +    ram_data = _get_raw_data() + +    if raw: +        return ram_data +    else: +        return _get_formatted_output(ram_data) + +  if __name__ == '__main__': -    print(get_formatted_output()) +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except ValueError as e: +        print(e) +        sys.exit(1) + diff --git a/src/op_mode/show_neigh.py b/src/op_mode/neighbor.py index d874bd544..d86a372ac 100755 --- a/src/op_mode/show_neigh.py +++ b/src/op_mode/neighbor.py @@ -28,29 +28,37 @@  # ]  import sys +import typing +import vyos.opmode -def get_raw_data(family, device=None, state=None): +def interface_exists(interface): +    import os +    return os.path.exists(f'/sys/class/net/{interface}') + +def get_raw_data(family, interface=None, state=None):      from json import loads      from vyos.util import cmd -    if device: -        device = f"dev {device}" +    if interface: +        if not interface_exists(interface): +            raise ValueError(f"Interface '{interface}' does not exist in the system") +        interface = f"dev {interface}"      else: -        device = "" +        interface = ""      if state:          state = f"nud {state}"      else:          state = "" -    neigh_cmd = f"ip --family {family} --json neighbor list {device} {state}" +    neigh_cmd = f"ip --family {family} --json neighbor list {interface} {state}"      data = loads(cmd(neigh_cmd))      return data -def get_formatted_output(family, device=None, state=None): +def format_neighbors(neighs, interface=None):      from tabulate import tabulate      def entry_to_list(e, intf=None): @@ -68,35 +76,47 @@ def get_formatted_output(family, device=None, state=None):          # Device field is absent from outputs of `ip neigh list dev ...`          if "dev" in e:              dev = e["dev"] -        elif device: -            dev = device +        elif interface: +            dev = interface          else:              raise ValueError("interface is not defined")          return [dst, dev, lladdr, state] -    neighs = get_raw_data(family, device=device, state=state)      neighs = map(entry_to_list, neighs)      headers = ["Address", "Interface", "Link layer address",  "State"]      return tabulate(neighs, headers) -if __name__ == '__main__': -    from argparse import ArgumentParser +def show(raw: bool, family: str, interface: typing.Optional[str], state: typing.Optional[str]): +    """ Display neighbor table contents """ +    data = get_raw_data(family, interface, state=state) -    parser = ArgumentParser() -    parser.add_argument("-f", "--family", type=str, default="inet", help="Address family") -    parser.add_argument("-i", "--interface", type=str, help="Network interface") -    parser.add_argument("-s", "--state", type=str, help="Neighbor table entry state") +    if raw: +        return data +    else: +        return format_neighbors(data, interface) -    args = parser.parse_args() +def reset(family: str, interface: typing.Optional[str], address: typing.Optional[str]): +    from vyos.util import run -    if args.state: -        if args.state not in ["reachable", "failed", "stale", "permanent"]: -            raise ValueError(f"""Incorrect state "{args.state}"! Must be one of: reachable, stale, failed, permanent""") +    if address and interface: +        raise ValueError("interface and address parameters are mutually exclusive") +    elif address: +        run(f"""ip --family {family} neighbor flush to {address}""") +    elif interface: +        run(f"""ip --family {family} neighbor flush dev {interface}""") +    else: +        # Flush an entire neighbor table +        run(f"""ip --family {family} neighbor flush""") + +if __name__ == '__main__':      try: -        print(get_formatted_output(args.family, device=args.interface, state=args.state)) +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res)      except ValueError as e:          print(e)          sys.exit(1) + diff --git a/src/op_mode/route.py b/src/op_mode/route.py new file mode 100644 index 000000000..3bb06adac --- /dev/null +++ b/src/op_mode/route.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# +# Purpose: +#    Displays routing table information. +#    Used by the "run <ip|ipv6> route *" commands. + +import re +import sys +import typing + +from jinja2 import Template + +import vyos.opmode + +frr_command_template = Template(""" +{% if family == "inet" %} +    show ip route +{% else %} +    show ipv6 route +{% endif %} + +{% if table %} +    table {{table}} +{% endif %} + +{% if vrf %} +    vrf {{table}} +{% endif %} + +{% if tag %} +    tag {{tag}} +{% elif net %} +    {{net}} +{% elif protocol %} +    {{protocol}} +{% endif %} + +{% if raw %} +    json +{% endif %} +""") + +def show(raw: bool, +         family: str, +         net: typing.Optional[str], +         table: typing.Optional[int], +         protocol: typing.Optional[str], +         vrf: typing.Optional[str], +         tag: typing.Optional[str]): +    if net and protocol: +        raise ValueError("net and protocol are mutually exclusive") +    elif table and vrf: +        raise ValueError("table and vrf are mutually exclusive") +    elif (family == 'inet6') and (protocol == 'rip'): +        raise ValueError("rip is not a valid protocol for family inet6") +    elif (family == 'inet') and (protocol == 'ripng'): +        raise ValueError("rip is not a valid protocol for family inet6") +    else: +        if (family == 'inet6') and (protocol == 'ospf'): +            protocol = 'ospf6' + +        kwargs = dict(locals()) + +        frr_command = frr_command_template.render(kwargs) +        frr_command = re.sub(r'\s+', ' ', frr_command) + +        from vyos.util import cmd +        output = cmd(f"vtysh -c '{frr_command}'") + +        if raw: +            from json import loads +            return loads(output) +        else: +            return output + +if __name__ == '__main__': +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except ValueError as e: +        print(e) +        sys.exit(1) + diff --git a/src/op_mode/show_cpu.py b/src/op_mode/show_cpu.py deleted file mode 100755 index 9973d9789..000000000 --- a/src/op_mode/show_cpu.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2016-2020 VyOS maintainers and contributors -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 or later as -# published by the Free Software Foundation. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. - -import json - -from jinja2 import Template -from sys import exit -from vyos.util import popen, DEVNULL - -OUT_TMPL_SRC = """ -{%- if cpu -%} -{% if 'vendor' in cpu %}CPU Vendor:       {{cpu.vendor}}{% endif %} -{% if 'model' in cpu %}Model:            {{cpu.model}}{% endif %} -{% if 'cpus' in cpu %}Total CPUs:       {{cpu.cpus}}{% endif %} -{% if 'sockets' in cpu %}Sockets:          {{cpu.sockets}}{% endif %} -{% if 'cores' in cpu %}Cores:            {{cpu.cores}}{% endif %} -{% if 'threads' in cpu %}Threads:          {{cpu.threads}}{% endif %} -{% if 'mhz' in cpu %}Current MHz:      {{cpu.mhz}}{% endif %} -{% if 'mhz_min' in cpu %}Minimum MHz:      {{cpu.mhz_min}}{% endif %} -{% if 'mhz_max' in cpu %}Maximum MHz:      {{cpu.mhz_max}}{% endif %} -{%- endif -%} -""" - -def get_raw_data(): -    cpu = {} -    cpu_json, code = popen('lscpu -J', stderr=DEVNULL) - -    if code == 0: -        cpu_info = json.loads(cpu_json) -        if len(cpu_info) > 0 and 'lscpu' in cpu_info: -            for prop in cpu_info['lscpu']: -                if (prop['field'].find('Thread(s)') > -1): cpu['threads'] = prop['data'] -                if (prop['field'].find('Core(s)')) > -1: cpu['cores'] = prop['data'] -                if (prop['field'].find('Socket(s)')) > -1: cpu['sockets'] = prop['data'] -                if (prop['field'].find('CPU(s):')) > -1: cpu['cpus'] = prop['data'] -                if (prop['field'].find('CPU MHz')) > -1: cpu['mhz'] = prop['data'] -                if (prop['field'].find('CPU min MHz')) > -1: cpu['mhz_min'] = prop['data'] -                if (prop['field'].find('CPU max MHz')) > -1: cpu['mhz_max'] = prop['data'] -                if (prop['field'].find('Vendor ID')) > -1: cpu['vendor'] = prop['data'] -                if (prop['field'].find('Model name')) > -1: cpu['model'] = prop['data'] - -    return cpu - -def get_formatted_output(): -    cpu = get_raw_data() - -    tmp = {'cpu':cpu} -    tmpl = Template(OUT_TMPL_SRC) -    return tmpl.render(tmp) - -if __name__ == '__main__': -    cpu = get_raw_data() - -    if len(cpu) > 0: -        print(get_formatted_output()) -    else: -        print('CPU information could not be determined\n') -        exit(1) - diff --git a/src/op_mode/show_version.py b/src/op_mode/version.py index b82ab6eca..06208c3e5 100755 --- a/src/op_mode/show_version.py +++ b/src/op_mode/version.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2016-2020 VyOS maintainers and contributors +# Copyright (C) 2016-2022 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -18,13 +18,14 @@  #    Displays image version and system information.  #    Used by the "run show version" command. -import argparse +import sys +import typing + +import vyos.opmode  import vyos.version  import vyos.limericks  from jinja2 import Template -from sys import exit -from vyos.util import call  version_output_tmpl = """  Version:          VyOS {{version}} @@ -45,32 +46,39 @@ Hardware S/N:     {{hardware_serial}}  Hardware UUID:    {{hardware_uuid}}  Copyright:        VyOS maintainers and contributors +{%- if limerick %} +{{limerick}} +{% endif -%}  """ -def get_raw_data(): +def _get_raw_data(funny=False):      version_data = vyos.version.get_full_version_data() + +    if funny: +        version_data["limerick"] = vyos.limericks.get_random() +      return version_data -def get_formatted_output(): -    version_data = get_raw_data() +def _get_formatted_output(version_data):      tmpl = Template(version_output_tmpl) -    return tmpl.render(version_data) +    return tmpl.render(version_data).strip() -if __name__ == '__main__': -    parser = argparse.ArgumentParser() -    parser.add_argument("-f", "--funny", action="store_true", help="Add something funny to the output") -    parser.add_argument("-j", "--json", action="store_true", help="Produce JSON output") +def show(raw: bool, funny: typing.Optional[bool]): +    """ Display neighbor table contents """ +    version_data = _get_raw_data(funny=funny) -    args = parser.parse_args() +    if raw: +        return version_data +    else: +        return _get_formatted_output(version_data) -    version_data = vyos.version.get_full_version_data() -    if args.json: -        import json -        print(json.dumps(version_data)) -        exit(0) -    else: -        print(get_formatted_output()) +if __name__ == '__main__': +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except ValueError as e: +        print(e) +        sys.exit(1) -    if args.funny: -        print(vyos.limericks.get_random()) | 
