Skip to content

Commit 2f3f92e

Browse files
committed
Add sno-nxsw scenario with NGS and POAP automation
Introduces Single Node OpenShift scenario with Cisco NX-OS switch integration, featuring automated POAP configuration and OpenStack ML2 generic switch plugin for dynamic switch port VLAN management.
1 parent d9b7965 commit 2f3f92e

22 files changed

Lines changed: 3268 additions & 2 deletions

.gitleaks.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
# Ignore control-plane.yaml
66
'''\.*/control-plane.yaml''',
77
'''\.*/defaults/main.yml''',
8+
# Ignore poap.cfg
9+
'''scenarios/.*/poap.cfg''',
810
]

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ repos:
5050
- pyyaml
5151
files: nncp.(yaml|yml)$
5252
types: [file, yaml]
53+
- id: poap-md5sum-management
54+
name: Format POAP script with md5sum management
55+
entry: scenarios/sno-nxsw/manage-poap-md5sum.sh
56+
language: system
57+
files: ^scenarios/sno-nxsw/poap\.py$
58+
pass_filenames: false
5359

5460
- repo: https://github.com/ansible/ansible-lint
5561
rev: v6.22.2

docs/virtual_switches.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Using virtual switches with Hotstack
2+
3+
```bash
4+
openstack image create hotstack-switch \
5+
--disk-format qcow2 \
6+
--file <switch-image-file> \
7+
--property hw_firmware_type=uefi \
8+
--property hw_machine_type=q35 --public
9+
```

scenarios/snapshot-sno/heat_template.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,30 @@ resources:
175175
[main]
176176
rc-manager=unmanaged
177177
owner: root:root
178+
- path: /etc/dnsmasq.d/tftpboot.conf
179+
content: |
180+
enable-tftp
181+
tftp-root=/var/lib/tftpboot
182+
tftp-mtu=1442
183+
owner: root:root
184+
- path: /var/lib/tftpboot/poap.py
185+
content: {get_file: ../sno-nxsw/poap.py}
186+
owner: root:root
187+
- path: /var/lib/tftpboot/poap.cfg
188+
content: {get_file: ../sno-nxsw/poap.cfg}
189+
owner: root:root
178190

179191
controller-runcmd:
180192
type: OS::Heat::CloudConfig
181193
properties:
182194
cloud_config:
183195
runcmd:
184-
- ['systemctl', 'enable', 'dnsmasq.service']
185-
- ['systemctl', 'start', 'dnsmasq.service']
186196
- ['setenforce', 'permissive']
187197
- ['sed', '-i', 's/Listen 80/Listen 8081/g', '/etc/httpd/conf/httpd.conf']
188198
- ['systemctl', 'enable', 'httpd.service']
189199
- ['systemctl', 'start', 'httpd.service']
200+
- ['systemctl', 'enable', 'dnsmasq.service']
201+
- ['systemctl', 'start', 'dnsmasq.service']
190202

191203
controller-init:
192204
type: OS::Heat::MultipartMime

