Skip to content

Commit b78d0a8

Browse files
authored
Merge branch 'stackhpc/2024.1' into upstream/2024.1-2025-06-30
2 parents dc142ec + 3ce9491 commit b78d0a8

22 files changed

+740
-6
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @stackhpc/openstack
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
name: Tag & Release
3+
'on':
4+
push:
5+
branches:
6+
- stackhpc/2024.1
7+
permissions:
8+
actions: read
9+
contents: write
10+
jobs:
11+
tag-and-release:
12+
uses: stackhpc/.github/.github/workflows/tag-and-release.yml@main

.github/workflows/tox.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
name: Tox Continuous Integration
3+
'on':
4+
pull_request:
5+
jobs:
6+
tox:
7+
uses: stackhpc/.github/.github/workflows/tox.yml@main

doc/source/configuration.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,16 @@ for a Cumulus Linux device::
184184
secret = secret
185185
ngs_mac_address = <switch mac address>
186186

187+
for a Cumulus NVUE Linux device::
188+
189+
[genericswitch:hostname-for-cumulus]
190+
device_type = netmiko_cumulus_nvue
191+
ip = <switch mgmt_ip address>
192+
username = admin
193+
password = password
194+
secret = secret
195+
ngs_mac_address = <switch mac address>
196+
187197
for the Nokia SRL series device::
188198

189199
[genericswitch:sw-hostname]

doc/source/supported-devices.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The following devices are supported by this plugin:
1111
* Cisco IOS switches
1212
* Cisco NX-OS switches (Nexus)
1313
* Cumulus Linux (via NCLU)
14+
* Cumulus Linux (via NVUE)
1415
* Dell Force10
1516
* Dell OS10
1617
* Dell PowerConnect

networking_generic_switch/devices/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
{'name': 'ngs_network_name_format', 'default': '{network_id}'},
4747
# If false, ngs will not add and delete VLANs from switches
4848
{'name': 'ngs_manage_vlans', 'default': True},
49+
{'name': 'vlan_translation_supported', 'default': False},
4950
# If False, ngs will skip saving configuration on devices
5051
{'name': 'ngs_save_configuration', 'default': True},
5152
# When true try to batch up in flight switch requests
@@ -187,6 +188,10 @@ def add_network(self, segmentation_id, network_id):
187188
def del_network(self, segmentation_id, network_id):
188189
pass
189190

191+
def plug_port_to_network_trunk(self, port_id, segmentation_id,
192+
trunk_details=None, vtr=False):
193+
pass
194+
190195
@abc.abstractmethod
191196
def plug_port_to_network(self, port_id, segmentation_id):
192197
pass

networking_generic_switch/devices/netmiko_devices/__init__.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class NetmikoSwitch(devices.GenericSwitchDevice):
9090

9191
SAVE_CONFIGURATION = None
9292

