Skip to content

Commit 0f23480

Browse files
abaysclaude
authored andcommitted
[openshift_adp] Add OADP operator installation role
Install and configure the OADP (OpenShift API for Data Protection) operator with an S3-compatible storage backend, create the DataProtectionApplication CR, set up VolumeSnapshotClass for CSI snapshots, and verify the BackupStorageLocation is available. Signed-off-by: Andrew Bays <abays@redhat.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e0de247 commit 0f23480

6 files changed

Lines changed: 370 additions & 0 deletions

File tree

docs/dictionary/en-custom.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ num
424424
nvme
425425
nwy
426426
nzgdh
427+
OADP
427428
oauth
428429
observability
429430
oc
@@ -641,6 +642,7 @@ vcpus
641642
vda
642643
venv
643644
vexxhost
645+
Velero
644646
virbr
645647
virsh
646648
virt
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
# All variables intended for modification should be placed in this file.
18+
# All variables within this role should have a prefix of "cifmw_openshift_adp"
19+
20+
# OADP operator
21+
cifmw_openshift_adp_namespace: openshift-adp
22+
cifmw_openshift_adp_channel: stable
23+
cifmw_openshift_adp_enable_node_agent: true
24+
25+
# S3 backend (MinIO or other S3-compatible)
26+
cifmw_openshift_adp_s3_namespace: minio
27+
cifmw_openshift_adp_s3_bucket: velero
28+
cifmw_openshift_adp_s3_region: minio
29+
cifmw_openshift_adp_s3_prefix: rhoso
30+
cifmw_openshift_adp_s3_force_path_style: true
31+
cifmw_openshift_adp_s3_insecure_skip_tls: true
32+
# cifmw_openshift_adp_s3_access_key: REQUIRED
33+
# cifmw_openshift_adp_s3_secret_key: REQUIRED

roles/openshift_adp/meta/main.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
galaxy_info:
3+
role_name: openshift_adp
4+
namespace: cifmw
5+
author: Red Hat
6+
description: Install and configure OADP (OpenShift API for Data Protection)
7+
license: Apache-2.0
8+
min_ansible_version: "2.11"

