Skip to content

Commit c14ee2f

Browse files
committed
[ci_local_storage] Fall back to oc debug for PV dir creation
When no Ansible inventory host matches a k8s node hostname (e.g. bare metal SNO where the node is not SSH-accessible), the role silently skips directory creation while still creating PVs that reference non-existent paths. Add an oc debug fallback that creates directories on each node via a debug pod. Generated-by: claude-4.6-opus-high Signed-off-by: Bohdan Dobrelia <bdobreli@redhat.com>
1 parent 620b121 commit c14ee2f

7 files changed

Lines changed: 137 additions & 0 deletions

File tree

docs/dictionary/en-custom.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Marjanovic
1919
Nemanja
2020
NICs
2121
NodeHealthCheck
22+
PV
2223
PyYAML
2324
RHCOS
2425
SNO

roles/ci_local_storage/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ If apply, please explain the privilege escalation done in this role.
1717
* `cifmw_cls_create_ee_storage`: (Bool) Param to create ee_storage. Defaults to `false`.
1818
* `cifmw_cls_namespace`: (String) The namespace where OCP resources will be installed. Defaults to `openstack`.
1919
* `cifmw_cls_action`: (String) Action to perform, can be `create` or `clean`. Defaults to `create`.
20+
* `cifmw_cls_oc_debug_fallback`: (Bool) Use `oc debug node/` to create PV directories on k8s nodes that are not reachable via SSH from the Ansible inventory. When enabled, the role computes which k8s nodes have no matching SSH-reachable inventory host and falls back to `oc debug` for those nodes. Applies to both create and cleanup. Defaults to `false`. Use it with an SNO BM setup.
2021
* `cifmw_cls_storage_manifest`: (Dict) The storage manifest resource to be used to initiate storage class.
2122

2223
## Examples
24+
25+
### Standard (CRC / VM-based)
2326
```YAML
2427
- hosts: localhost
2528
vars:
@@ -32,3 +35,18 @@ If apply, please explain the privilege escalation done in this role.
3235
- ansible.builtin.include_role:
3336
name: ci_local_storage
3437
```
38+
39+
### Baremetal SNO
40+
On bare-metal Single Node OpenShift the k8s node is typically not present
41+
in the Ansible inventory for SSH access. Enable `cifmw_cls_oc_debug_fallback`
42+
so the role uses `oc debug node/` to manage PV directories instead:
43+
```YAML
44+
- hosts: localhost
45+
vars:
46+
cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.kube/kubeconfig"
47+
cifmw_cls_pv_count: 20
48+
cifmw_cls_oc_debug_fallback: true
49+
tasks:
50+
- ansible.builtin.include_role:
51+
name: ci_local_storage
52+
```

roles/ci_local_storage/defaults/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ cifmw_cls_storage_provisioner: cifmw
2828
cifmw_cls_create_ee_storage: false
2929
cifmw_cls_namespace: openstack
3030
cifmw_cls_action: create
31+
cifmw_cls_oc_debug_fallback: false
3132

3233
cifmw_cls_storage_manifest:
3334
kind: StorageClass