scenarios/sno-nxsw/README.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# SNO-NXSW Scenario
2+
3+
## Overview
4+
5+
The `sno-nxsw` scenario is a Single Node OpenShift (SNO) deployment scenario
6+
for HotStack that deploys OpenStack on OpenShift with ironic bare metal
7+
provisioning capabilities and network switch integration.
8+
9+
## Architecture
10+
11+
This scenario provisions:
12+
13+
- **1x Controller Node**: Management and DNS/DHCP services
14+
- **1x OpenShift Master Node**: Single node OpenShift cluster running OpenStack services
15+
- **1x Switch Node**: NXSW switch with trunk ports for tenant VLAN networks
16+
- **2x Ironic Nodes**: Virtual bare metal nodes for testing Ironic provisioning workflows
17+
18+
## Features
19+
20+
- **Complete OpenStack Stack**: Full OpenStack deployment with ironic bare
21+
metal service
22+
- **Network Switch Integration**: Automated switch configuration with
23+
POAP (Power-On Auto Provisioning) and NGS (Networking Generic Switch)
24+
- **Complete Networking**: All OpenStack service networks with dedicated
25+
ironic networks
26+
- **SNO Deployment**: Single node OpenShift optimized for OpenStack services
27+
- **Development Ready**: Ideal for testing and development environments
28+
- **Bare Metal Provisioning**: Ironic service with 2 nodes for testing bare
29+
metal workflows
30+
31+
## Networks
32+
33+
- **machine-net**: 192.168.32.0/24 - External access network
34+
- **ctlplane-net**: 192.168.122.0/24 - Control plane network
35+
- **internal-api-net**: 172.17.0.0/24 - OpenStack internal API network
36+
- **storage-net**: 172.18.0.0/24 - Storage network
37+
- **tenant-net**: 172.19.0.0/24 - Tenant network for OpenStack workloads
38+
- **ironic-net**: 172.20.1.0/24 - Ironic network for bare metal provisioning
39+
- **tenant-vlan103**: 172.20.3.0/24 - Tenant VLAN network (VLAN 103)
40+
- **tenant-vlan104**: 172.20.4.0/24 - Tenant VLAN network (VLAN 104)
41+
- **ironic0-br-net**: 172.20.5.0/29 - Ironic0 bridge network
42+
- **ironic1-br-net**: 172.20.5.8/29 - Ironic1 bridge network
43+
44+
## Switch Instance Configuration
45+
46+
The switch instance provides network switching capabilities with the following
47+
interface configuration:
48+
49+
### Network Interface Summary
50+
51+
```text
52+
Switch Instance:
53+
├── eth0: machine-net (management interface)
54+
├── eth1: trunk (ironic:101, tenant-vlan103:103, tenant-vlan104:104)
55+
├── eth2: ironic0-br-net (ironic bridge network)
56+
└── eth3: ironic1-br-net (ironic bridge network)
57+
```
58+
59+
### VLAN Mapping
60+
61+
- **VLAN 101**: ironic (172.20.1.0/24)
62+
- **VLAN 102**: Default native VLAN
63+
- **VLAN 103**: tenant-vlan103 (172.20.3.0/24)
64+
- **VLAN 104**: tenant-vlan104 (172.20.4.0/24)
65+
66+
The switch uses the `nxsw` image and provides dual trunk ports for redundancy
67+
and high availability.
68+
69+
### POAP (Power-On Auto Provisioning)
70+
71+
POAP is a Cisco NX-OS feature that automates the initial configuration of
72+
network switches. When the switch boots up, it automatically:
73+
74+
1. **Downloads Configuration**: Fetches the switch configuration from a
75+
TFTP/HTTP server
76+
2. **Applies Settings**: Automatically configures interfaces, VLANs, and
77+
network settings
78+
3. **Enables Services**: Activates required network services (NETCONF, LACP, LLDP)
79+
4. **Validates Setup**: Performs integrity checks using MD5 checksums
80+
81+
In this scenario, POAP enables zero-touch deployment of the NX-OS switch with pre-configured:
82+
83+
- **Interface Configuration**: Trunk and access ports for tenant VLANs
84+
- **VLAN Setup**: VLANs for network segmentation
85+
- **Management Settings**: IP addressing, DNS, and routing configuration
86+
- **Security**: User accounts and access control
87+
88+
## Ironic Nodes
89+
90+
The scenario includes 2 virtual bare metal nodes for testing Ironic provisioning:
91+
92+
### Ironic Node 0
93+
94+
- **Network**: ironic0-br-net (172.20.5.0/29)
95+
- **Purpose**: Bare metal provisioning testing
96+
- **Configuration**: Virtual media boot capable with sushy-tools
97+
98+
### Ironic Node 1
99+
100+
- **Network**: ironic1-br-net (172.20.5.8/29)
101+
- **Purpose**: Bare metal provisioning testing
102+
- **Configuration**: Virtual media boot capable with sushy-tools
103+
104+
## Usage
105+
106+
This scenario is ideal for:
107+
108+
- Testing OpenStack deployments with neutron ML2 plugins
109+
- Validating bare metal provisioning workflows with Ironic
110+
- Network switch integration testing with OpenStack
111+
- Development and testing of networking-generic-switch functionality
112+
113+
## Files
114+
115+
- `bootstrap_vars.yml`: Main configuration variables
116+
- `heat_template.yaml`: OpenStack Heat template for infrastructure
117+
- `automation-vars.yml`: Automation pipeline definition
118+
- `manifests/`: OpenShift/Kubernetes manifests
119+
- `test-operator/`: Test automation configuration
120+
121+
## Switch image preparation
122+
123+
Due to an issue with some virtual hardware, where the EEPROM checksum is
124+
incorrect for the e1000 NIC the NXOS image must be modified to include a kernel
125+
module option `eeprom_bad_csum_allow=1` for the virtual e1000 network interface
126+
to work.
127+
128+
```bash
129+
guestfish --rw --add <nxos-img> --mount /dev/sda6:/ edit /boot/grub/menu.lst.local
130+
```
131+
132+
Add the module parameter `e1000.eeprom_bad_csum_allow=1` at the end of the
133+
line starting with `cmdline`.
134+
135+
> **NOTE**: The eeprom_bad_csum_allow only works on v.9.x.x images, the module
136+
> option does not seem to exist on later kernels?
137+
138+
## Upload switch image to cloud
139+
140+
The images are very particular when it comes to what hardware is supported,
141+
when the image ensure to set the properties as shown in the example below.
142+
143+
```bash
144+
openstack image create nexus9300v.9.3.15\
145+
--disk-format qcow2 \
146+
--file nexus9300v.9.3.15.qcow2 \
147+
--public \
148+
--property hw_disk_bus=sata \
149+
--property hw_vif_model=e1000 \
150+
--property hw_video_model=none \
151+
--property hw_firmware_type=uefi \
152+
--property hw_machine_type=q35 \
153+
--property os_type=linux \
154+
--property hw_boot_menu=true
155+
```
156+
157+
## Deployment
158+
159+
Follow the standard HotStack deployment process with this scenario by setting
160+
the scenario name to `sno-nxsw` in your deployment configuration.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
stages:
3+
- name: Dependencies
4+
stages: >-
5+
{{
6+
lookup("ansible.builtin.template",
7+
"common/stages/deps-stages.yaml.j2")
8+
}}
9+
10+
- name: Cinder LVM
11+
stages: >-
12+
{{
13+
lookup("ansible.builtin.file",
14+
"common/stages/cinder-lvm-label-stages.yaml")
15+
}}
16+
17+
- name: TopoLVM
18+
stages: >-
19+
{{
20+
lookup("ansible.builtin.template",
21+
"common/stages/topolvm-stages.yaml.j2")
22+
}}
23+
24+
- name: OLM Openstack
25+
stages: >-
26+
{{
27+
lookup("ansible.builtin.template",
28+
"common/stages/olm-openstack-stages.yaml.j2")
29+
}}
30+
31+
- name: NodeNetworkConfigurationPolicy (nncp)
32+
manifest: manifests/networking/nncp.yaml
33+
wait_conditions:
34+
- >-
35+
oc wait -n openstack nncp -l osp/nncm-config-type=standard
36+
--for jsonpath='{.status.conditions[0].reason}'=SuccessfullyConfigured
37+
--timeout=180s
38+
39+
- name: NetworkAttchmentDefinition (NAD)
40+
manifest: manifests/networking/nad.yaml
41+
42+
- name: MetalLB - L2Advertisement and IPAddressPool
43+
manifest: manifests/networking/metallb.yaml
44+
45+
- name: Netconfig
46+
manifest: manifests/networking/netconfig.yaml
47+
48+
- name: NGS config (Networking Generic Switch)
49+
manifest: manifests/ngs/config.yaml
50+
wait_conditions:
51+
- >-
52+
oc wait -n openstack secret neutron-switch-config
53+
--for jsonpath='{.metadata.name}'=neutron-switch-config
54+
--timeout=30s
55+
56+
- name: Openstack Version
57+
manifest: manifests/openstack-version.yaml
58+
patches:
59+
- path: spec.customContainerImages
60+
value: "{{ customContainerImages }}"
61+
wait_conditions:
62+
- >-
63+
oc wait -n openstack openstackversions.core.openstack.org controlplane
64+
--for condition=Initialized --timeout=30m
65+
run_conditions:
66+
- >-
67+
{{ customContainerImages is defined and customContainerImages | length > 0 }}
68+
69+
- name: OpenstackControlPlane
70+
manifest: manifests/control-plane.yaml
71+
wait_conditions:
72+
- >-
73+
oc wait -n openstack openstackcontrolplane controlplane
74+
--for condition=Ready --timeout=30m
75+
76+
- name: Update openstack-operators OLM
77+
stages: >-
78+
{{
79+
lookup('ansible.builtin.template',
80+
'common/stages/openstack-olm-update.yaml.j2')
81+
}}
82+
run_conditions:
83+
- >-
84+
{{
85+
openstack_operators_update is defined and
86+
openstack_operators_update | bool
87+
}}
88+
89+
- name: Wait for condition MinorUpdateAvailable True
90+
wait_conditions:
91+
- >-
92+
oc -n openstack wait openstackversions.core.openstack.org controlplane
93+
--for=condition=MinorUpdateAvailable=True --timeout=10m
94+
run_conditions:
95+
- "{{ openstack_update is defined and openstack_update | bool }}"
96+
97+
- name: "Minor update :: Create OpenStackVersion patch"
98+
documentation: |
99+
This creates a patch file `{{ manifests_dir }}/patches/openstack_version_patch.yaml`
100+
If `openstack_update_custom_images` is defined it will populate the customContainerImages
101+
in the OpenstackVersion YAML patch.
102+
shell: >-
103+
{{
104+
lookup('ansible.builtin.template',
105+
'common/scripts/create_openstack_version_patch.sh.j2')
106+
}}
107+
run_conditions:
108+
- "{{ openstack_update is defined and openstack_update | bool }}"
109+
110+
- name: "Minor update :: Update the target version in the OpenStackVersion custom resource (CR)"
111+
documentation: |
112+
The `hotstack-openstack-version-patch` script will get the `availableVersion`
113+
and us it to replace the string `__TARGET_VERSION__` in the patch file and
114+
apply the patch using `oc patch` command.
115+
command: >-
116+
hotstack-openstack-version-patch --namespace openstack --name controlplane
117+
--file {{ manifests_dir }}/patches/openstack_version_patch.yaml
118+
wait_conditions:
119+
- oc -n openstack wait openstackversions.core.openstack.org controlplane
120+
--for=condition=Ready --timeout=10m
121+
run_conditions:
122+
- "{{ openstack_update is defined and openstack_update | bool }}"

0 commit comments

Comments
 (0)