diff options
Diffstat (limited to 'src/op_mode')
-rwxr-xr-x | src/op_mode/config_mgmt.py | 85 | ||||
-rwxr-xr-x | src/op_mode/generate_interfaces_debug_archive.py | 115 | ||||
-rwxr-xr-x | src/op_mode/igmp-proxy.py | 99 | ||||
-rwxr-xr-x | src/op_mode/lldp.py | 13 | ||||
-rwxr-xr-x | src/op_mode/show_igmpproxy.py | 241 | ||||
-rwxr-xr-x | src/op_mode/zone.py | 215 | ||||
-rwxr-xr-x | src/op_mode/zone_policy.py | 81 |
7 files changed, 526 insertions, 323 deletions
diff --git a/src/op_mode/config_mgmt.py b/src/op_mode/config_mgmt.py new file mode 100755 index 000000000..66de26d1f --- /dev/null +++ b/src/op_mode/config_mgmt.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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 typing + +import vyos.opmode +from vyos.config_mgmt import ConfigMgmt + +def show_commit_diff(raw: bool, rev: int, rev2: typing.Optional[int], + commands: bool): + config_mgmt = ConfigMgmt() + config_diff = config_mgmt.show_commit_diff(rev, rev2, commands) + + if raw: + rev2 = (rev+1) if rev2 is None else rev2 + if commands: + d = {f'config_command_diff_{rev2}_{rev}': config_diff} + else: + d = {f'config_file_diff_{rev2}_{rev}': config_diff} + return d + + return config_diff + +def show_commit_file(raw: bool, rev: int): + config_mgmt = ConfigMgmt() + config_file = config_mgmt.show_commit_file(rev) + + if raw: + d = {f'config_revision_{rev}': config_file} + return d + + return config_file + +def show_commit_log(raw: bool): + config_mgmt = ConfigMgmt() + + msg = '' + if config_mgmt.max_revisions == 0: + msg = ('commit-revisions is not configured;\n' + 'commit log is empty or stale:\n\n') + + data = config_mgmt.get_raw_log_data() + if raw: + return data + + out = config_mgmt.format_log_data(data) + out = msg + out + + return out + +def show_commit_log_brief(raw: bool): + # used internally for completion help for 'rollback' + # option 'raw' will return same as 'show_commit_log' + config_mgmt = ConfigMgmt() + + data = config_mgmt.get_raw_log_data() + if raw: + return data + + out = config_mgmt.format_log_data_brief(data) + + return out + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) diff --git a/src/op_mode/generate_interfaces_debug_archive.py b/src/op_mode/generate_interfaces_debug_archive.py new file mode 100755 index 000000000..f5767080a --- /dev/null +++ b/src/op_mode/generate_interfaces_debug_archive.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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/>. + +from datetime import datetime +from pathlib import Path +from shutil import rmtree +from socket import gethostname +from sys import exit +from tarfile import open as tar_open +from vyos.util import rc_cmd +import os + +# define a list of commands that needs to be executed + +CMD_LIST: list[str] = [ + "journalctl -b -n 500", + "journalctl -b -k -n 500", + "ip -s l", + "cat /proc/interrupts", + "cat /proc/softirqs", + "top -b -d 1 -n 2 -1", + "netstat -l", + "cat /proc/net/dev", + "cat /proc/net/softnet_stat", + "cat /proc/net/icmp", + "cat /proc/net/udp", + "cat /proc/net/tcp", + "cat /proc/net/netstat", + "sysctl net", + "timeout 10 tcpdump -c 500 -eni any port not 22" +] + +CMD_INTERFACES_LIST: list[str] = [ + "ethtool -i ", + "ethtool -S ", + "ethtool -g ", + "ethtool -c ", + "ethtool -a ", + "ethtool -k ", + "ethtool -i ", + "ethtool --phy-statistics " +] + +# get intefaces info +interfaces_list = os.popen('ls /sys/class/net/').read().split() + +# modify CMD_INTERFACES_LIST for all interfaces +CMD_INTERFACES_LIST_MOD=[] +for command_interface in interfaces_list: + for command_interfacev2 in CMD_INTERFACES_LIST: + CMD_INTERFACES_LIST_MOD.append (f'{command_interfacev2}{command_interface}') + +# execute a command and save the output to a file + +def save_stdout(command: str, file: Path) -> None: + rc, stdout = rc_cmd(command) + body: str = f'''### {command} ### +Command: {command} +Exit code: {rc} +Stdout: +{stdout} + +''' + with file.open(mode='a') as f: + f.write(body) + +# get local host name +hostname: str = gethostname() +# get current time +time_now: str = datetime.now().isoformat(timespec='seconds') + +# define a temporary directory for logs and collected data +tmp_dir: Path = Path(f'/tmp/drops-debug_{time_now}') +# set file paths +drops_file: Path = Path(f'{tmp_dir}/drops.txt') +interfaces_file: Path = Path(f'{tmp_dir}/interfaces.txt') +archive_file: str = f'/tmp/packet-drops-debug_{time_now}.tar.bz2' + +# create files +tmp_dir.mkdir() +drops_file.touch() +interfaces_file.touch() + +try: + # execute all commands + for command in CMD_LIST: + save_stdout(command, drops_file) + for command_interface in CMD_INTERFACES_LIST_MOD: + save_stdout(command_interface, interfaces_file) + + # create an archive + with tar_open(name=archive_file, mode='x:bz2') as tar_file: + tar_file.add(tmp_dir) + + # inform user about success + print(f'Debug file is generated and located in {archive_file}') +except Exception as err: + print(f'Error during generating a debug file: {err}') +finally: + # cleanup + rmtree(tmp_dir) + exit() diff --git a/src/op_mode/igmp-proxy.py b/src/op_mode/igmp-proxy.py new file mode 100755 index 000000000..0086c9aa6 --- /dev/null +++ b/src/op_mode/igmp-proxy.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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/>. + +# File: show_igmpproxy.py +# Purpose: +# Display istatistics from IPv4 IGMP proxy. +# Used by the "run show ip multicast" command tree. + +import ipaddress +import json +import socket +import sys +import tabulate + +import vyos.config +import vyos.opmode + +from vyos.util import bytes_to_human, print_error + +def _is_configured(): + """Check if IGMP proxy is configured""" + return vyos.config.Config().exists_effective('protocols igmp-proxy') + +def _is_running(): + """Check if IGMP proxy is currently running""" + return not vyos.util.run('ps -C igmpproxy') + +def _kernel_to_ip(addr): + """ + Convert any given address from Linux kernel to a proper, IPv4 address + using the correct host byte order. + """ + # Convert from hex 'FE000A0A' to decimal '4261415434' + addr = int(addr, 16) + # Kernel ABI _always_ uses network byte order. + addr = socket.ntohl(addr) + return str(ipaddress.IPv4Address(addr)) + +def _process_mr_vif(): + """Read rows from /proc/net/ip_mr_vif into dicts.""" + result = [] + with open('/proc/net/ip_mr_vif', 'r') as f: + next(f) + for line in f: + result.append({ + 'Interface': line.split()[1], + 'PktsIn' : int(line.split()[3]), + 'PktsOut' : int(line.split()[5]), + 'BytesIn' : int(line.split()[2]), + 'BytesOut' : int(line.split()[4]), + 'Local' : _kernel_to_ip(line.split()[7]), + }) + return result + +def show_interface(raw: bool): + if data := _process_mr_vif(): + if raw: + # Make the interface name the key for each row. + table = {} + for v in data: + table[v.pop('Interface')] = v + return json.loads(json.dumps(table)) + # Make byte values human-readable for the table. + arr = [] + for x in data: + arr.append({k: bytes_to_human(v) if k.startswith('Bytes') \ + else v for k, v in x.items()}) + return tabulate.tabulate(arr, headers='keys') + + +if not _is_configured(): + print_error('IGMP proxy is not configured.') + sys.exit(0) +if not _is_running(): + print_error('IGMP proxy is not running.') + sys.exit(0) + + +if __name__ == "__main__": + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print_error(e) + sys.exit(1) diff --git a/src/op_mode/lldp.py b/src/op_mode/lldp.py index dc2b1e0b5..1a1b94783 100755 --- a/src/op_mode/lldp.py +++ b/src/op_mode/lldp.py @@ -61,7 +61,14 @@ def _get_raw_data(interface=None, detail=False): def _get_formatted_output(raw_data): data_entries = [] - for neighbor in dict_search('lldp.interface', raw_data): + tmp = dict_search('lldp.interface', raw_data) + if not tmp: + return None + # One can not always ensure that "interface" is of type list, add safeguard. + # E.G. Juniper Networks, Inc. ex2300-c-12t only has a dict, not a list of dicts + if isinstance(tmp, dict): + tmp = [tmp] + for neighbor in tmp: for local_if, values in neighbor.items(): tmp = [] @@ -80,6 +87,10 @@ def _get_formatted_output(raw_data): # Capabilities cap = '' capabilities = jmespath.search('chassis.[*][0][0].capability', values) + # One can not always ensure that "capability" is of type list, add + # safeguard. E.G. Unify US-24-250W only has a dict, not a list of dicts + if isinstance(capabilities, dict): + capabilities = [capabilities] if capabilities: for capability in capabilities: if capability['enabled']: diff --git a/src/op_mode/show_igmpproxy.py b/src/op_mode/show_igmpproxy.py deleted file mode 100755 index 4714e494b..000000000 --- a/src/op_mode/show_igmpproxy.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018 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/>. - -# File: show_igmpproxy.py -# Purpose: -# Display istatistics from IPv4 IGMP proxy. -# Used by the "run show ip multicast" command tree. - -import sys -import jinja2 -import argparse -import ipaddress -import socket - -import vyos.config - -# Output Template for "show ip multicast interface" command -# -# Example: -# Interface BytesIn PktsIn BytesOut PktsOut Local -# eth0 0.0b 0 0.0b 0 xxx.xxx.xxx.65 -# eth1 0.0b 0 0.0b 0 xxx.xxx.xx.201 -# eth0.3 0.0b 0 0.0b 0 xxx.xxx.x.7 -# tun1 0.0b 0 0.0b 0 xxx.xxx.xxx.2 -vif_out_tmpl = """ -{% for r in data %} -{{ "%-10s"|format(r.interface) }} {{ "%-12s"|format(r.bytes_in) }} {{ "%-12s"|format(r.pkts_in) }} {{ "%-12s"|format(r.bytes_out) }} {{ "%-12s"|format(r.pkts_out) }} {{ "%-15s"|format(r.loc) }} -{% endfor %} -""" - -# Output Template for "show ip multicast mfc" command -# -# Example: -# Group Origin In Out Pkts Bytes Wrong -# xxx.xxx.xxx.250 xxx.xx.xxx.75 -- -# xxx.xxx.xx.124 xx.xxx.xxx.26 -- -mfc_out_tmpl = """ -{% for r in data %} -{{ "%-15s"|format(r.group) }} {{ "%-15s"|format(r.origin) }} {{ "%-12s"|format(r.pkts) }} {{ "%-12s"|format(r.bytes) }} {{ "%-12s"|format(r.wrong) }} {{ "%-10s"|format(r.iif) }} {{ "%-20s"|format(r.oifs|join(', ')) }} -{% endfor %} -""" - -parser = argparse.ArgumentParser() -parser.add_argument("--interface", action="store_true", help="Interface Statistics") -parser.add_argument("--mfc", action="store_true", help="Multicast Forwarding Cache") - -def byte_string(size): - # convert size to integer - size = int(size) - - # One Terrabyte - s_TB = 1024 * 1024 * 1024 * 1024 - # One Gigabyte - s_GB = 1024 * 1024 * 1024 - # One Megabyte - s_MB = 1024 * 1024 - # One Kilobyte - s_KB = 1024 - # One Byte - s_B = 1 - - if size > s_TB: - return str(round((size/s_TB), 2)) + 'TB' - elif size > s_GB: - return str(round((size/s_GB), 2)) + 'GB' - elif size > s_MB: - return str(round((size/s_MB), 2)) + 'MB' - elif size > s_KB: - return str(round((size/s_KB), 2)) + 'KB' - else: - return str(round((size/s_B), 2)) + 'b' - - return None - -def kernel2ip(addr): - """ - Convert any given addr from Linux Kernel to a proper, IPv4 address - using the correct host byte order. - """ - - # Convert from hex 'FE000A0A' to decimal '4261415434' - addr = int(addr, 16) - # Kernel ABI _always_ uses network byteorder - addr = socket.ntohl(addr) - - return ipaddress.IPv4Address( addr ) - -def do_mr_vif(): - """ - Read contents of file /proc/net/ip_mr_vif and print a more human - friendly version to the command line. IPv4 addresses present as - 32bit integers in hex format are converted to IPv4 notation, too. - """ - - with open('/proc/net/ip_mr_vif', 'r') as f: - lines = len(f.readlines()) - if lines < 2: - return None - - result = { - 'data': [] - } - - # Build up table format string - table_format = { - 'interface': 'Interface', - 'pkts_in' : 'PktsIn', - 'pkts_out' : 'PktsOut', - 'bytes_in' : 'BytesIn', - 'bytes_out': 'BytesOut', - 'loc' : 'Local' - } - result['data'].append(table_format) - - # read and parse information from /proc filesystema - with open('/proc/net/ip_mr_vif', 'r') as f: - header_line = next(f) - for line in f: - data = { - 'interface': line.split()[1], - 'pkts_in' : line.split()[3], - 'pkts_out' : line.split()[5], - - # convert raw byte number to something more human readable - # Note: could be replaced by Python3 hurry.filesize module - 'bytes_in' : byte_string( line.split()[2] ), - 'bytes_out': byte_string( line.split()[4] ), - - # convert IP address from hex 'FE000A0A' to decimal '4261415434' - 'loc' : kernel2ip( line.split()[7] ), - } - result['data'].append(data) - - return result - -def do_mr_mfc(): - """ - Read contents of file /proc/net/ip_mr_cache and print a more human - friendly version to the command line. IPv4 addresses present as - 32bit integers in hex format are converted to IPv4 notation, too. - """ - - with open('/proc/net/ip_mr_cache', 'r') as f: - lines = len(f.readlines()) - if lines < 2: - return None - - # We need this to convert from interface index to a real interface name - # Thus we also skip the format identifier on list index 0 - vif = do_mr_vif()['data'][1:] - - result = { - 'data': [] - } - - # Build up table format string - table_format = { - 'group' : 'Group', - 'origin': 'Origin', - 'iif' : 'In', - 'oifs' : ['Out'], - 'pkts' : 'Pkts', - 'bytes' : 'Bytes', - 'wrong' : 'Wrong' - } - result['data'].append(table_format) - - # read and parse information from /proc filesystem - with open('/proc/net/ip_mr_cache', 'r') as f: - header_line = next(f) - for line in f: - data = { - # convert IP address from hex 'FE000A0A' to decimal '4261415434' - 'group' : kernel2ip( line.split()[0] ), - 'origin': kernel2ip( line.split()[1] ), - - 'iif' : '--', - 'pkts' : '', - 'bytes' : '', - 'wrong' : '', - 'oifs' : [] - } - - iif = int( line.split()[2] ) - if not ((iif == -1) or (iif == 65535)): - data['pkts'] = line.split()[3] - data['bytes'] = byte_string( line.split()[4] ) - data['wrong'] = line.split()[5] - - # convert index to real interface name - data['iif'] = vif[iif]['interface'] - - # convert each output interface index to a real interface name - for oif in line.split()[6:]: - idx = int( oif.split(':')[0] ) - data['oifs'].append( vif[idx]['interface'] ) - - result['data'].append(data) - - return result - -if __name__ == '__main__': - args = parser.parse_args() - - # Do nothing if service is not configured - c = vyos.config.Config() - if not c.exists_effective('protocols igmp-proxy'): - print("IGMP proxy is not configured") - sys.exit(0) - - if args.interface: - data = do_mr_vif() - if data: - tmpl = jinja2.Template(vif_out_tmpl) - print(tmpl.render(data)) - - sys.exit(0) - elif args.mfc: - data = do_mr_mfc() - if data: - tmpl = jinja2.Template(mfc_out_tmpl) - print(tmpl.render(data)) - - sys.exit(0) - else: - parser.print_help() - sys.exit(1) - diff --git a/src/op_mode/zone.py b/src/op_mode/zone.py new file mode 100755 index 000000000..f326215b1 --- /dev/null +++ b/src/op_mode/zone.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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 typing +import sys +import vyos.opmode + +import tabulate +from vyos.configquery import ConfigTreeQuery +from vyos.util import dict_search_args +from vyos.util import dict_search + + +def get_config_zone(conf, name=None): + config_path = ['firewall', 'zone'] + if name: + config_path += [name] + + zone_policy = conf.get_config_dict(config_path, key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True) + return zone_policy + + +def _convert_one_zone_data(zone: str, zone_config: dict) -> dict: + """ + Convert config dictionary of one zone to API dictionary + :param zone: Zone name + :type zone: str + :param zone_config: config dictionary + :type zone_config: dict + :return: AP dictionary + :rtype: dict + """ + list_of_rules = [] + intrazone_dict = {} + if dict_search('from', zone_config): + for from_zone, from_zone_config in zone_config['from'].items(): + from_zone_dict = {'name': from_zone} + if dict_search('firewall.name', from_zone_config): + from_zone_dict['firewall'] = dict_search('firewall.name', + from_zone_config) + if dict_search('firewall.ipv6_name', from_zone_config): + from_zone_dict['firewall_v6'] = dict_search( + 'firewall.ipv6_name', from_zone_config) + list_of_rules.append(from_zone_dict) + + zone_dict = { + 'name': zone, + 'interface': dict_search('interface', zone_config), + 'type': 'LOCAL' if dict_search('local_zone', + zone_config) is not None else None, + } + if list_of_rules: + zone_dict['from'] = list_of_rules + if dict_search('intra_zone_filtering.firewall.name', zone_config): + intrazone_dict['firewall'] = dict_search( + 'intra_zone_filtering.firewall.name', zone_config) + if dict_search('intra_zone_filtering.firewall.ipv6_name', zone_config): + intrazone_dict['firewall_v6'] = dict_search( + 'intra_zone_filtering.firewall.ipv6_name', zone_config) + if intrazone_dict: + zone_dict['intrazone'] = intrazone_dict + return zone_dict + + +def _convert_zones_data(zone_policies: dict) -> list: + """ + Convert all config dictionary to API list of zone dictionaries + :param zone_policies: config dictionary + :type zone_policies: dict + :return: API list + :rtype: list + """ + zone_list = [] + for zone, zone_config in zone_policies.items(): + zone_list.append(_convert_one_zone_data(zone, zone_config)) + return zone_list + + +def _convert_config(zones_config: dict, zone: str = None) -> list: + """ + convert config to API list + :param zones_config: zones config + :type zones_config: + :param zone: zone name + :type zone: str + :return: API list + :rtype: list + """ + if zone: + if zones_config: + output = [_convert_one_zone_data(zone, zones_config)] + else: + raise vyos.opmode.DataUnavailable(f'Zone {zone} not found') + else: + if zones_config: + output = _convert_zones_data(zones_config) + else: + raise vyos.opmode.UnconfiguredSubsystem( + 'Zone entries are not configured') + return output + + +def output_zone_list(zone_conf: dict) -> list: + """ + Format one zone row + :param zone_conf: zone config + :type zone_conf: dict + :return: formatted list of zones + :rtype: list + """ + zone_info = [zone_conf['name']] + if zone_conf['type'] == 'LOCAL': + zone_info.append('LOCAL') + else: + zone_info.append("\n".join(zone_conf['interface'])) + + from_zone = [] + firewall = [] + firewall_v6 = [] + if 'intrazone' in zone_conf: + from_zone.append(zone_conf['name']) + + v4_name = dict_search_args(zone_conf['intrazone'], 'firewall') + v6_name = dict_search_args(zone_conf['intrazone'], 'firewall_v6') + if v4_name: + firewall.append(v4_name) + else: + firewall.append('') + if v6_name: + firewall_v6.append(v6_name) + else: + firewall_v6.append('') + + if 'from' in zone_conf: + for from_conf in zone_conf['from']: + from_zone.append(from_conf['name']) + + v4_name = dict_search_args(from_conf, 'firewall') + v6_name = dict_search_args(from_conf, 'firewall_v6') + if v4_name: + firewall.append(v4_name) + else: + firewall.append('') + if v6_name: + firewall_v6.append(v6_name) + else: + firewall_v6.append('') + + zone_info.append("\n".join(from_zone)) + zone_info.append("\n".join(firewall)) + zone_info.append("\n".join(firewall_v6)) + return zone_info + + +def get_formatted_output(zone_policy: list) -> str: + """ + Formatted output of all zones + :param zone_policy: list of zones + :type zone_policy: list + :return: formatted table with zones + :rtype: str + """ + headers = ["Zone", + "Interfaces", + "From Zone", + "Firewall IPv4", + "Firewall IPv6" + ] + formatted_list = [] + for zone_conf in zone_policy: + formatted_list.append(output_zone_list(zone_conf)) + tabulate.PRESERVE_WHITESPACE = True + output = tabulate.tabulate(formatted_list, headers, numalign="left") + return output + + +def show(raw: bool, zone: typing.Optional[str]): + """ + Show zone-policy command + :param raw: if API + :type raw: bool + :param zone: zone name + :type zone: str + """ + conf: ConfigTreeQuery = ConfigTreeQuery() + zones_config: dict = get_config_zone(conf, zone) + zone_policy_api: list = _convert_config(zones_config, zone) + if raw: + return zone_policy_api + else: + return get_formatted_output(zone_policy_api) + + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) diff --git a/src/op_mode/zone_policy.py b/src/op_mode/zone_policy.py deleted file mode 100755 index 7b43018c2..000000000 --- a/src/op_mode/zone_policy.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2021 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 argparse -import tabulate - -from vyos.config import Config -from vyos.util import dict_search_args - -def get_config_zone(conf, name=None): - config_path = ['zone-policy'] - if name: - config_path += ['zone', name] - - zone_policy = conf.get_config_dict(config_path, key_mangling=('-', '_'), - get_first_key=True, no_tag_node_value_mangle=True) - return zone_policy - -def output_zone_name(zone, zone_conf): - print(f'\n---------------------------------\nZone: "{zone}"\n') - - interfaces = ', '.join(zone_conf['interface']) if 'interface' in zone_conf else '' - if 'local_zone' in zone_conf: - interfaces = 'LOCAL' - - print(f'Interfaces: {interfaces}\n') - - header = ['From Zone', 'Firewall'] - rows = [] - - if 'from' in zone_conf: - for from_name, from_conf in zone_conf['from'].items(): - row = [from_name] - v4_name = dict_search_args(from_conf, 'firewall', 'name') - v6_name = dict_search_args(from_conf, 'firewall', 'ipv6_name') - - if v4_name: - rows.append(row + [v4_name]) - - if v6_name: - rows.append(row + [f'{v6_name} [IPv6]']) - - if rows: - print('From Zones:\n') - print(tabulate.tabulate(rows, header)) - -def show_zone_policy(zone): - conf = Config() - zone_policy = get_config_zone(conf, zone) - - if not zone_policy: - return - - if 'zone' in zone_policy: - for zone, zone_conf in zone_policy['zone'].items(): - output_zone_name(zone, zone_conf) - elif zone: - output_zone_name(zone, zone_policy) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--action', help='Action', required=False) - parser.add_argument('--name', help='Zone name', required=False, action='store', nargs='?', default='') - - args = parser.parse_args() - - if args.action == 'show': - show_zone_policy(args.name) |