Skip to content

Commit 190b49e

Browse files
committed
[ci-framework-jobs] add cleanup-openstack-for-reuse playbook
Add a wrapper playbook that calls the ci-framework cleanup-openstack-for-reuse playbook to enable infrastructure reuse in ci-framework-jobs workflows. This playbook provides a convenient way to clean up OpenStack resources (CRs, storage, API resources) while preserving the OpenShift cluster infrastructure for reuse in subsequent deployments. By default, it performs aggressive cleanup including namespace deletion and force removal of finalizers to ensure a clean state. The playbook follows the same pattern as clean-env.yaml, executing the ci-framework cleanup playbook with configurable options that can be overridden via extra variables. Related: OSPRH-21759 Signed-off-by: Roberto Alfieri <[email protected]>
1 parent 1638776 commit 190b49e

File tree

5 files changed

+697
-0
lines changed

5 files changed

+697
-0
lines changed

cleanup-openstack-for-reuse.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
# Copyright Red Hat, Inc.
3+
# All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
# This playbook cleans up OpenStack resources while preserving the OpenShift
18+
# cluster infrastructure for reuse. It removes:
19+
# - All OpenStack CRs (ControlPlane, DataPlane, etc.)
20+
# - Storage resources (PVCs, secrets, ConfigMaps)
21+
# - Optionally: OpenStack API resources (servers, networks, volumes, etc.)
22+
#
23+
# Usage examples:
24+
#
25+
# Basic cleanup (removes OpenStack CRs and storage, keeps cluster):
26+
# ansible-playbook -i inventory.yml cleanup-openstack-for-reuse.yml
27+
#
28+
# Skip API resource cleanup (if needed):
29+
# ansible-playbook -i inventory.yml cleanup-openstack-for-reuse.yml \
30+
# -e cleanup_api_resources=false
31+
#
32+
# Aggressive cleanup (removes everything including namespaces):
33+
# ansible-playbook -i inventory.yml cleanup-openstack-for-reuse.yml \
34+
# -e cleanup_api_resources=true \
35+
# -e cleanup_namespaces=true \
36+
# -e force_remove_finalizers=true
37+
38+
- name: Clean OpenStack deployment for infrastructure reuse
39+
hosts: "{{ target_host | default('localhost') }}"
40+
gather_facts: true
41+
vars:
42+
# By default, clean OpenStack CRs, storage, and API resources but keep OpenShift cluster
43+
# Set to false to skip OpenStack API resource cleanup
44+
cifmw_cleanup_openstack_delete_api_resources: "{{ cleanup_api_resources | default(true) }}"
45+
# Set to true to delete namespaces (use with caution)
46+
cifmw_cleanup_openstack_delete_namespaces: "{{ cleanup_namespaces | default(false) }}"
47+
# Set to true to force remove finalizers from stuck CRs
48+
cifmw_cleanup_openstack_force_remove_finalizers: "{{ force_remove_finalizers | default(false) }}"
49+
tasks:
50+
- name: Cleanup OpenStack deployment
51+
ansible.builtin.include_role:
52+
name: cleanup_openstack
53+
54+
- name: Display cleanup summary
55+
ansible.builtin.debug:
56+
msg: >-
57+
OpenStack cleanup completed. The OpenShift cluster is now ready for reuse.
58+
59+
Cleaned resources:
60+
- OpenStack CRs (ControlPlane, DataPlane, etc.)
61+
- Storage resources (PVCs, secrets, ConfigMaps)
62+
- OpenStack API resources (servers, networks, volumes, etc.)
63+
- Artifacts and logs
64+
{% if cifmw_cleanup_openstack_delete_namespaces %}
65+
- OpenStack namespaces (if empty)
66+
{% endif %}
67+
68+
The cluster infrastructure is preserved and ready for a new deployment.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
---
2+
# Copyright Red Hat, Inc.
3+
# All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
- name: Get OpenStack namespace
18+
ansible.builtin.set_fact:
19+
_openstack_namespace: "{{ cifmw_kustomize_deploy_namespace | default('openstack') }}"
20+
21+
- name: Delete OpenStackControlPlane CRs
22+
kubernetes.core.k8s:
23+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
24+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
25+
context: "{{ cifmw_openshift_context | default(omit) }}"
26+
api_version: core.openstack.org/v1beta1
27+
kind: OpenStackControlPlane
28+
namespace: "{{ _openstack_namespace }}"
29+
state: absent
30+
wait: true
31+
wait_timeout: 600
32+
ignore_errors: true
33+
register: _delete_controlplane_result
34+
until: _delete_controlplane_result is succeeded or (_delete_controlplane_result.failed and 'not found' in (_delete_controlplane_result.msg | default('')))
35+
retries: 3
36+
delay: 30
37+
38+
- name: Wait for control plane pods to terminate
39+
kubernetes.core.k8s_info:
40+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
41+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
42+
context: "{{ cifmw_openshift_context | default(omit) }}"
43+
namespace: "{{ _openstack_namespace }}"
44+
kind: Pod
45+
register: _remaining_pods
46+
until: _remaining_pods.resources | length == 0 or (_remaining_pods.resources | selectattr('metadata.name', 'match', '.*(rabbitmq|galera|openstack).*') | list | length == 0)
47+
retries: 60
48+
delay: 10
49+
when: _delete_controlplane_result is succeeded
50+
51+
- name: Delete OpenStackDataPlaneDeployment CRs
52+
kubernetes.core.k8s:
53+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
54+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
55+
context: "{{ cifmw_openshift_context | default(omit) }}"
56+
api_version: dataplane.openstack.org/v1beta1
57+
kind: OpenStackDataPlaneDeployment
58+
namespace: "{{ _openstack_namespace }}"
59+
state: absent
60+
wait: true
61+
wait_timeout: 600
62+
ignore_errors: true
63+
64+
- name: Delete OpenStackDataPlaneNodeSet CRs
65+
kubernetes.core.k8s:
66+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
67+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
68+
context: "{{ cifmw_openshift_context | default(omit) }}"
69+
api_version: dataplane.openstack.org/v1beta1
70+
kind: OpenStackDataPlaneNodeSet
71+
namespace: "{{ _openstack_namespace }}"
72+
state: absent
73+
wait: true
74+
wait_timeout: 600
75+
ignore_errors: true
76+
77+
- name: Delete OpenStackDataPlaneService CRs
78+
kubernetes.core.k8s:
79+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
80+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
81+
context: "{{ cifmw_openshift_context | default(omit) }}"
82+
api_version: dataplane.openstack.org/v1beta1
83+
kind: OpenStackDataPlaneService
84+
namespace: "{{ _openstack_namespace }}"
85+
state: absent
86+
wait: true
87+
wait_timeout: 300
88+
ignore_errors: true
89+
90+
- name: Delete OpenStackDataPlaneNode CRs
91+
kubernetes.core.k8s:
92+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
93+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
94+
context: "{{ cifmw_openshift_context | default(omit) }}"
95+
api_version: dataplane.openstack.org/v1beta1
96+
kind: OpenStackDataPlaneNode
97+
namespace: "{{ _openstack_namespace }}"
98+
state: absent
99+
wait: true
100+
wait_timeout: 300
101+
ignore_errors: true
102+
103+
- name: Delete OpenStackClient CRs
104+
kubernetes.core.k8s:
105+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
106+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
107+
context: "{{ cifmw_openshift_context | default(omit) }}"
108+
api_version: client.openstack.org/v1beta1
109+
kind: OpenStackClient
110+
namespace: "{{ _openstack_namespace }}"
111+
state: absent
112+
wait: true
113+
wait_timeout: 300
114+
ignore_errors: true
115+
116+
- name: Delete OpenStackVersion CRs
117+
kubernetes.core.k8s:
118+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
119+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
120+
context: "{{ cifmw_openshift_context | default(omit) }}"
121+
api_version: core.openstack.org/v1beta1
122+
kind: OpenStackVersion
123+
namespace: "{{ _openstack_namespace }}"
124+
state: absent
125+
wait: true
126+
wait_timeout: 300
127+
ignore_errors: true
128+
129+
- name: Delete OpenStack CR (legacy)
130+
kubernetes.core.k8s:
131+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
132+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
133+
context: "{{ cifmw_openshift_context | default(omit) }}"
134+
api_version: openstack.org/v1beta1
135+
kind: OpenStack
136+
namespace: "{{ _openstack_namespace }}"
137+
state: absent
138+
wait: true
139+
wait_timeout: 300
140+
ignore_errors: true
141+
142+
- name: Remove finalizers from stuck OpenStackControlPlane CRs
143+
kubernetes.core.k8s:
144+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
145+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
146+
context: "{{ cifmw_openshift_context | default(omit) }}"
147+
api_version: core.openstack.org/v1beta1
148+
kind: OpenStackControlPlane
149+
namespace: "{{ _openstack_namespace }}"
150+
state: patched
151+
definition:
152+
metadata:
153+
finalizers: []
154+
ignore_errors: true
155+
when: cifmw_cleanup_openstack_force_remove_finalizers | default(false)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
---
2+
# Copyright Red Hat, Inc.
3+
# All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
# License for the specific language governing permissions and limitations
15+
# under the License.
16+
17+
- name: Get OpenStack namespace
18+
ansible.builtin.set_fact:
19+
_openstack_namespace: "{{ cifmw_kustomize_deploy_namespace | default('openstack') }}"
20+
_openstack_operators_namespace: "{{ cifmw_kustomize_deploy_operators_namespace | default('openstack-operators') }}"
21+
22+
- name: Get all resources in OpenStack namespace
23+
kubernetes.core.k8s_info:
24+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
25+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
26+
context: "{{ cifmw_openshift_context | default(omit) }}"
27+
namespace: "{{ _openstack_namespace }}"
28+
register: _openstack_namespace_resources
29+
ignore_errors: true
30+
31+
- name: Check if OpenStack namespace is empty
32+
ansible.builtin.set_fact:
33+
_openstack_namespace_empty: >-
34+
{{
35+
(_openstack_namespace_resources.resources | default([]) |
36+
rejectattr('kind', 'in', ['Namespace', 'ServiceAccount']) |
37+
list | length) == 0
38+
}}
39+
40+
- name: Delete OpenStack namespace if empty
41+
kubernetes.core.k8s:
42+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
43+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
44+
context: "{{ cifmw_openshift_context | default(omit) }}"
45+
kind: Namespace
46+
name: "{{ _openstack_namespace }}"
47+
state: absent
48+
wait: true
49+
wait_timeout: 300
50+
when:
51+
- _openstack_namespace_empty
52+
- cifmw_cleanup_openstack_delete_namespaces
53+
ignore_errors: true
54+
55+
- name: Get all resources in OpenStack operators namespace
56+
kubernetes.core.k8s_info:
57+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
58+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
59+
context: "{{ cifmw_openshift_context | default(omit) }}"
60+
namespace: "{{ _openstack_operators_namespace }}"
61+
register: _operators_namespace_resources
62+
ignore_errors: true
63+
64+
- name: Check if OpenStack operators namespace is empty
65+
ansible.builtin.set_fact:
66+
_operators_namespace_empty: >-
67+
{{
68+
(_operators_namespace_resources.resources | default([]) |
69+
rejectattr('kind', 'in', ['Namespace', 'ServiceAccount']) |
70+
list | length) == 0
71+
}}
72+
73+
- name: Delete OpenStack operators namespace if empty
74+
kubernetes.core.k8s:
75+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
76+
api_key: "{{ cifmw_openshift_token | default(omit) }}"
77+
context: "{{ cifmw_openshift_context | default(omit) }}"
78+
kind: Namespace
79+
name: "{{ _openstack_operators_namespace }}"
80+
state: absent
81+
wait: true
82+
wait_timeout: 300
83+
when:
84+
- _operators_namespace_empty
85+
- cifmw_cleanup_openstack_delete_namespaces
86+
ignore_errors: true
87+
88+
- name: Display namespace cleanup status
89+
ansible.builtin.debug:
90+
msg: >-
91+
Namespace cleanup:
92+
- {{ _openstack_namespace }}: {{ 'deleted' if (_openstack_namespace_empty and cifmw_cleanup_openstack_delete_namespaces) else 'kept (not empty or deletion disabled)' }}
93+
- {{ _openstack_operators_namespace }}: {{ 'deleted' if (_operators_namespace_empty and cifmw_cleanup_openstack_delete_namespaces) else 'kept (not empty or deletion disabled)' }}

0 commit comments

Comments
 (0)