roles/openshift_adp/tasks/main.yml

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
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+
# OADP Setup
18+
#
19+
# Installs and configures OADP (OpenShift API for Data Protection)
20+
# with an S3-compatible storage backend.
21+
22+
- name: Verify S3 credentials are provided
23+
ansible.builtin.fail:
24+
msg: >-
25+
cifmw_openshift_adp_s3_access_key and cifmw_openshift_adp_s3_secret_key
26+
are required. Deploy an S3 backend first (e.g. deploy_minio role).
27+
when: >-
28+
cifmw_openshift_adp_s3_access_key is not defined or
29+
cifmw_openshift_adp_s3_secret_key is not defined
30+
31+
- name: Print setup header
32+
ansible.builtin.debug:
33+
msg:
34+
- "========================================"
35+
- "OADP Setup"
36+
- "========================================"
37+
- "OADP Namespace: {{ cifmw_openshift_adp_namespace }}"
38+
- "OADP Channel: {{ cifmw_openshift_adp_channel }}"
39+
- "S3 Namespace: {{ cifmw_openshift_adp_s3_namespace }}"
40+
- "S3 Bucket: {{ cifmw_openshift_adp_s3_bucket }}"
41+
- "Node Agent (Kopia): {{ cifmw_openshift_adp_enable_node_agent }}"
42+
43+
- name: Create OADP namespace
44+
kubernetes.core.k8s:
45+
api_version: v1
46+
kind: Namespace
47+
name: "{{ cifmw_openshift_adp_namespace }}"
48+
state: present
49+
50+
- name: Create OperatorGroup for OADP
51+
kubernetes.core.k8s:
52+
state: present
53+
definition:
54+
apiVersion: operators.coreos.com/v1
55+
kind: OperatorGroup
56+
metadata:
57+
name: openshift-adp-operator-group
58+
namespace: "{{ cifmw_openshift_adp_namespace }}"
59+
spec:
60+
targetNamespaces:
61+
- "{{ cifmw_openshift_adp_namespace }}"
62+
63+
- name: Create Subscription for OADP operator
64+
kubernetes.core.k8s:
65+
state: present
66+
definition:
67+
apiVersion: operators.coreos.com/v1alpha1
68+
kind: Subscription
69+
metadata:
70+
name: redhat-oadp-operator
71+
namespace: "{{ cifmw_openshift_adp_namespace }}"
72+
spec:
73+
channel: "{{ cifmw_openshift_adp_channel }}"
74+
installPlanApproval: Automatic
75+
name: redhat-oadp-operator
76+
source: redhat-operators
77+
sourceNamespace: openshift-marketplace
78+
79+
- name: Wait for OADP operator to be ready
80+
kubernetes.core.k8s_info:
81+
api_version: v1
82+
kind: Pod
83+
namespace: "{{ cifmw_openshift_adp_namespace }}"
84+
label_selectors:
85+
- control-plane=controller-manager
86+
wait: true
87+
wait_timeout: 300
88+
wait_condition:
89+
type: Ready
90+
status: "True"
91+
register: _operator_wait
92+
retries: 30
93+
delay: 10
94+
until: _operator_wait.resources | length > 0
95+
96+
- name: Create cloud credentials secret
97+
kubernetes.core.k8s:
98+
state: present
99+
definition:
100+
apiVersion: v1
101+
kind: Secret
102+
metadata:
103+
name: cloud-credentials
104+
namespace: "{{ cifmw_openshift_adp_namespace }}"
105+
type: Opaque
106+
stringData:
107+
cloud: |
108+
[default]
109+
aws_access_key_id={{ cifmw_openshift_adp_s3_access_key }}
110+
aws_secret_access_key={{ cifmw_openshift_adp_s3_secret_key }}
111+
no_log: true
112+
113+
- name: Get S3 API route
114+
kubernetes.core.k8s_info:
115+
api_version: route.openshift.io/v1
116+
kind: Route
117+
name: minio-api
118+
namespace: "{{ cifmw_openshift_adp_s3_namespace }}"
119+
register: _s3_api_route
120+
121+
- name: Create DataProtectionApplication
122+
kubernetes.core.k8s:
123+
state: present
124+
definition:
125+
apiVersion: oadp.openshift.io/v1alpha1
126+
kind: DataProtectionApplication
127+
metadata:
128+
name: velero
129+
namespace: "{{ cifmw_openshift_adp_namespace }}"
130+
spec:
131+
configuration:
132+
velero:
133+
defaultPlugins:
134+
- openshift
135+
- aws
136+
- csi
137+
nodeAgent:
138+
enable: "{{ cifmw_openshift_adp_enable_node_agent | bool }}"
139+
uploaderType: kopia
140+
backupLocations:
141+
- velero:
142+
provider: aws
143+
default: true
144+
objectStorage:
145+
bucket: "{{ cifmw_openshift_adp_s3_bucket }}"
146+
prefix: "{{ cifmw_openshift_adp_s3_prefix }}"
147+
config:
148+
region: "{{ cifmw_openshift_adp_s3_region }}"
149+
s3ForcePathStyle: "{{ cifmw_openshift_adp_s3_force_path_style | lower }}"
150+
s3Url: "https://{{ _s3_api_route.resources[0].spec.host }}"
151+
insecureSkipTLSVerify: "{{ cifmw_openshift_adp_s3_insecure_skip_tls | lower }}"
152+
credential:
153+
name: cloud-credentials
154+
key: cloud
155+
156+
- name: Wait for Velero pod to be ready
157+
kubernetes.core.k8s_info:
158+
api_version: v1
159+
kind: Pod
160+
namespace: "{{ cifmw_openshift_adp_namespace }}"
161+
label_selectors:
162+
- app.kubernetes.io/name=velero
163+
wait: true
164+
wait_timeout: 300
165+
wait_condition:
166+
type: Ready
167+
status: "True"
168+
register: _velero_wait
169+
retries: 30
170+
delay: 10
171+
until: _velero_wait.resources | length > 0
172+
173+
- name: Wait for node-agent pods to be ready
174+
kubernetes.core.k8s_info:
175+
api_version: v1
176+
kind: Pod
177+
namespace: "{{ cifmw_openshift_adp_namespace }}"
178+
label_selectors:
179+
- app.kubernetes.io/name=node-agent
180+
wait: true
181+
wait_timeout: 300
182+
wait_condition:
183+
type: Ready
184+
status: "True"
185+
when: cifmw_openshift_adp_enable_node_agent | bool
186+
187+
- name: Get OADP pods
188+
kubernetes.core.k8s_info:
189+
api_version: v1
190+
kind: Pod
191+
namespace: "{{ cifmw_openshift_adp_namespace }}"
192+
register: _oadp_pods
193+
194+
- name: Display OADP pods
195+
ansible.builtin.debug:
196+
msg: "{{ item.metadata.name }} - {{ item.status.phase }}"
197+
loop: "{{ _oadp_pods.resources }}"
198+
loop_control:
199+
label: "{{ item.metadata.name }}"
200+
201+
# ========================================
202+
# VolumeSnapshotClass for CSI snapshots
203+
# ========================================
204+
- name: Check for existing VolumeSnapshotClass
205+
kubernetes.core.k8s_info:
206+
api_version: snapshot.storage.k8s.io/v1
207+
kind: VolumeSnapshotClass
208+
register: _vsc_list
209+
210+
- name: Create VolumeSnapshotClass for OADP (TopoLVM/LVMS)
211+
kubernetes.core.k8s:
212+
state: present
213+
definition:
214+
apiVersion: snapshot.storage.k8s.io/v1
215+
kind: VolumeSnapshotClass
216+
metadata:
217+
name: lvms-velero
218+
labels:
219+
velero.io/csi-volumesnapshot-class: "true"
220+
annotations:
221+
snapshot.storage.kubernetes.io/is-default-class: "false"
222+
driver: topolvm.io
223+
deletionPolicy: Retain
224+
when: >-
225+
_vsc_list.resources |
226+
selectattr('driver', 'equalto', 'topolvm.io') |
227+
list | length > 0
228+
229+
- name: Print VolumeSnapshotClass status (TopoLVM found)
230+
ansible.builtin.debug:
231+
msg: "VolumeSnapshotClass 'lvms-velero' created for OADP CSI snapshots"
232+
when: >-
233+
_vsc_list.resources |
234+
selectattr('driver', 'equalto', 'topolvm.io') |
235+
list | length > 0
236+
237+
- name: Print VolumeSnapshotClass status (no TopoLVM)
238+
ansible.builtin.debug:
239+
msg: "No TopoLVM driver found. If using a different CSI driver, manually create a VolumeSnapshotClass with velero.io/csi-volumesnapshot-class=true label."
240+
when: >-
241+
_vsc_list.resources |
242+
selectattr('driver', 'equalto', 'topolvm.io') |
243+
list | length == 0
244+
245+
# ========================================
246+
# Verify BackupStorageLocation
247+
# ========================================
248+
- name: Wait for BackupStorageLocation to be available
249+
kubernetes.core.k8s_info:
250+
api_version: velero.io/v1
251+
kind: BackupStorageLocation
252+
namespace: "{{ cifmw_openshift_adp_namespace }}"
253+
register: _bsl_status
254+
retries: 30
255+
delay: 10
256+
until:
257+
- _bsl_status.resources | length > 0
258+
- (_bsl_status.resources[0].status.phase | default('')) == 'Available'
259+
ignore_errors: true
260+
261+
- name: Get BackupStorageLocation details
262+
kubernetes.core.k8s_info:
263+
api_version: velero.io/v1
264+
kind: BackupStorageLocation
265+
namespace: "{{ cifmw_openshift_adp_namespace }}"
266+
register: _bsl_output
267+
268+
- name: Display BackupStorageLocation status
269+
ansible.builtin.debug:
270+
msg: >-
271+
{{ item.metadata.name }} - Phase: {{ item.status.phase | default('Unknown') }}
272+
loop: "{{ _bsl_output.resources }}"
273+
loop_control:
274+
label: "{{ item.metadata.name }}"
275+
276+
- name: Get troubleshooting info if BSL not available
277+
ansible.builtin.shell: |
278+
echo "=== BackupStorageLocation ==="
279+
oc get backupstoragelocation -n {{ cifmw_openshift_adp_namespace }} -o yaml
280+
echo ""
281+
echo "=== Velero Logs (last 50 lines) ==="
282+
oc logs -n {{ cifmw_openshift_adp_namespace }} deployment/velero --tail=50
283+
register: _bsl_debug
284+
changed_when: false
285+
when: _bsl_status is failed
286+
287+
- name: Display troubleshooting info
288+
ansible.builtin.debug:
289+
msg: "{{ _bsl_debug.stdout_lines }}"
290+
when: _bsl_status is failed
291+
292+
- name: Print success summary
293+
ansible.builtin.debug:
294+
msg:
295+
- "========================================"
296+
- "OADP Setup Complete"
297+
- "========================================"
298+
- ""
299+
- "OADP Namespace: {{ cifmw_openshift_adp_namespace }}"
300+
- "S3 API: https://{{ _s3_api_route.resources[0].spec.host }}"
301+
- "Bucket: {{ cifmw_openshift_adp_s3_bucket }}"
302+
- "BackupStorageLocation: Available"
303+
when: _bsl_status is not failed
304+
305+
- name: Print warning summary
306+
ansible.builtin.debug:
307+
msg:
308+
- "========================================"
309+
- "OADP Setup Complete with Warnings"
310+
- "========================================"
311+
- ""
312+
- "BackupStorageLocation is not yet available."
313+
- ""
314+
- "Troubleshoot:"
315+
- " oc get backupstoragelocation -n {{ cifmw_openshift_adp_namespace }} -o yaml"
316+
- " oc logs -n {{ cifmw_openshift_adp_namespace }} deployment/velero"
317+
when: _bsl_status is failed

zuul.d/molecule.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,15 @@
10281028
- ^.config/molecule/.*
10291029
name: cifmw-molecule-openshift_adm
10301030
parent: cifmw-molecule-noop
1031+
- job:
1032+
files:
1033+
- ^common-requirements.txt
1034+
- ^test-requirements.txt
1035+
- ^roles/openshift_adp/.*
1036+
- ^ci/playbooks/molecule.*
1037+
- ^.config/molecule/.*
1038+
name: cifmw-molecule-openshift_adp
1039+
parent: cifmw-molecule-noop
10311040
- job:
10321041
files:
10331042
- ^common-requirements.txt

0 commit comments

Comments
 (0)