93+
SET_NATIVE_VLAN = None
94+
95+
ALLOW_NETWORK_ON_TRUNK = None
96+
9397
ERROR_MSG_PATTERNS = ()
9498
"""Sequence of error message patterns.
9599
@@ -301,6 +305,28 @@ def del_network(self, segmentation_id, network_id):
301305
network_name=network_name)
302306
return self.send_commands_to_device(cmds)
303307

308+
@check_output('plug port trunk')
309+
def plug_port_to_network_trunk(self, port, segmentation_id,
310+
trunk_details=None, vtr=False):
311+
cmd_set = []
312+
vts = self.ngs_config.get('vlan_translation_supported', False)
313+
# NOTE(vsaienko) Always use vlan translation if it is supported.
314+
if vts:
315+
cmd_set.extend(self.get_trunk_port_cmds_vlan_translation(
316+
port, segmentation_id, trunk_details))
317+
else:
318+
if vtr:
319+
msg = ("Cannot bind_port VLAN aware port as switch %s "
320+
"doesn't support VLAN translation. "
321+
"But it is required.") % self.config['ip']
322+
raise exc.GenericSwitchNotSupported(error=msg)
323+
else:
324+
cmd_set.extend(
325+
self.get_trunk_port_cmds_no_vlan_translation(
326+
port, segmentation_id, trunk_details))
327+
328+
self.send_commands_to_device(cmd_set)
329+
304330
@check_output('plug port')
305331
def plug_port_to_network(self, port, segmentation_id):
306332
cmds = []
@@ -442,3 +468,22 @@ def check_output(self, output, operation):
442468
raise exc.GenericSwitchNetmikoConfigError(
443469
config=device_utils.sanitise_config(self.config),
444470
error=msg)
471+
472+
def get_trunk_port_cmds_no_vlan_translation(self, port_id,
473+
segmentation_id,
474+
trunk_details):
475+
cmd_set = []
476+
cmd_set.extend(
477+
self._format_commands(self.SET_NATIVE_VLAN,
478+
port=port_id,
479+
segmentation_id=segmentation_id))
480+
for sub_port in trunk_details.get('sub_ports'):
481+
cmd_set.extend(
482+
self._format_commands(
483+
self.ALLOW_NETWORK_ON_TRUNK, port=port_id,
484+
segmentation_id=sub_port['segmentation_id']))
485+
return cmd_set
486+
487+
def get_trunk_port_cmds_vlan_translation(self, port_id, segmentation_id,
488+
trunk_details):
489+
pass

networking_generic_switch/devices/netmiko_devices/arista.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,15 @@ class AristaEos(netmiko_devices.NetmikoSwitch):
3737
'no switchport mode trunk',
3838
'switchport trunk allowed vlan none'
3939
)
40+
41+
SET_NATIVE_VLAN = (
42+
'interface {port}',
43+
'switchport mode trunk',
44+
'switchport trunk native vlan {segmentation_id}',
45+
'switchport trunk allowed vlan add {segmentation_id}'
46+
)
47+
48+
ALLOW_NETWORK_ON_TRUNK = (
49+
'interface {port}',
50+
'switchport trunk allowed vlan add {segmentation_id}'
51+
)

networking_generic_switch/devices/netmiko_devices/cisco.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ class CiscoIos(netmiko_devices.NetmikoSwitch):
3939
'switchport trunk allowed vlan none'
4040
)
4141

42+
SET_NATIVE_VLAN = (
43+
'interface {port}',
44+
'switchport mode trunk',
45+
'switchport trunk native vlan {segmentation_id}',
46+
'switchport trunk allowed vlan add {segmentation_id}'
47+
)
48+
49+
ALLOW_NETWORK_ON_TRUNK = (
50+
'interface {port}',
51+
'switchport trunk allowed vlan add {segmentation_id}'
52+
)
53+
4254

4355
class CiscoNxOS(netmiko_devices.NetmikoSwitch):
4456
"""Netmiko device driver for Cisco Nexus switches running NX-OS."""

networking_generic_switch/devices/netmiko_devices/cumulus.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,93 @@ class Cumulus(netmiko_devices.NetmikoSwitch):
8787
re.compile(r'command not found'),
8888
re.compile(r'is not a physical interface on this switch'),
8989
]
90+
91+
92+
class CumulusNVUE(netmiko_devices.NetmikoSwitch):
93+
"""Built for Cumulus 5.x
94+
95+
Note for this switch you want config like this,
96+
where secret is the password needed for sudo su:
97+
98+
[genericswitch:<hostname>]
99+
device_type = netmiko_cumulus
100+
ip = <ip>
101+
username = <username>
102+
password = <password>
103+
secret = <password for sudo>
104+
ngs_physical_networks = physnet1
105+
ngs_max_connections = 1
106+
ngs_port_default_vlan = 123
107+
ngs_disable_inactive_ports = False
108+
"""
109+
NETMIKO_DEVICE_TYPE = "linux"
110+
111+
ADD_NETWORK = [
112+
'nv set bridge domain br_default vlan {segmentation_id}',
113+
]
114+
115+
DELETE_NETWORK = [
116+
'nv unset bridge domain br_default vlan {segmentation_id}',
117+
]
118+
119+
PLUG_PORT_TO_NETWORK = [
120+
'nv unset interface {port} bridge domain br_default vlan',
121+
'nv unset interface {port} bridge domain br_default untagged',
122+
'nv set interface {port} bridge domain br_default access '
123+
'{segmentation_id}',
124+
]
125+
126+
DELETE_PORT = [
127+
'nv unset interface {port} bridge domain br_default access',
128+
]
129+
130+
ENABLE_PORT = [
131+
'nv set interface {port} link state up',
132+
]
133+
134+
DISABLE_PORT = [
135+
'nv set interface {port} link state down',
136+
]
137+
138+
SAVE_CONFIGURATION = [
139+
'nv config save',
140+
]
141+
142+
SET_NATIVE_VLAN = [
143+
'nv unset interface {port} bridge domain br_default access',
144+
'nv set interface {port} bridge domain br_default untagged '
145+
'{segmentation_id}',
146+
'nv set interface {port} bridge domain br_default vlan '
147+
'{segmentation_id}'
148+
]
149+
ALLOW_NETWORK_ON_TRUNK = [
150+
'nv set interface {port} bridge domain br_default vlan '
151+
'{segmentation_id}'
152+
]
153+
154+
ERROR_MSG_PATTERNS = [
155+
# Its tempting to add this error message, but as only one
156+
# bridge-access is allowed, we ignore that error for now:
157+
# re.compile(r'configuration does not have "bridge-access')
158+
re.compile(r'Invalid config'),
159+
re.compile(r'Config invalid at'),
160+
re.compile(r'ERROR: Command not found.'),
161+
re.compile(r'command not found'),
162+
re.compile(r'is not a physical interface on this switch'),
163+
re.compile(r'Error: Invalid parameter'),
164+
]
165+
166+
def send_config_set(self, net_connect, cmd_set):
167+
"""Send a set of configuration lines to the device.
168+
169+
:param net_connect: a netmiko connection object.
170+
:param cmd_set: a list of configuration lines to send.
171+
:returns: The output of the configuration commands.
172+
"""
173+
cmd_set.append('nv config apply --assume-yes')
174+
# NOTE: Do not exit config mode because save needs elevated
175+
# privileges
176+
return net_connect.send_config_set(config_commands=cmd_set,
177+
cmd_verify=False,
178+
enter_config_mode=False,
179+
exit_config_mode=False)

0 commit comments

Comments
 (0)