roles/ci_local_storage/molecule/default/converge.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,65 @@
137137
}}
138138
ansible.builtin.assert:
139139
that: "cifmw_cls_namespace not in ns_names"
140+
141+
- name: Test oc-debug fallback path (uncovered_node_dirs.yml)
142+
vars:
143+
cifmw_cls_pv_count: 3
144+
cifmw_cls_local_storage_name: /mnt/openstack-fallback
145+
cifmw_cls_oc_debug_fallback: true
146+
block:
147+
- name: Get k8s node names for fallback test
148+
kubernetes.core.k8s_info:
149+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
150+
kind: Node
151+
register: _fb_k8s_nodes
152+
153+
- name: Simulate no SSH-reachable hosts matching k8s nodes
154+
ansible.builtin.set_fact:
155+
cifmw_ci_local_storage_k8s_hostnames:
156+
- "{{ _fb_k8s_nodes.resources[0].metadata.name }}"
157+
_hostnames:
158+
results: []
159+
160+
- name: Run uncovered_node_dirs.yml (create)
161+
vars:
162+
cifmw_cls_action: create
163+
ansible.builtin.include_tasks:
164+
file: "{{ playbook_dir }}/../../tasks/uncovered_node_dirs.yml"
165+
166+
- name: Assert uncovered nodes were identified
167+
ansible.builtin.assert:
168+
that:
169+
- _cls_uncovered_nodes | length == 1
170+
171+
- name: Verify directories created on node
172+
delegate_to: crc
173+
become: true
174+
register: _fb_check
175+
ansible.builtin.stat:
176+
path: "/mnt/openstack-fallback/pv{{ '%02d' | format(item | int) }}"
177+
loop: "{{ range(1, 4) }}"
178+
179+
- name: Assert all fallback directories exist
180+
ansible.builtin.assert:
181+
that: item.stat.exists
182+
loop: "{{ _fb_check.results }}"
183+
loop_control:
184+
label: "{{ item.invocation.module_args.path }}"
185+
186+
- name: Run uncovered_node_dirs.yml (cleanup)
187+
vars:
188+
cifmw_cls_action: clean
189+
ansible.builtin.include_tasks:
190+
file: "{{ playbook_dir }}/../../tasks/uncovered_node_dirs.yml"
191+
192+
- name: Verify fallback directories removed
193+
delegate_to: crc
194+
become: true
195+
register: _fb_removed
196+
ansible.builtin.stat:
197+
path: "/mnt/openstack-fallback"
198+
199+
- name: Assert fallback directory tree is gone
200+
ansible.builtin.assert:
201+
that: not _fb_removed.stat.exists

roles/ci_local_storage/tasks/cleanup.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@
5555
loop_control:
5656
loop_var: host
5757

58+
- name: Delete PV directories on nodes unreachable via SSH
59+
vars:
60+
cifmw_cls_action: "clean"
61+
when:
62+
- cifmw_cls_oc_debug_fallback | bool
63+
ansible.builtin.include_tasks: uncovered_node_dirs.yml
64+
5865
- name: Remove the cifmw_cls_namespace namespace
5966
kubernetes.core.k8s:
6067
state: absent

roles/ci_local_storage/tasks/main.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
loop_control:
5353
loop_var: host
5454

55+
- name: Manage PV directories on nodes unreachable via SSH
56+
when:
57+
- cifmw_cls_oc_debug_fallback | bool
58+
ansible.builtin.include_tasks: uncovered_node_dirs.yml
59+
5560
- name: Generate pv related storage manifest file
5661
ansible.builtin.template:
5762
src: storage.yaml.j2
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
- name: Identify k8s nodes not reachable via SSH (SNO BM)
3+
vars:
4+
_ssh_covered: >-
5+
{{
6+
_hostnames.results |
7+
default([]) |
8+
selectattr('stdout', 'defined') |
9+
map(attribute='stdout') |
10+
list
11+
}}
12+
ansible.builtin.set_fact:
13+
_cls_uncovered_nodes: >-
14+
{{
15+
cifmw_ci_local_storage_k8s_hostnames |
16+
difference(_ssh_covered)
17+
}}
18+
19+
- name: Manage PV directories via oc debug for unreachable nodes
20+
when:
21+
- _cls_uncovered_nodes | length > 0
22+
vars:
23+
_action_script: >-
24+
{% if cifmw_cls_action == 'create' %}
25+
for i in $(seq 1 {{ cifmw_cls_pv_count | int }});
26+
do d=$(printf '%02d' "$i");
27+
mkdir -p '{{ cifmw_cls_local_storage_name }}'/pv$d &&
28+
chmod 0775 '{{ cifmw_cls_local_storage_name }}'/pv$d; done
29+
{% else %}
30+
rm -rf '{{ cifmw_cls_local_storage_name }}'
31+
{% endif %}
32+
ansible.builtin.command:
33+
cmd: >-
34+
oc debug node/{{ node_name }}
35+
--kubeconfig={{ cifmw_openshift_kubeconfig }}
36+
-- chroot /host bash -c "{{ _action_script }}"
37+
register: _cls_oc_debug
38+
retries: 3
39+
delay: 10
40+
until: _cls_oc_debug.rc == 0
41+
loop: "{{ _cls_uncovered_nodes }}"
42+
loop_control:
43+
loop_var: node_name

0 commit comments

Comments
 (0)