|
4 | 4 |
|
5 | 5 | import utilities_common.cli as clicommon
|
6 | 6 |
|
| 7 | + |
7 | 8 | @click.group(cls=clicommon.AliasedGroup)
|
8 | 9 | def vlan():
|
9 | 10 | """Show VLAN information"""
|
10 | 11 | pass
|
11 | 12 |
|
| 13 | + |
| 14 | +def get_vlan_id(ctx, vlan): |
| 15 | + vlan_prefix, vid = vlan.split('Vlan') |
| 16 | + return vid |
| 17 | + |
| 18 | + |
| 19 | +def get_vlan_ip_address(ctx, vlan): |
| 20 | + cfg, _ = ctx |
| 21 | + _, vlan_ip_data, _ = cfg |
| 22 | + ip_address = "" |
| 23 | + for key in vlan_ip_data: |
| 24 | + if not clicommon.is_ip_prefix_in_key(key): |
| 25 | + continue |
| 26 | + ifname, address = key |
| 27 | + if vlan == ifname: |
| 28 | + ip_address += "\n{}".format(address) |
| 29 | + |
| 30 | + return ip_address |
| 31 | + |
| 32 | + |
| 33 | +def get_vlan_ports(ctx, vlan): |
| 34 | + cfg, db = ctx |
| 35 | + _, _, vlan_ports_data = cfg |
| 36 | + vlan_ports = [] |
| 37 | + iface_alias_converter = clicommon.InterfaceAliasConverter(db) |
| 38 | + # Here natsorting is important in relation to another |
| 39 | + # column which prints port tagging mode. |
| 40 | + # If we sort both in the same way using same keys |
| 41 | + # we will result in right order in both columns. |
| 42 | + # This should be fixed by cli code autogeneration tool |
| 43 | + # and we won't need this specific approach with |
| 44 | + # VlanBrief.COLUMNS anymore. |
| 45 | + for key in natsorted(list(vlan_ports_data.keys())): |
| 46 | + ports_key, ports_value = key |
| 47 | + if vlan != ports_key: |
| 48 | + continue |
| 49 | + |
| 50 | + if clicommon.get_interface_naming_mode() == "alias": |
| 51 | + ports_value = iface_alias_converter.name_to_alias(ports_value) |
| 52 | + |
| 53 | + vlan_ports.append(ports_value) |
| 54 | + |
| 55 | + return '\n'.join(vlan_ports) |
| 56 | + |
| 57 | + |
| 58 | +def get_vlan_ports_tagging(ctx, vlan): |
| 59 | + cfg, db = ctx |
| 60 | + _, _, vlan_ports_data = cfg |
| 61 | + vlan_ports_tagging = [] |
| 62 | + # Here natsorting is important in relation to another |
| 63 | + # column which prints vlan ports. |
| 64 | + # If we sort both in the same way using same keys |
| 65 | + # we will result in right order in both columns. |
| 66 | + # This should be fixed by cli code autogeneration tool |
| 67 | + # and we won't need this specific approach with |
| 68 | + # VlanBrief.COLUMNS anymore. |
| 69 | + for key in natsorted(list(vlan_ports_data.keys())): |
| 70 | + ports_key, ports_value = key |
| 71 | + if vlan != ports_key: |
| 72 | + continue |
| 73 | + |
| 74 | + tagging_value = vlan_ports_data[key]["tagging_mode"] |
| 75 | + vlan_ports_tagging.append(tagging_value) |
| 76 | + |
| 77 | + return '\n'.join(vlan_ports_tagging) |
| 78 | + |
| 79 | + |
| 80 | +def get_proxy_arp(ctx, vlan): |
| 81 | + cfg, _ = ctx |
| 82 | + _, vlan_ip_data, _ = cfg |
| 83 | + proxy_arp = "disabled" |
| 84 | + for key in vlan_ip_data: |
| 85 | + if clicommon.is_ip_prefix_in_key(key): |
| 86 | + continue |
| 87 | + if vlan == key: |
| 88 | + proxy_arp = vlan_ip_data[key].get("proxy_arp", "disabled") |
| 89 | + |
| 90 | + return proxy_arp |
| 91 | + |
| 92 | + |
| 93 | +class VlanBrief: |
| 94 | + """ This class is used as a namespace to |
| 95 | + define columns for "show vlan brief" command. |
| 96 | + The usage of this class is for external plugin |
| 97 | + (in this case dhcp-relay) to append new columns |
| 98 | + to this list. |
| 99 | + """ |
| 100 | + |
| 101 | + COLUMNS = [ |
| 102 | + ("VLAN ID", get_vlan_id), |
| 103 | + ("IP Address", get_vlan_ip_address), |
| 104 | + ("Ports", get_vlan_ports), |
| 105 | + ("Port Tagging", get_vlan_ports_tagging), |
| 106 | + ("Proxy ARP", get_proxy_arp) |
| 107 | + ] |
| 108 | + |
| 109 | + @classmethod |
| 110 | + def register_column(cls, column_name, callback): |
| 111 | + """ Adds a new column to "vlan brief" output. |
| 112 | + Expected to be used from plugins code to extend |
| 113 | + this command with additional VLAN fields. """ |
| 114 | + |
| 115 | + cls.COLUMNS.append((column_name, callback)) |
| 116 | + |
| 117 | + |
12 | 118 | @vlan.command()
|
13 | 119 | @click.option('--verbose', is_flag=True, help="Enable verbose output")
|
14 | 120 | @clicommon.pass_db
|
15 | 121 | def brief(db, verbose):
|
16 | 122 | """Show all bridge information"""
|
17 |
| - header = ['VLAN ID', 'IP Address', 'Ports', 'Port Tagging', 'DHCP Helper Address', 'Proxy ARP'] |
| 123 | + header = [colname for colname, getter in VlanBrief.COLUMNS] |
18 | 124 | body = []
|
19 | 125 |
|
20 | 126 | # Fetching data from config db for VLAN, VLAN_INTERFACE and VLAN_MEMBER
|
21 |
| - vlan_dhcp_helper_data = db.cfgdb.get_table('VLAN') |
| 127 | + vlan_data = db.cfgdb.get_table('VLAN') |
22 | 128 | vlan_ip_data = db.cfgdb.get_table('VLAN_INTERFACE')
|
23 | 129 | vlan_ports_data = db.cfgdb.get_table('VLAN_MEMBER')
|
| 130 | + vlan_cfg = (vlan_data, vlan_ip_data, vlan_ports_data) |
24 | 131 |
|
25 |
| - # Defining dictionaries for DHCP Helper address, Interface Gateway IP, |
26 |
| - # VLAN ports and port tagging |
27 |
| - vlan_dhcp_helper_dict = {} |
28 |
| - vlan_ip_dict = {} |
29 |
| - vlan_ports_dict = {} |
30 |
| - vlan_tagging_dict = {} |
31 |
| - vlan_proxy_arp_dict = {} |
32 |
| - |
33 |
| - # Parsing DHCP Helpers info |
34 |
| - for key in natsorted(list(vlan_dhcp_helper_data.keys())): |
35 |
| - try: |
36 |
| - if vlan_dhcp_helper_data[key]['dhcp_servers']: |
37 |
| - vlan_dhcp_helper_dict[key.strip('Vlan')] = vlan_dhcp_helper_data[key]['dhcp_servers'] |
38 |
| - except KeyError: |
39 |
| - vlan_dhcp_helper_dict[key.strip('Vlan')] = " " |
40 |
| - |
41 |
| - # Parsing VLAN Gateway info |
42 |
| - for key in vlan_ip_data: |
43 |
| - if clicommon.is_ip_prefix_in_key(key): |
44 |
| - interface_key = key[0].strip("Vlan") |
45 |
| - interface_value = key[1] |
46 |
| - |
47 |
| - if interface_key in vlan_ip_dict: |
48 |
| - vlan_ip_dict[interface_key].append(interface_value) |
49 |
| - else: |
50 |
| - vlan_ip_dict[interface_key] = [interface_value] |
51 |
| - else: |
52 |
| - interface_key = key.strip("Vlan") |
53 |
| - if 'proxy_arp' in vlan_ip_data[key]: |
54 |
| - proxy_arp_status = vlan_ip_data[key]['proxy_arp'] |
55 |
| - else: |
56 |
| - proxy_arp_status = "disabled" |
57 |
| - |
58 |
| - vlan_proxy_arp_dict[interface_key] = proxy_arp_status |
59 |
| - |
60 |
| - |
| 132 | + for vlan in natsorted(vlan_data): |
| 133 | + row = [] |
| 134 | + for column in VlanBrief.COLUMNS: |
| 135 | + column_name, getter = column |
| 136 | + row.append(getter((vlan_cfg, db), vlan)) |
| 137 | + body.append(row) |
61 | 138 |
|
62 |
| - iface_alias_converter = clicommon.InterfaceAliasConverter(db) |
63 |
| - |
64 |
| - # Parsing VLAN Ports info |
65 |
| - for key in natsorted(list(vlan_ports_data.keys())): |
66 |
| - ports_key = key[0].strip("Vlan") |
67 |
| - ports_value = key[1] |
68 |
| - ports_tagging = vlan_ports_data[key]['tagging_mode'] |
69 |
| - if ports_key in vlan_ports_dict: |
70 |
| - if clicommon.get_interface_naming_mode() == "alias": |
71 |
| - ports_value = iface_alias_converter.name_to_alias(ports_value) |
72 |
| - vlan_ports_dict[ports_key].append(ports_value) |
73 |
| - else: |
74 |
| - if clicommon.get_interface_naming_mode() == "alias": |
75 |
| - ports_value = iface_alias_converter.name_to_alias(ports_value) |
76 |
| - vlan_ports_dict[ports_key] = [ports_value] |
77 |
| - if ports_key in vlan_tagging_dict: |
78 |
| - vlan_tagging_dict[ports_key].append(ports_tagging) |
79 |
| - else: |
80 |
| - vlan_tagging_dict[ports_key] = [ports_tagging] |
81 |
| - |
82 |
| - # Printing the following dictionaries in tablular forms: |
83 |
| - # vlan_dhcp_helper_dict={}, vlan_ip_dict = {}, vlan_ports_dict = {} |
84 |
| - # vlan_tagging_dict = {} |
85 |
| - for key in natsorted(list(vlan_dhcp_helper_dict.keys())): |
86 |
| - if key not in vlan_ip_dict: |
87 |
| - ip_address = "" |
88 |
| - else: |
89 |
| - ip_address = ','.replace(',', '\n').join(vlan_ip_dict[key]) |
90 |
| - if key not in vlan_ports_dict: |
91 |
| - vlan_ports = "" |
92 |
| - else: |
93 |
| - vlan_ports = ','.replace(',', '\n').join((vlan_ports_dict[key])) |
94 |
| - if key not in vlan_dhcp_helper_dict: |
95 |
| - dhcp_helpers = "" |
96 |
| - else: |
97 |
| - dhcp_helpers = ','.replace(',', '\n').join(vlan_dhcp_helper_dict[key]) |
98 |
| - if key not in vlan_tagging_dict: |
99 |
| - vlan_tagging = "" |
100 |
| - else: |
101 |
| - vlan_tagging = ','.replace(',', '\n').join((vlan_tagging_dict[key])) |
102 |
| - vlan_proxy_arp = vlan_proxy_arp_dict.get(key, "disabled") |
103 |
| - body.append([key, ip_address, vlan_ports, vlan_tagging, dhcp_helpers, vlan_proxy_arp]) |
104 | 139 | click.echo(tabulate(body, header, tablefmt="grid"))
|
105 | 140 |
|
| 141 | + |
106 | 142 | @vlan.command()
|
107 | 143 | @clicommon.pass_db
|
108 | 144 | def config(db):
|
@@ -141,3 +177,4 @@ def tablelize(keys, data):
|
141 | 177 |
|
142 | 178 | header = ['Name', 'VID', 'Member', 'Mode']
|
143 | 179 | click.echo(tabulate(tablelize(keys, data), header))
|
| 180 | + |
0 commit comments