Skip to content

Commit 14168c4

Browse files
dlaw4608claude
andcommitted
Add Availability Zones (AZ) scenario support
Port the Nova + Cinder Availability Zones scenario from the legacy openshift-ir-plugin / rhos-infrared automation into the shiftstack-qa stages. The AZ job installs OCP IPI on OpenStack with one Nova aggregate per compute host (one AZ each), OCP masters/workers distributed evenly across the AZs, and rootVolumes placed on per-AZ Cinder backends. Post- install verification asserts the OCP nodes and their root volumes landed in the expected Nova and Cinder AZs. Stages/roles: - prepare: configure_az.yml creates host aggregates + per-AZ volume types, configure_az_ceph_crush.yml pins each per-AZ pool to its host-local OSDs. - install: discovers Nova/Cinder AZs (tools_cluster_checks/discover_az.yml) and renders zones + per-AZ rootVolume types/zones into install-config. - verification: check_azs.yml verifies Nova and Cinder AZ placement. - day2ops: scaleup_worker and cinder_registry (AZ-aware registry storage). - cleanup: remove_az.yml tears down aggregates and AZ volume types, gated by az_remove_on_cleanup. - jobs_definitions/availability_zones_4.22_nightly.yaml wires it together. All AZ behaviour is gated behind az_enable / openshift_root_volumes (default false), so non-AZ jobs are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Change-Id: I45bdf61b3bc8e270c950e2e07590a736a9cd81ce Signed-off-by: Daniel Lawton <dlawton@redhat.com>
1 parent f8bd928 commit 14168c4

16 files changed

Lines changed: 795 additions & 2 deletions

File tree

collection/stages/roles/cleanup/defaults/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
# Set the OpenShift installation type to None
55
existing_ocp_installation_type: ""
66
force_cleanup: false
7+
az_remove_on_cleanup: false
8+
az_volume_type_prefix: "fastpool-"
9+
az_volume_type_count: 3

collection/stages/roles/cleanup/tasks/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
- name: Discover the OpenShift installation type
6969
ansible.builtin.include_tasks: detect_ocp_installation.yml
7070

71+
- name: Remove availability zone configuration from OpenStack
72+
ansible.builtin.include_tasks: remove_az.yml
73+
when: az_remove_on_cleanup | default(false) | bool
74+
7175
- name: Cleanup IPv6 secondary network resources if they exist
7276
ansible.builtin.include_tasks: cleanup_ipv6_secondary.yml
7377
when: ocp_deployment_topology.secondary_ip_protocol | default('') == 'ipv6'
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
- name: Discover existing host aggregates
3+
ansible.builtin.command:
4+
cmd: openstack aggregate list -c Name -f value
5+
environment:
6+
OS_CLOUD: "{{ admin_cloud }}"
7+
register: az_existing_aggregates
8+
changed_when: false
9+
10+
- name: Remove hosts from existing aggregates
11+
openstack.cloud.host_aggregate:
12+
cloud: "{{ admin_cloud }}"
13+
state: present
14+
name: "{{ item }}"
15+
hosts: []
16+
loop: "{{ az_existing_aggregates.stdout_lines }}"
17+
when: az_existing_aggregates.stdout_lines | length > 0
18+
19+
- name: Delete existing host aggregates
20+
openstack.cloud.host_aggregate:
21+
cloud: "{{ admin_cloud }}"
22+
state: absent
23+
name: "{{ item }}"
24+
loop: "{{ az_existing_aggregates.stdout_lines }}"
25+
when: az_existing_aggregates.stdout_lines | length > 0
26+
27+
- name: Show nova host AZ mapping after aggregate cleanup
28+
ansible.builtin.command:
29+
cmd: openstack host list -c Zone -c "Host Name" -f table
30+
environment:
31+
OS_CLOUD: "{{ admin_cloud }}"
32+
register: az_host_list_after_cleanup
33+
changed_when: false
34+
35+
- name: Print nova host AZ mapping after aggregate cleanup
36+
ansible.builtin.debug:
37+
var: az_host_list_after_cleanup.stdout_lines
38+
39+
- name: Delete AZ volume types
40+
ansible.builtin.command:
41+
cmd: openstack volume type delete {{ az_volume_type_prefix }}{{ item }}
42+
environment:
43+
OS_CLOUD: "{{ admin_cloud }}"
44+
loop: "{{ range(0, az_volume_type_count | int) | list }}"
45+
failed_when: false
46+
changed_when: true

collection/stages/roles/day2ops/defaults/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# defaults file for day2ops
33
day2ops_steps: []
44
day2ops_report_filename: shiftstack-qa-day2ops-results.xml
5+
registry_test_project: registry-test
56

