Skip to content

Commit a929cd2

Browse files
feat: Adds post-deploy OpenStack Octavia playbook
1 parent f2b3157 commit a929cd2

File tree

10 files changed

+366
-1
lines changed

10 files changed

+366
-1
lines changed

ansible/playbooks/openstack_network.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# License for the specific language governing permissions and limitations
1414
# under the License.
1515

16-
- name: Openstack Network
16+
- name: OpenStack Network
1717
hosts: neutron
1818
connection: local
1919

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
# Copyright (c) 2025 Rackspace Technology, Inc.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
- name: OpenStack Octavia Post Deployment
17+
hosts: neutron
18+
connection: local
19+
20+
pre_tasks:
21+
- name: Fail if ENV variables are not set
22+
ansible.builtin.fail:
23+
msg: "Environment variable {{ item }} is not set. Exiting playbook."
24+
when: lookup('env', item) == ''
25+
loop:
26+
- OS_CLOUD
27+
28+
roles:
29+
- role: openstack_octavia
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
load_balancer_network_name: "lb-mgmt-net"
3+
load_balancer_subnet_name: "lb-mgmt-subnet"
4+
load_balancer_subnet: "172.31.0.0/24"
5+
load_balancer_subnet_start: "172.31.0.10"
6+
load_balancer_subnet_end: "172.31.0.200"
7+
provider_network_type: "ovn"
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
3+
- name: Get network info
4+
openstack.cloud.networks_info:
5+
name: "{{ load_balancer_network_name }}"
6+
register: existing_networks
7+
run_one: true
8+
9+
- name: Create network if not exists
10+
openstack.cloud.network:
11+
name: "{{ load_balancer_network_name }}"
12+
provider_network_type: "{{ provider_network_type }}"
13+
state: present
14+
when: existing_networks | length == 0
15+
run_one: true
16+
17+
- name: Create a new subnet in neutron
18+
openstack.cloud.subnet:
19+
network_name: "{{ load_balancer_network_name }}"
20+
name: "{{ load_balancer_subnet_name }}"
21+
cidr: "{{ load_balancer_subnet }}"
22+
allocation_pool_start: "{{ load_balancer_subnet_start }}"
23+
allocation_pool_end: "{{ load_balancer_subnet_end }}"
24+
state: present
25+
run_one: true
26+
27+
- name: Create a security group
28+
openstack.cloud.security_group:
29+
name: lb-mgmt-sec-grp
30+
state: present
31+
description: security group for octavia load balancers
32+
run_one: true
33+
34+
- name: Create a security group rule
35+
openstack.cloud.security_group_rule:
36+
security_group: lb-mgmt-sec-grp
37+
protocol: icmp
38+
remote_ip_prefix: 0.0.0.0/0
39+
run_one: true
40+
41+
- name: Create a security group rule
42+
openstack.cloud.security_group_rule:
43+
security_group: lb-mgmt-sec-grp
44+
protocol: tcp
45+
port_range_min: 22
46+
port_range_max: 22
47+
remote_ip_prefix: 0.0.0.0/0
48+
run_one: true
49+
50+
- name: Create a security group rule
51+
openstack.cloud.security_group_rule:
52+
security_group: lb-mgmt-sec-grp
53+
protocol: tcp
54+
port_range_min: 9443
55+
port_range_max: 9443
56+
remote_ip_prefix: 0.0.0.0/0
57+
run_one: true
58+
59+
- name: Create a security group for octavia health manager
60+
openstack.cloud.security_group:
61+
name: lb-health-mgr-sec-grp
62+
state: present
63+
description: security group for octavia health manager
64+
run_one: true
65+
66+
- name: Create a health group security rules
67+
openstack.cloud.security_group_rule:
68+
security_group: lb-health-mgr-sec-grp
69+
protocol: udp
70+
port_range_min: 5555
71+
port_range_max: 5555
72+
remote_ip_prefix: 0.0.0.0/0
73+
run_one: true
74+
75+
# We want to create the ports on the ovn nodes. In Understack, we can
76+
# identify those as the nodes having the ansible host var setting
77+
# `ovs_enabled=true`.
78+
- name: Create ports
79+
openstack.cloud.port:
80+
name: "octavia-health-manager-port-{{ item }}"
81+
network: lb-mgmt-net
82+
security_groups: lb-health-mgr-sec-grp
83+
device_owner: "Octavia:health-mgr"
84+
binding_host_id: "{{ item }}"
85+
state: present
86+
with_items: "{{ groups['all']
87+
| map('extract', hostvars)
88+
| selectattr('ovs_enabled', 'defined')
89+
| selectattr('ovs_enabled', 'equalto', true)
90+
| map(attribute='inventory_hostname')
91+
| list }}"
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Load Balancer Configuration
2+
3+
If you decide to use Octavia Load Balancers there are some one-time, post-install
4+
steps to be completed before load balancers can be used.
5+
6+
## Create security groups and their rules
7+
8+
``` bash
9+
openstack security group create lb-mgmt-sec-grp
10+
openstack security group rule create --protocol icmp lb-mgmt-sec-grp
11+
openstack security group rule create --protocol tcp --dst-port 22 lb-mgmt-sec-grp
12+
openstack security group rule create --protocol tcp --dst-port 9443 lb-mgmt-sec-grp
13+
openstack security group create lb-health-mgr-sec-grp
14+
openstack security group rule create --protocol udp --dst-port 5555 lb-health-mgr-sec-grp
15+
```
16+
17+
## Create a network
18+
19+
During the execution of the below command, please save the of BRNAME and MGMT_PORT_MAC in a notepad for further reference.
20+
21+
``` bash
22+
OCTAVIA_MGMT_SUBNET=172.16.0.0/12
23+
OCTAVIA_MGMT_SUBNET_START=172.16.0.100
24+
OCTAVIA_MGMT_SUBNET_END=172.16.31.254
25+
OCTAVIA_MGMT_PORT_IP=172.16.0.2
26+
27+
openstack network create lb-mgmt-net
28+
openstack subnet create --subnet-range $OCTAVIA_MGMT_SUBNET --allocation-pool \
29+
start=$OCTAVIA_MGMT_SUBNET_START,end=$OCTAVIA_MGMT_SUBNET_END \
30+
--network lb-mgmt-net lb-mgmt-subnet
31+
32+
SUBNET_ID=$(openstack subnet show lb-mgmt-subnet -f value -c id)
33+
PORT_FIXED_IP="--fixed-ip subnet=$SUBNET_ID,ip-address=$OCTAVIA_MGMT_PORT_IP"
34+
35+
MGMT_PORT_ID=$(openstack port create --security-group \
36+
lb-health-mgr-sec-grp --device-owner Octavia:health-mgr \
37+
--host=$(hostname) -c id -f value --network lb-mgmt-net \
38+
PORT_FIXED_IP octavia-health-manager-listen-port)
39+
40+
MGMT_PORT_MAC=$(openstack port show -c mac_address -f value \
41+
MGMT_PORT_ID)
42+
```
43+
44+
45+
``` bash
46+
OSH_LB_SUBNET="172.31.0.0/24"
47+
OSH_LB_SUBNET_START="172.31.0.2"
48+
OSH_LB_SUBNET_END="172.31.0.200"
49+
50+
openstack network create lb-mgmt-net -f value -c id
51+
openstack subnet create --subnet-range $OSH_LB_SUBNET --allocation-pool start=$OSH_LB_SUBNET_START,end=$OSH_LB_SUBNET_END --network lb-mgmt-net lb-mgmt-subnet -f value -c id
52+
openstack security group create lb-mgmt-sec-grp
53+
openstack security group rule create --protocol icmp lb-mgmt-sec-grp
54+
openstack security group rule create --protocol tcp --dst-port 22 lb-mgmt-sec-grp
55+
openstack security group rule create --protocol tcp --dst-port 9443 lb-mgmt-sec-grp
56+
57+
# Create security group for Octavia health manager
58+
openstack security group create lb-health-mgr-sec-grp
59+
openstack security group rule create --protocol udp --dst-port 5555 lb-health-mgr-sec-grp
60+
```
61+
62+
``` bash
63+
node=1327172-hp1
64+
PORTNAME=octavia-health-manager-port-1327172-hp1
65+
66+
openstack port create --security-group lb-health-mgr-sec-grp --device-owner Octavia:health-mgr --host=$node -c id -f value --network lb-mgmt-net $PORTNAME
67+
IP=$(openstack port show $PORTNAME -c fixed_ips -f value | awk -F',' '{print $1}' | awk -F'=' '{print $2}' | tr -d \')
68+
echo $IP
69+
```
70+
71+
``` bash
72+
NETWORK_NODES=$(kubectl get nodes -l openstack-network-node=enabled -o name | awk -F"/" '{print $2}')
73+
for node in $NETWORK_NODES; do
74+
75+
done
76+
77+
```
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Testing and Verification
2+
3+
After deploying a new Understack, we have a few tools available to help us test our new deployment
4+
and ensure everything is working.
5+
6+
## OpenStack Tempest
7+
8+
We'll use [OpenStack Tempest](https://docs.openstack.org/tempest/latest/index.html)
9+
to quickly perform API tests against Understack.
10+
11+
Here's a small example using tempest to run keypair tests against an Understack instance:
12+
13+
``` text
14+
$ tempest run --concurrency 1 --serial --include-list include-keypair.txt
15+
{0} tempest.api.compute.keypairs.test_keypairs.KeyPairsV2TestJSON.test_get_keypair_detail [1.563604s] ... ok
16+
{0} tempest.api.compute.keypairs.test_keypairs.KeyPairsV2TestJSON.test_keypair_create_delete [0.884011s] ... ok
17+
{0} tempest.api.compute.keypairs.test_keypairs.KeyPairsV2TestJSON.test_keypair_create_with_pub_key [0.893123s] ... ok
18+
{0} tempest.api.compute.keypairs.test_keypairs.KeyPairsV2TestJSON.test_keypairs_create_list_delete [3.178549s] ... ok
19+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_create_keypair_invalid_name [0.589208s] ... ok
20+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_create_keypair_when_public_key_bits_exceeds_maximum [0.432699s] ... ok
21+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_create_keypair_with_duplicate_name [1.471715s] ... ok
22+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_create_keypair_with_empty_name_string [0.540209s] ... ok
23+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_create_keypair_with_empty_public_key [0.440568s] ... ok
24+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_create_keypair_with_long_keynames [0.435756s] ... ok
25+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_keypair_create_with_invalid_pub_key [0.479691s] ... ok
26+
{0} tempest.api.compute.keypairs.test_keypairs_negative.KeyPairsNegativeTestJSON.test_keypair_delete_nonexistent_key [0.509478s] ... ok
27+
28+
======
29+
Totals
30+
======
31+
Ran: 12 tests in 12.3828 sec.
32+
- Passed: 12
33+
- Skipped: 0
34+
- Expected Fail: 0
35+
- Unexpected Success: 0
36+
- Failed: 0
37+
Sum of execute time for each test: 11.4186 sec.
38+
39+
==============
40+
Worker Balance
41+
==============
42+
- Worker 0 (12 tests) => 0:00:12.382768
43+
```
44+
45+
## OpenStack Rally
46+
47+
We'll also use [OpenStack Rally](https://docs.openstack.org/rally/latest/) to run integration and scenario tests.
48+
49+
See the [understack-tests](https://github.com/rackerlabs/understack/tree/main/python/understack-tests) in the understack repo
50+
for docs on running our rally scenarios.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Deployment Troubleshooting
2+
3+
We have documentation for individual components in the [Operator Guide](../operator-guide/index.md).
4+
5+
## ArgoCD Stuck Syncing
6+
7+
We have seen ArgoCD can sometimes become "stuck" while processing deployments. Sometimes
8+
this can be due to the app component running a kubernetes job which gets stuck indefinitely.
9+
10+
For example, some openstack-helm components have init jobs which depends on other steps being
11+
completed or may have a misconfiguration, where the init will loop forever. In argo you can
12+
see what jobs are stuck, then check the kubernetes job pod logs for further details. Note that
13+
a lot of OpenStack pods may have multiple containers, so interesting logs may not be in the
14+
default container output.
15+
16+
In argo, we've also seen it can be helpful to terminate an old sync and issue a new sync.

mkdocs.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ nav:
132132
- deploy-guide/config-argo-workflows.md
133133
- Starting the Deployment:
134134
- deploy-guide/management-cluster.md
135+
- Post Deployment:
136+
- deploy-guide/load-balancers.md
137+
- deploy-guide/testing-verification.md
138+
- deploy-guide/troubleshooting.md
135139
- Further Actions:
136140
- deploy-guide/extra-sites.md
137141
- deploy-guide/add-remove-app.md
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: argoproj.io/v1alpha1
2+
kind: EventSource
3+
metadata:
4+
name: k8s-openstack-octavia
5+
namespace: openstack
6+
spec:
7+
template:
8+
serviceAccountName: k8s-openstack-events
9+
# Kubernetes resource event sources
10+
resource:
11+
octavia-deployment:
12+
# monitor deployment resources under openstack namespace
13+
namespace: openstack
14+
resource: deployments
15+
group: apps
16+
version: v1
17+
# Event types to listen for (e.g., ADD, UPDATE, DELETE). Here we want only when deployment is created.
18+
eventTypes:
19+
- ADD
20+
filter:
21+
# filter based these labels to match octavia-api deployment
22+
labels:
23+
- key: application
24+
value: octavia
25+
- key: component
26+
value: api
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
apiVersion: argoproj.io/v1alpha1
3+
kind: Sensor
4+
metadata:
5+
name: octavia-deployment
6+
namespace: openstack
7+
spec:
8+
template:
9+
serviceAccountName: k8s-openstack-events
10+
# events the Sensor listens for
11+
dependencies:
12+
- eventName: octavia-deployment
13+
eventSourceName: k8s-openstack-octavia
14+
name: openstack-octavia-server-deployment
15+
# actions executed when dependencies are satisfied (StandardK8STrigger designed to create or update a generic Kubernetes resource.)
16+
triggers:
17+
- template:
18+
name: octavia-post-deploy
19+
k8s:
20+
operation: create
21+
source:
22+
resource:
23+
apiVersion: batch/v1
24+
kind: Job
25+
metadata:
26+
generateName: octavia-post-deploy-job
27+
spec:
28+
template:
29+
spec:
30+
containers:
31+
- name: octavia-post-deploy
32+
image: ghcr.io/rackerlabs/understack/ansible:latest
33+
imagePullPolicy: Always
34+
command: ["ansible-runner", "run", "/runner", "--playbook", "openstack_octavia.yaml"]
35+
env:
36+
- name: OS_CLOUD
37+
value: understack
38+
volumeMounts:
39+
- name: ansible-inventory
40+
mountPath: /runner/inventory/hosts.yaml
41+
subPath: hosts.yaml
42+
- name: ansible-kubernetes-inventory
43+
mountPath: /runner/inventory/inventory.yaml
44+
subPath: inventory.yaml
45+
- name: ansible-group-vars
46+
mountPath: /runner/inventory/group_vars/
47+
- name: openstack-svc-acct
48+
mountPath: /etc/openstack
49+
readOnly: true
50+
volumes:
51+
- name: runner-data
52+
emptyDir: {}
53+
- name: ansible-inventory
54+
configMap:
55+
name: ansible-inventory
56+
- name: ansible-kubernetes-inventory
57+
configMap:
58+
name: ansible-kubernetes-inventory
59+
- name: ansible-group-vars
60+
configMap:
61+
name: ansible-group-vars
62+
- name: openstack-svc-acct
63+
secret:
64+
secretName: openstack-svc-acct
65+
restartPolicy: OnFailure

0 commit comments

Comments
 (0)