Skip to content

Commit

Permalink
New command walt device port-config
Browse files Browse the repository at this point in the history
Allows to view switch ports configuration (name, poe status, peer
device) and to rename them for a more readable walt device tree
output.

Fix #102.
  • Loading branch information
eduble committed Apr 11, 2024
1 parent 9d8c03f commit 8891aee
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 24 deletions.
18 changes: 18 additions & 0 deletions client/walt/client/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
DEVICE_CONFIG_PARAM,
RESCAN_SET_OF_DEVICES,
SET_OF_DEVICES,
SWITCH,
PORT_CONFIG_PARAM,
)


Expand Down Expand Up @@ -126,6 +128,22 @@ def main(self, old_name: DEVICE, new_name):
server.rename(old_name, new_name)


@WalTDevice.subcommand("port-config")
class WalTDevicePortConfig(WalTApplication):
"""view and edit switch port config and names"""

ORDERING = 10

def main(self, switch_name: SWITCH, port_id: int = None,
*configuration: PORT_CONFIG_PARAM):
with ClientToServerLink() as server:
if len(configuration) > 0:
server.set_port_config(switch_name, port_id, configuration)
else:
# no settings specified => list current settings
server.get_port_config(switch_name, port_id)


@WalTDevice.subcommand("ping")
class WalTDevicePing(WalTApplication):
"""check that a device is reachable on WalT network"""
Expand Down
8 changes: 8 additions & 0 deletions client/walt/client/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,11 @@ class DIRECTORY(str):

class IMAGE_BUILD_NAME(str):
pass


class SWITCH(str):
pass


class PORT_CONFIG_PARAM(str):
pass
31 changes: 31 additions & 0 deletions doc/walt/doc/md/device-port-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

# Viewing and updating switch ports configuration

Users can view or modify switch ports configuration using command `walt device port-config`:
```
$ walt device port-config switch1 # show conf of all ports of switch1
[...]
$ walt device port-config switch1 4 # show conf of 4th port of switch1
Port 4 of switch1 has the following config:
4: name="4" poe=on peer=walt-server
$ walt device port-config switch1 4 name="SR32C14" # rename port 4 of switch1
Done.
$ walt device tree # name is updated in the network view
-- switch1 --
├─SR32C14: walt-server
[...]
```

When the WalT network is deployed on selected wall plugs of a large building, and these wall plugs have their name on a tag, one can give to switch ports the name of respective wall plugs, for easier platform maintenance.

WalT implements the following port settings:

| Name | possible values | access type |
|-----------|-------------------------|----------------|
| name | alphanumeric name | read-write |
| poe | on / off / unavailable | read |
| peer | peer device or unknown | read |