67
# Application Credentials rotation
78
app_credential_name: "AppCreds-{{ user_cloud }}"
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
---
2+
- name: Get existing workers
3+
kubernetes.core.k8s_info:
4+
kubeconfig: "{{ kubeconfig }}"
5+
api_version: v1
6+
kind: Node
7+
label_selectors:
8+
- node-role.kubernetes.io/worker
9+
register: workers
10+
11+
- name: Get first worker name and its Cinder zone label
12+
ansible.builtin.set_fact:
13+
worker_name: "{{ workers.resources[0].metadata.labels['kubernetes.io/hostname'] }}"
14+
nova_az_for_registry: "{{ workers.resources[0].metadata.labels['topology.cinder.csi.openstack.org/zone'] }}"
15+
16+
- name: Discover Cinder AZ for the worker root volume
17+
block:
18+
- name: Query worker root volume AZ
19+
ansible.builtin.shell: |
20+
set -o pipefail
21+
openstack volume show \
22+
"$(openstack volume list -c ID -c Name -f value | grep "{{ worker_name }}" | cut -d' ' -f2)" \
23+
-c availability_zone -f value
24+
environment:
25+
OS_CLOUD: "{{ user_cloud }}"
26+
register: registry_worker_volume_az
27+
failed_when: false
28+
changed_when: false
29+
30+
- name: Set Cinder AZ for registry PVC
31+
ansible.builtin.set_fact:
32+
cinder_az_for_registry: "{{ (registry_worker_volume_az.stdout | trim == '') | ternary('nova', registry_worker_volume_az.stdout | trim) }}"
33+
34+
- name: Remove existing topology-aware storage class
35+
kubernetes.core.k8s:
36+
kubeconfig: "{{ kubeconfig }}"
37+
state: absent
38+
api_version: storage.k8s.io/v1
39+
kind: StorageClass
40+
name: topology-aware-image-registry
41+
42+
- name: Create a storage class for integrated registry
43+
kubernetes.core.k8s:
44+
kubeconfig: "{{ kubeconfig }}"
45+
state: present
46+
definition:
47+
apiVersion: storage.k8s.io/v1
48+
kind: StorageClass
49+
metadata:
50+
name: topology-aware-image-registry
51+
provisioner: cinder.csi.openstack.org
52+
parameters:
53+
availability: "{{ cinder_az_for_registry }}"
54+
volumeBindingMode: WaitForFirstConsumer
55+
56+
- name: Create PVC for integrated registry
57+
kubernetes.core.k8s:
58+
kubeconfig: "{{ kubeconfig }}"
59+
state: present
60+
definition:
61+
apiVersion: v1
62+
kind: PersistentVolumeClaim
63+
metadata:
64+
name: pvc-registry
65+
namespace: openshift-image-registry
66+
annotations:
67+
imageregistry.openshift.io: "true"
68+
spec:
69+
accessModes:
70+
- ReadWriteOnce
71+
resources:
72+
requests:
73+
storage: 1Gi
74+
storageClassName: topology-aware-image-registry
75+
76+
- name: Trigger registry reconfiguration
77+
kubernetes.core.k8s:
78+
kubeconfig: "{{ kubeconfig }}"
79+
definition:
80+
apiVersion: imageregistry.operator.openshift.io/v1
81+
kind: Config
82+
metadata:
83+
name: cluster
84+
spec:
85+
defaultRoute: true
86+
disableRedirect: false
87+
rolloutStrategy: Recreate
88+
replicas: 1
89+
storage:
90+
managementState: Managed
91+
pvc:
92+
claim: pvc-registry
93+
swift: null
94+
status: null
95+
state: present
96+
97+
- name: Wait for registry pod on Running phase
98+
kubernetes.core.k8s_info:
99+
kubeconfig: "{{ kubeconfig }}"
100+
kind: Pod
101+
namespace: openshift-image-registry
102+
label_selectors:
103+
- docker-registry=default
104+
register: registry_pod
105+
retries: 60
106+
delay: 10
107+
until:
108+
- registry_pod.resources | length > 0
109+
- registry_pod.resources[0].spec.volumes[0].persistentVolumeClaim is defined
110+
- registry_pod.resources[0].spec.volumes[0].persistentVolumeClaim.claimName == "pvc-registry"
111+
- registry_pod.resources[0].status is defined
112+
- registry_pod.resources[0].status.phase == "Running"
113+
114+
- name: Get integrated registry route
115+
kubernetes.core.k8s_info:
116+
kubeconfig: "{{ kubeconfig }}"
117+
api_version: route.openshift.io/v1
118+
kind: Route
119+
namespace: openshift-image-registry
120+
name: default-route
121+
register: registry_routes
122+
123+
- name: Set integrated registry URL
124+
ansible.builtin.set_fact:
125+
registry_url: "{{ registry_routes.resources[0].spec.host }}"
126+
127+
- name: Add registry domain resolution to /etc/hosts
128+
block:
129+
- name: Resolve apps ingress IP from /etc/hosts
130+
ansible.builtin.shell: |
131+
set -o pipefail
132+
grep "apps.{{ ocp_cluster_name }}" /etc/hosts | awk '{print $1}' | head -n 1
133+
register: hosts_apps_ip
134+
changed_when: false
135+
136+
- name: Set apps ingress IP
137+
ansible.builtin.set_fact:
138+
apps_fip_ip: "{{ hosts_apps_ip.stdout }}"
139+
140+
- name: Add registry floating IP to /etc/hosts
141+
ansible.builtin.lineinfile:
142+
path: /etc/hosts
143+
line: "{{ apps_fip_ip }} {{ registry_url }}"
144+
become: true
145+
146+
- name: Delete the registry test project if it exists
147+
kubernetes.core.k8s:
148+
kubeconfig: "{{ kubeconfig }}"
149+
state: absent
150+
api_version: project.openshift.io/v1
151+
kind: Project
152+
name: "{{ registry_test_project }}"
153+
wait: true
154+
wait_timeout: 60
155+
156+
- name: Create the registry test project
157+
kubernetes.core.k8s:
158+
kubeconfig: "{{ kubeconfig }}"
159+
state: present
160+
api_version: project.openshift.io/v1
161+
kind: Project
162+
name: "{{ registry_test_project }}"
163+
164+
- name: Add registry permissions to admin user
165+
ansible.builtin.shell: |
166+
set -o pipefail
167+
oc project {{ registry_test_project }}
168+
oc policy add-role-to-user registry-viewer admin
169+
oc policy add-role-to-user registry-editor admin
170+
environment:
171+
KUBECONFIG: "{{ kubeconfig }}"
172+
changed_when: true
173+
174+
- name: Get builder service account token for OCP before 4.11
175+
when: openshift_release_build_name is version('4.11', '<')
176+
block:
177+
- name: Get builder token
178+
ansible.builtin.command: oc serviceaccounts get-token builder
179+
environment:
180+
KUBECONFIG: "{{ kubeconfig }}"
181+
register: registry_token_result
182+
retries: 5
183+
delay: 60
184+
until: registry_token_result is succeeded
185+
changed_when: false
186+
187+
- name: Set registry token
188+
ansible.builtin.set_fact:
189+
registry_token: "{{ registry_token_result.stdout }}"
190+
191+
- name: Get builder service account token for OCP 4.11 and later
192+
when: openshift_release_build_name is version('4.11', '>=')
193+
block:
194+
- name: Create builder token
195+
ansible.builtin.command: oc create token builder
196+
environment:
197+
KUBECONFIG: "{{ kubeconfig }}"
198+
register: registry_token_result
199+
retries: 5
200+
delay: 60
201+
until: registry_token_result is succeeded
202+
changed_when: false
203+
204+
- name: Set registry token
205+
ansible.builtin.set_fact:
206+
registry_token: "{{ registry_token_result.stdout }}"
207+
208+
- name: Push demo image to integrated registry
209+
ansible.builtin.shell: |
210+
set -o pipefail
211+
sudo podman login -u admin -p {{ registry_token }} --tls-verify=false {{ registry_url }} && \
212+
sudo podman pull quay.io/kuryr/demo && \
213+
sudo podman tag quay.io/kuryr/demo {{ registry_url }}/{{ registry_test_project }}/demo && \
214+
sudo podman push {{ registry_url }}/{{ registry_test_project }}/demo --tls-verify=false
215+
register: registry_push_result
216+
retries: 10
217+
delay: 30
218+
until: not registry_push_result.failed
219+
changed_when: true
220+
221+
- name: Create a pod using integrated registry
222+
kubernetes.core.k8s:
223+
kubeconfig: "{{ kubeconfig }}"
224+
state: present
225+
definition:
226+
apiVersion: apps/v1
227+
kind: Deployment
228+
metadata:
229+
name: demo
230+
namespace: "{{ registry_test_project }}"
231+
spec:
232+
replicas: 1
233+
selector:
234+
matchLabels:
235+
app: demo
236+
template:
237+
metadata:
238+
labels:
239+
app: demo
240+
spec:
241+
containers:
242+
- name: demo
243+
image: image-registry.openshift-image-registry.svc:5000/{{ registry_test_project }}/demo
244+
ports:
245+
- containerPort: 80
246+
247+
- name: Wait for demo pod to reach Running phase
248+
kubernetes.core.k8s_info:
249+
kubeconfig: "{{ kubeconfig }}"
250+
kind: Pod
251+
label_selectors:
252+
- app=demo
253+
register: demo_pod
254+
retries: 5
255+
delay: 10
256+
until:
257+
- demo_pod.resources | length > 0
258+
- demo_pod.resources[0].status is defined
259+
- demo_pod.resources[0].status.phase == "Running"

0 commit comments

Comments
 (0)