3 changes: 3 additions & 0 deletions doc/walt/doc/md/switch-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,6 @@ $ walt device config <switch-name> snmp.version=2 snmp.community='private' lldp.
```

For general information about this command, see [`walt help show device-config`](device-config.md).

Last note: to make the network view (output by `walt device tree`) of a large building more readable, its is possible to rename the switch ports.
See [`walt help show device-port-config`](device-port-config.md).
1 change: 1 addition & 0 deletions doc/walt/doc/sphinx/index_rst_tables
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Full table of Contents

device-sets
device-config
device-port-config
device-expose
device-netsetup
unmanaged-devices
Expand Down
12 changes: 11 additions & 1 deletion server/walt/server/processes/blocking/devices/topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
"use 'walt device config ...' (see walt help show device-config)"
" to let WalT explore forbidden switches"
)
TIPS_MIN = (TIP_DEVICE_SHOW, TIP_DEVICE_ADMIN_2, TIP_DEVICE_RESCAN)
TIP_DEVICE_ADMIN_3 = (
"use 'walt device port-config ...' (see walt help show device-port-config)"
" to give sensible names to switch ports"
)
TIPS_MIN = (TIP_DEVICE_SHOW, TIP_DEVICE_ADMIN_2, TIP_DEVICE_ADMIN_3, TIP_DEVICE_RESCAN)

NOTE_LAST_NETWORK_SCAN = (
"this view comes from last network scan, issued %s ago"
Expand Down Expand Up @@ -441,6 +445,7 @@ def printed_tree(
device_labels,
device_types,
lldp_forbidden,
port_names,
show_all,
):
t = Tree(stdout_encoding)
Expand Down Expand Up @@ -471,6 +476,8 @@ def printed_tree(
):
if device_types[parent_mac] == "switch":
if show_all or device_types[node_mac] != "unknown":
parent_port = port_names.get(
(parent_mac, parent_port), parent_port)
t.add_child(parent_mac, parent_port, node_mac)
# prune parts of the tree
self.prune(t, root_mac, device_types, lldp_forbidden, show_all)
Expand Down Expand Up @@ -830,6 +837,8 @@ def tree(self, requester, server, db, show_all):
for d in db.select("devices", type="switch")
if d.conf.get("lldp.explore", False) is False
)
# get optional switch port names
port_names = {(sp.mac, sp.port): sp.name for sp in db.select("switchports")}
# compute and return the topology tree
stdout_encoding = requester.stdout.get_encoding()
return db_topology.printed_tree(
Expand All @@ -839,6 +848,7 @@ def tree(self, requester, server, db, show_all):
device_labels,
device_types,
lldp_forbidden,
port_names,
show_all,
)

Expand Down
8 changes: 5 additions & 3 deletions server/walt/server/processes/blocking/devices/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ def prune(self, node_key, msg):
def sort_children(self):
if not self.up_to_date:
# sort children by child_pos
# child_pos may be None, an integer or a string,
# so include the class name in the ordering
for node in self.nodes.values():
node["children"] = sorted(
node["children"],
key=lambda t: (-1, t[1]) if t[0] is None else (t[0], t[1]),
key=lambda t: (t[0].__class__.__name__,) + tuple(t)
)
self.up_to_date = True

Expand Down Expand Up @@ -94,9 +96,9 @@ def print_elem(
label = "?: %s" % label
subtree_offset = 3
else:
label = "%d: %s" % (child_pos, label)
label = "%s: %s" % (child_pos, label)
# align to 2nd letter of the name
subtree_offset = len("%d" % child_pos) + 2
subtree_offset = len("%s" % child_pos) + 2
if last_child:
sep_char_item = self.charset.UPPER_V_RIGHT_H
sep_char_child = self.charset.SPACE
Expand Down
8 changes: 7 additions & 1 deletion server/walt/server/processes/db/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ def prepare(self):
self.execute("""CREATE TABLE IF NOT EXISTS switches (
mac TEXT REFERENCES devices(mac),
model TEXT);""")
self.execute("""CREATE TABLE IF NOT EXISTS switchports (
mac TEXT REFERENCES devices(mac),
port INTEGER,
name TEXT,
PRIMARY KEY (mac, port));""")
self.execute("""CREATE TABLE IF NOT EXISTS logstreams (
id SERIAL PRIMARY KEY,
issuer_mac TEXT REFERENCES devices(mac),
Expand Down Expand Up @@ -347,13 +352,14 @@ def forget_device(self, dev_name):
DELETE FROM logstreams s USING devices d
WHERE d.name = %s AND s.issuer_mac = d.mac;
DELETE FROM nodes n USING devices d WHERE d.name = %s AND d.mac = n.mac;
DELETE FROM switchports sp USING devices d WHERE d.name = %s AND d.mac = sp.mac;
DELETE FROM switches s USING devices d WHERE d.name = %s AND d.mac = s.mac;
DELETE FROM topology t USING devices d WHERE d.name = %s AND d.mac = t.mac1;
DELETE FROM topology t USING devices d WHERE d.name = %s AND d.mac = t.mac2;
DELETE FROM poeoff po USING devices d WHERE d.name = %s AND d.mac = po.mac;
DELETE FROM devices d WHERE d.name = %s;
""",
(dev_name,) * 8,
(dev_name,) * 9,
)
self.commit()

Expand Down
10 changes: 10 additions & 0 deletions server/walt/server/processes/main/api/cs.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,16 @@ def set_device_config(self, context, device_set, conf_args):
def get_device_config(self, context, device_set):
context.server.settings.get_device_config(context.requester, device_set)

@api_expose_method
def set_port_config(self, context, switch_name, port_id, configuration):
context.server.port_settings.set_config(context.requester,
switch_name, port_id, configuration)

@api_expose_method
def get_port_config(self, context, switch_name, port_id):
context.server.port_settings.get_config(context.requester,
switch_name, port_id)

@api_expose_method
def get_device_config_data(self, context, device_set):
return context.server.settings.get_device_config_data(
Expand Down
20 changes: 20 additions & 0 deletions server/walt/server/processes/main/autocomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ def complete_device(server, partial_token):
)


def complete_switch(server, partial_token):
return tuple(
dev.name
for dev in server.db.select("devices", type="switch")
if dev.name.startswith(partial_token)
)


def complete_set(possible_items, partial_token):
set_items = partial_token.split(",")
partial_item = set_items[-1]
Expand Down Expand Up @@ -167,6 +175,14 @@ def complete_device_config_param(server, requester, argv):
return tuple(f"{name}=" for name in setting_names)


def complete_port_config_param(server, partial_token):
# we will just help the user with the setting names, not the values
if "=" in partial_token:
return ()
return tuple(f"{name}=" for name in
server.port_settings.get_writable_setting_names())


def get_walt_clone_urls(server, username):
# faster than using server.registry
return tuple(
Expand Down Expand Up @@ -248,12 +264,16 @@ def shell_autocomplete_switch(server, requester, username, argv):
return complete_device_config_param(server, requester, argv)
elif arg_type == "DEVICE":
return complete_device(server, partial_token)
elif arg_type == "SWITCH":
return complete_switch(server, partial_token)
elif arg_type == "SET_OF_DEVICES":
return complete_set_of_devices(server, partial_token)
elif arg_type == "RESCAN_SET_OF_DEVICES":
return complete_rescan_set_of_devices(server, partial_token)
elif arg_type == "DEVICE_CONFIG_PARAM":
return complete_device_config_param(server, requester, argv)
elif arg_type == "PORT_CONFIG_PARAM":
return complete_port_config_param(server, partial_token)
elif arg_type == "IMAGE_CLONE_URL":
return complete_image_clone_url(server, username, partial_token)
elif arg_type == "LOG_CHECKPOINT":
Expand Down
3 changes: 2 additions & 1 deletion server/walt/server/processes/main/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from walt.server.processes.main.network.named import DNSServer
from walt.server.processes.main.nodes.manager import NodesManager
from walt.server.processes.main.registry import WalTLocalRegistry
from walt.server.processes.main.settings import SettingsManager
from walt.server.processes.main.settings import SettingsManager, PortSettingsManager
from walt.server.processes.main.devices.expose import ExposeManager
from walt.server.processes.main.transfer import (
TransferManager,
Expand Down Expand Up @@ -53,6 +53,7 @@ def __init__(self, ev_loop, db, blocking):
self.transfer = TransferManager(self.tcp_server, self.ev_loop)
self.nodes = NodesManager(self)
self.settings = SettingsManager(server=self)
self.port_settings = PortSettingsManager(server=self)
self.vpn = VPNManager()
self.expose = ExposeManager(server=self)

Expand Down
Loading

0 comments on commit 8891aee

Please sign in to comment.