From ec7ff790f29e83301466b3435b1a5735e63a043e Mon Sep 17 00:00:00 2001 From: sfulmer Date: Wed, 15 Apr 2026 10:55:18 -0400 Subject: [PATCH 01/12] feat(vm-storage-labeling): add storage volume labeling role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move from openshift_virtualization_migration repo — this is day 2 ops functionality for labeling PVCs/DataVolumes on existing VMs. Co-Authored-By: Claude Opus 4.6 --- playbooks/vm_storage_labeling.yml | 15 ++++ roles/vm_storage_labeling/defaults/main.yml | 32 ++++++++ roles/vm_storage_labeling/meta/main.yml | 10 +++ .../tasks/_apply_metadata.yml | 75 +++++++++++++++++ .../tasks/_process_request.yml | 82 +++++++++++++++++++ roles/vm_storage_labeling/tasks/main.yml | 40 +++++++++ roles/vm_storage_labeling/tests/inventory | 1 + roles/vm_storage_labeling/tests/test.yml | 7 ++ 8 files changed, 262 insertions(+) create mode 100644 playbooks/vm_storage_labeling.yml create mode 100644 roles/vm_storage_labeling/defaults/main.yml create mode 100644 roles/vm_storage_labeling/meta/main.yml create mode 100644 roles/vm_storage_labeling/tasks/_apply_metadata.yml create mode 100644 roles/vm_storage_labeling/tasks/_process_request.yml create mode 100644 roles/vm_storage_labeling/tasks/main.yml create mode 100644 roles/vm_storage_labeling/tests/inventory create mode 100644 roles/vm_storage_labeling/tests/test.yml diff --git a/playbooks/vm_storage_labeling.yml b/playbooks/vm_storage_labeling.yml new file mode 100644 index 0000000..add6b40 --- /dev/null +++ b/playbooks/vm_storage_labeling.yml @@ -0,0 +1,15 @@ +--- + +- name: VM Storage Volume Labeling + hosts: localhost + connection: local + gather_facts: false + tasks: + - name: Invoke VM Storage Volume Labeling + ansible.builtin.include_role: + name: infra.openshift_virtualization_ops.vm_storage_labeling + vars: + openshift_host: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_HOST', default=Undefined) | default('', True) }}" + openshift_api_key: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_API_KEY', default=Undefined) | default('', True) }}" # noqa: yaml[line-length] + openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(false) | bool }}" # noqa: yaml[line-length] +... diff --git a/roles/vm_storage_labeling/defaults/main.yml b/roles/vm_storage_labeling/defaults/main.yml new file mode 100644 index 0000000..a5195cf --- /dev/null +++ b/roles/vm_storage_labeling/defaults/main.yml @@ -0,0 +1,32 @@ +--- +# defaults file for vm_storage_labeling + +# title: Storage Volume Labeling Request +# required: True +# description: List of Storage Volume Labeling Requests +vm_storage_labeling_request: [] +# - namespace: # Namespace containing storage volumes to label. +# names: # List of PVC/DataVolume names within a namespace. \ +# Optional when using label_selectors. +# label_selectors: # Label selectors to match volumes. \ +# Cannot be used with list of volume names. +# - = +# labels: # Labels to apply to matched volumes. +# : +# annotations: # Annotations to apply to matched volumes. +# : + +# title: OpenShift Host +# required: True +# description: OpenShift Host +vm_storage_labeling_openshift_host: "{{ openshift_host }}" +# title: OpenShift API Key +# required: True +# description: OpenShift API Key +vm_storage_labeling_api_key: "{{ openshift_api_key }}" +# title: Verify SSL Certificate +# required: True +# description: Verify SSL Certificate +vm_storage_labeling_openshift_verify_ssl: "{{ openshift_verify_ssl }}" + +... diff --git a/roles/vm_storage_labeling/meta/main.yml b/roles/vm_storage_labeling/meta/main.yml new file mode 100644 index 0000000..1ff34cd --- /dev/null +++ b/roles/vm_storage_labeling/meta/main.yml @@ -0,0 +1,10 @@ +--- +galaxy_info: + author: "" + description: Add labels, annotations, and descriptive names to storage volumes (PVCs and DataVolumes). + company: Red Hat + license: GPL-3.0-only + min_ansible_version: 2.15.0 + galaxy_tags: [] +dependencies: [] +... diff --git a/roles/vm_storage_labeling/tasks/_apply_metadata.yml b/roles/vm_storage_labeling/tasks/_apply_metadata.yml new file mode 100644 index 0000000..1f78771 --- /dev/null +++ b/roles/vm_storage_labeling/tasks/_apply_metadata.yml @@ -0,0 +1,75 @@ +--- + +- name: _apply_metadata | Initialize Patch Operations + ansible.builtin.set_fact: + vm_storage_labeling_patch: [] + +- name: _apply_metadata | Build Label Patch Operations + when: vm_storage_labeling_current_request.labels | default({}, true) | length > 0 + ansible.builtin.set_fact: + vm_storage_labeling_patch: >- + {{ vm_storage_labeling_patch + [ + { + 'op': ('replace' + if (vm_storage_labeling_volume.metadata.labels | default({}) | dict2items + | selectattr('key', 'equalto', vm_storage_labeling_label.key) | list | length > 0) + else 'add'), + 'path': '/metadata/labels/' + (vm_storage_labeling_label.key | regex_replace('/', '~1')), + 'value': vm_storage_labeling_label.value + } + ] }} + loop: "{{ vm_storage_labeling_current_request.labels | dict2items }}" + loop_control: + loop_var: vm_storage_labeling_label + label: "{{ vm_storage_labeling_label.key }}" + +- name: _apply_metadata | Build Annotation Patch Operations + when: vm_storage_labeling_current_request.annotations | default({}, true) | length > 0 + ansible.builtin.set_fact: + vm_storage_labeling_patch: >- + {{ vm_storage_labeling_patch + [ + { + 'op': ('replace' + if (vm_storage_labeling_volume.metadata.annotations | default({}) | dict2items + | selectattr('key', 'equalto', vm_storage_labeling_annotation.key) | list | length > 0) + else 'add'), + 'path': '/metadata/annotations/' + (vm_storage_labeling_annotation.key | regex_replace('/', '~1')), + 'value': vm_storage_labeling_annotation.value + } + ] }} + loop: "{{ vm_storage_labeling_current_request.annotations | dict2items }}" + loop_control: + loop_var: vm_storage_labeling_annotation + label: "{{ vm_storage_labeling_annotation.key }}" + +- name: _apply_metadata | Apply Patch to PersistentVolumeClaim + when: vm_storage_labeling_patch | length > 0 + kubernetes.core.k8s_json_patch: + api_key: "{{ vm_storage_labeling_api_key }}" + host: "{{ vm_storage_labeling_openshift_host }}" + api_version: v1 + kind: PersistentVolumeClaim + namespace: "{{ vm_storage_labeling_volume.metadata.namespace }}" + name: "{{ vm_storage_labeling_volume.metadata.name }}" + validate_certs: "{{ vm_storage_labeling_openshift_verify_ssl }}" + patch: "{{ vm_storage_labeling_patch }}" + register: vm_storage_labeling_patch_result + +- name: _apply_metadata | Apply Patch to DataVolume + when: + - vm_storage_labeling_patch | length > 0 + - vm_storage_labeling_volume.metadata.ownerReferences | default([]) + | selectattr('kind', 'equalto', 'DataVolume') | list | length > 0 + kubernetes.core.k8s_json_patch: + api_key: "{{ vm_storage_labeling_api_key }}" + host: "{{ vm_storage_labeling_openshift_host }}" + api_version: cdi.kubevirt.io/v1beta1 + kind: DataVolume + namespace: "{{ vm_storage_labeling_volume.metadata.namespace }}" + name: "{{ vm_storage_labeling_volume.metadata.name }}" + validate_certs: "{{ vm_storage_labeling_openshift_verify_ssl }}" + patch: "{{ vm_storage_labeling_patch }}" + register: vm_storage_labeling_dv_patch_result + failed_when: false + +... diff --git a/roles/vm_storage_labeling/tasks/_process_request.yml b/roles/vm_storage_labeling/tasks/_process_request.yml new file mode 100644 index 0000000..054081a --- /dev/null +++ b/roles/vm_storage_labeling/tasks/_process_request.yml @@ -0,0 +1,82 @@ +--- + +- name: _process_request | Query PVCs by Name + when: vm_storage_labeling_current_request.names | default([], true) | length > 0 + kubernetes.core.k8s_info: + api_key: "{{ vm_storage_labeling_api_key }}" + host: "{{ vm_storage_labeling_openshift_host }}" + api_version: v1 + kind: PersistentVolumeClaim + namespace: "{{ vm_storage_labeling_current_request.namespace }}" + name: "{{ vm_storage_labeling_pvc_name }}" + validate_certs: "{{ vm_storage_labeling_openshift_verify_ssl }}" + register: vm_storage_labeling_pvc_by_name + loop: "{{ vm_storage_labeling_current_request.names }}" + loop_control: + loop_var: vm_storage_labeling_pvc_name + label: "{{ vm_storage_labeling_pvc_name }}" + +- name: _process_request | Query PVCs by Label Selector + when: vm_storage_labeling_current_request.label_selectors | default([], true) | length > 0 + kubernetes.core.k8s_info: + api_key: "{{ vm_storage_labeling_api_key }}" + host: "{{ vm_storage_labeling_openshift_host }}" + api_version: v1 + kind: PersistentVolumeClaim + namespace: "{{ vm_storage_labeling_current_request.namespace }}" + label_selectors: "{{ vm_storage_labeling_current_request.label_selectors }}" + validate_certs: "{{ vm_storage_labeling_openshift_verify_ssl }}" + register: vm_storage_labeling_pvc_by_selector + +- name: _process_request | Query All PVCs in Namespace + when: + - vm_storage_labeling_current_request.names | default([], true) | length == 0 + - vm_storage_labeling_current_request.label_selectors | default([], true) | length == 0 + kubernetes.core.k8s_info: + api_key: "{{ vm_storage_labeling_api_key }}" + host: "{{ vm_storage_labeling_openshift_host }}" + api_version: v1 + kind: PersistentVolumeClaim + namespace: "{{ vm_storage_labeling_current_request.namespace }}" + validate_certs: "{{ vm_storage_labeling_openshift_verify_ssl }}" + register: vm_storage_labeling_pvc_all + +- name: _process_request | Build Volume List from Named PVCs + when: vm_storage_labeling_pvc_by_name is not skipped + ansible.builtin.set_fact: + vm_storage_labeling_volumes: >- + {{ vm_storage_labeling_pvc_by_name.results + | selectattr('resources', 'defined') + | map(attribute='resources') + | flatten }} + +- name: _process_request | Build Volume List from Selector PVCs + when: vm_storage_labeling_pvc_by_selector is not skipped + ansible.builtin.set_fact: + vm_storage_labeling_volumes: "{{ vm_storage_labeling_pvc_by_selector.resources | default([]) }}" + +- name: _process_request | Build Volume List from All PVCs + when: vm_storage_labeling_pvc_all is not skipped + ansible.builtin.set_fact: + vm_storage_labeling_volumes: "{{ vm_storage_labeling_pvc_all.resources | default([]) }}" + +- name: _process_request | Verify Volumes Found + ansible.builtin.assert: + that: + - vm_storage_labeling_volumes | default([], true) | length > 0 + fail_msg: >- + No PersistentVolumeClaims found in namespace '{{ vm_storage_labeling_current_request.namespace }}' + matching the provided criteria + quiet: true + +- name: _process_request | Apply Labels and Annotations to Volumes + ansible.builtin.include_tasks: + file: _apply_metadata.yml + loop: "{{ vm_storage_labeling_volumes }}" + loop_control: + loop_var: vm_storage_labeling_volume + label: >- + Namespace: {{ vm_storage_labeling_volume.metadata.namespace }} + - Name: {{ vm_storage_labeling_volume.metadata.name }} + +... diff --git a/roles/vm_storage_labeling/tasks/main.yml b/roles/vm_storage_labeling/tasks/main.yml new file mode 100644 index 0000000..8746a40 --- /dev/null +++ b/roles/vm_storage_labeling/tasks/main.yml @@ -0,0 +1,40 @@ +--- + +- name: Verify vm_storage_labeling_request Variable Provided + ansible.builtin.assert: + that: + - vm_storage_labeling_request | default("", true) | length > 0 + fail_msg: "'vm_storage_labeling_request' Variable Not Provided" + quiet: true + +- name: Verify Required Properties Provided + ansible.builtin.assert: + that: + - vm_storage_labeling_request | selectattr('namespace', 'undefined') | list | length == 0 + fail_msg: "Required property 'namespace' in 'vm_storage_labeling_request' Variable Not Provided" + quiet: true + +- name: Verify Labels or Annotations Provided + ansible.builtin.assert: + that: + - >- + (vm_storage_labeling_item.labels | default({}, true) | length > 0) or + (vm_storage_labeling_item.annotations | default({}, true) | length > 0) + fail_msg: >- + Either 'labels' or 'annotations' must be provided for + namespace '{{ vm_storage_labeling_item.namespace }}' + quiet: true + loop: "{{ vm_storage_labeling_request }}" + loop_control: + loop_var: vm_storage_labeling_item + label: "Namespace: {{ vm_storage_labeling_item.namespace }}" + +- name: Process Storage Volume Labeling Request + ansible.builtin.include_tasks: + file: _process_request.yml + loop: "{{ vm_storage_labeling_request }}" + loop_control: + loop_var: vm_storage_labeling_current_request + label: "Namespace: {{ vm_storage_labeling_current_request.namespace }}" + +... diff --git a/roles/vm_storage_labeling/tests/inventory b/roles/vm_storage_labeling/tests/inventory new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/roles/vm_storage_labeling/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/roles/vm_storage_labeling/tests/test.yml b/roles/vm_storage_labeling/tests/test.yml new file mode 100644 index 0000000..fc12bcc --- /dev/null +++ b/roles/vm_storage_labeling/tests/test.yml @@ -0,0 +1,7 @@ +--- +- name: Test + hosts: localhost + remote_user: root + roles: + - vm_storage_labeling +... From 53b8d8ebf583f6052e9954f3926fe489e52770b9 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 09:51:58 -0400 Subject: [PATCH 02/12] fix: add missing allowlist_externals for tox-ansible environments --- tox-ansible.ini | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tox-ansible.ini b/tox-ansible.ini index 3e1b6d9..27d44ea 100644 --- a/tox-ansible.ini +++ b/tox-ansible.ini @@ -31,6 +31,14 @@ allowlist_externals = mkdir ln bash + echo + git + ansible-galaxy + ansible-test + ansible-doc + pytest + mkdir + ln commands = mkdir -p "{env:HOME}/.ansible/collections/ansible_collections" ansible-galaxy collection install "{toxinidir}" -p '{env:HOME}/.ansible/collections/ansible_collections' --force @@ -50,6 +58,14 @@ change_dir = {env:HOME}/.ansible/collections/ansible_collections/infra/openshift skip_install = false allowlist_externals = bash + echo + git + ansible-galaxy + ansible-test + ansible-doc + pytest + mkdir + ln commands = bash -c 'git init --initial-branch=main .' bash -c 'ansible-test integration' From beebafa42ba7a0f6db2f751377b2afb03ce8f734 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 10:00:31 -0400 Subject: [PATCH 03/12] fix: let tox-ansible manage test commands instead of overriding --- tox-ansible.ini | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tox-ansible.ini b/tox-ansible.ini index 27d44ea..5c79a79 100644 --- a/tox-ansible.ini +++ b/tox-ansible.ini @@ -46,15 +46,13 @@ commands = [testenv] set_env = - COLLECTIONS_PATH = "{env:HOME}/.ansible/collections/ansible_collections" + COLLECTIONS_PATH = {env:HOME}/.ansible/collections/ansible_collections FORCE_COLOR = 1 passenv = HOME ANSIBLE_COLLECTIONS_PATH + ANSIBLE_GALAXY_* no_package = true -deps = - -r tests/integration/requirements.txt -change_dir = {env:HOME}/.ansible/collections/ansible_collections/infra/openshift_virtualization_ops skip_install = false allowlist_externals = bash @@ -66,6 +64,5 @@ allowlist_externals = pytest mkdir ln -commands = - bash -c 'git init --initial-branch=main .' - bash -c 'ansible-test integration' + sh + ade From 9d2e4ee4418c1f259b09f46c632c0e5df8a5c559 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 10:11:16 -0400 Subject: [PATCH 04/12] fix: add distlib to integration requirements for manifest support --- tests/integration/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/requirements.txt b/tests/integration/requirements.txt index 8b3ac1e..04708bc 100644 --- a/tests/integration/requirements.txt +++ b/tests/integration/requirements.txt @@ -1 +1,2 @@ # Add python packages that are required for integration testing +distlib From 190b6f67b0811ed2dcf5d451b00d50ea1eb3a666 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 10:22:53 -0400 Subject: [PATCH 05/12] fix: add distlib to testenv deps for galaxy/sanity manifest support --- tox-ansible.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox-ansible.ini b/tox-ansible.ini index 5c79a79..d8b5c88 100644 --- a/tox-ansible.ini +++ b/tox-ansible.ini @@ -54,6 +54,8 @@ passenv = ANSIBLE_GALAXY_* no_package = true skip_install = false +deps = + distlib allowlist_externals = bash echo From aea07315bf66bbb21e1b12f34b349b62e820e717 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 10:26:49 -0400 Subject: [PATCH 06/12] =?UTF-8?q?fix:=20remove=20testenv=20overrides=20?= =?UTF-8?q?=E2=80=94=20only=20set=20allowlist=5Fexternals,=20let=20tox-ans?= =?UTF-8?q?ible=20manage=20deps/commands?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tox-ansible.ini | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tox-ansible.ini b/tox-ansible.ini index d8b5c88..5e0966b 100644 --- a/tox-ansible.ini +++ b/tox-ansible.ini @@ -31,31 +31,12 @@ allowlist_externals = mkdir ln bash - echo - git - ansible-galaxy - ansible-test - ansible-doc - pytest - mkdir - ln commands = mkdir -p "{env:HOME}/.ansible/collections/ansible_collections" ansible-galaxy collection install "{toxinidir}" -p '{env:HOME}/.ansible/collections/ansible_collections' --force ansible-galaxy collection install -r "{toxinidir}/requirements-dev.yml" [testenv] -set_env = - COLLECTIONS_PATH = {env:HOME}/.ansible/collections/ansible_collections - FORCE_COLOR = 1 -passenv = - HOME - ANSIBLE_COLLECTIONS_PATH - ANSIBLE_GALAXY_* -no_package = true -skip_install = false -deps = - distlib allowlist_externals = bash echo From 90c604d6496ca12e1e97053313741c398a376b3a Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 10:38:05 -0400 Subject: [PATCH 07/12] fix: add distlib to galaxy tox env for manifest support --- tox-ansible.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tox-ansible.ini b/tox-ansible.ini index 5e0966b..9348a75 100644 --- a/tox-ansible.ini +++ b/tox-ansible.ini @@ -49,3 +49,8 @@ allowlist_externals = ln sh ade + +[testenv:galaxy] +deps = + galaxy-importer>=0.4.31 + distlib From 0b865dd09d2b50489aa186ec3a02356266f7c155 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Mon, 4 May 2026 08:21:44 -0400 Subject: [PATCH 08/12] fix: add missing README for vm_storage_labeling role --- roles/vm_storage_labeling/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 roles/vm_storage_labeling/README.md diff --git a/roles/vm_storage_labeling/README.md b/roles/vm_storage_labeling/README.md new file mode 100644 index 0000000..b8ea4cc --- /dev/null +++ b/roles/vm_storage_labeling/README.md @@ -0,0 +1,17 @@ +# vm_storage_labeling + +Add labels, annotations, and descriptive names to storage volumes (PVCs and DataVolumes) in OpenShift Virtualization. + +## Requirements + +- `redhat.openshift_virtualization` collection +- `kubernetes.core` collection +- OpenShift cluster with Virtualization operator installed + +## Role Variables + +See `defaults/main.yml` for available variables. + +## License + +Apache-2.0 From 1bd00c9f6296115b9ff6e78d441b7309a9743c18 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Mon, 4 May 2026 08:23:36 -0400 Subject: [PATCH 09/12] fix: restore original testenv config, only add allowlist_externals --- tox-ansible.ini | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tox-ansible.ini b/tox-ansible.ini index 9348a75..89248d9 100644 --- a/tox-ansible.ini +++ b/tox-ansible.ini @@ -37,20 +37,29 @@ commands = ansible-galaxy collection install -r "{toxinidir}/requirements-dev.yml" [testenv] +set_env = + COLLECTIONS_PATH = "{env:HOME}/.ansible/collections/ansible_collections" + FORCE_COLOR = 1 +passenv = + HOME + ANSIBLE_COLLECTIONS_PATH +no_package = true +deps = + -r tests/integration/requirements.txt +change_dir = {env:HOME}/.ansible/collections/ansible_collections/infra/openshift_virtualization_ops +skip_install = false allowlist_externals = bash echo git + mkdir + sh + ade ansible-galaxy ansible-test ansible-doc pytest - mkdir ln - sh - ade - -[testenv:galaxy] -deps = - galaxy-importer>=0.4.31 - distlib +commands = + bash -c 'git init --initial-branch=main .' + bash -c 'ansible-test integration' From bef3a512c64656667f88395adf6709accf76c079 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Mon, 4 May 2026 08:36:39 -0400 Subject: [PATCH 10/12] fix: pin tox-ansible<26.2.2 to match main (26.3.0 requires ade) --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 9d3d4f9..0061feb 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -5,7 +5,7 @@ pytest-cov coverage molecule tox -tox-ansible +tox-ansible<26.2.2 black jmespath ansible-core From a78f5e6e9d85dec67bb7eb1601ae684385d44440 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Mon, 18 May 2026 21:08:38 -0400 Subject: [PATCH 11/12] fix: enforce SSL verification and suppress credential logging - Change openshift_verify_ssl default from false to true in all 5 playbooks (vm_backup, vm_restore, vm_hot_plug, vm_operations, vm_storage_labeling) - Add no_log: true to all tasks that pass api_key to k8s modules or use Bearer token headers --- CHANGELOG.md | 9 +++++++++ playbooks/vm_backup.yml | 2 +- playbooks/vm_hot_plug.yml | 2 +- playbooks/vm_operations.yml | 2 +- playbooks/vm_restore.yml | 2 +- playbooks/vm_storage_labeling.yml | 2 +- roles/vm_backup_restore/tasks/_restore_vm.yml | 3 +++ roles/vm_backup_restore/tasks/_snapshot_vm.yml | 1 + roles/vm_collect/tasks/main.yml | 2 ++ roles/vm_hot_plug/tasks/_compute.yml | 1 + roles/vm_hot_plug/tasks/_process_vm.yml | 1 + roles/vm_hot_plug/tasks/_storage.yml | 1 + roles/vm_lifecycle/tasks/_collect_vms.yml | 2 ++ roles/vm_lifecycle/tasks/_perform_operation.yml | 1 + roles/vm_lifecycle/tasks/_verify_operation.yml | 1 + roles/vm_storage_labeling/tasks/_apply_metadata.yml | 2 ++ roles/vm_storage_labeling/tasks/_process_request.yml | 3 +++ 17 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0849992..a843459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # CHANGELOG +## v1.0.4 (2026-05-18) + +### Security + +- Change SSL verify default from `false` to `true` in all 5 playbooks +- Add `no_log: true` to all tasks that handle `api_key` or Bearer tokens + across vm_backup_restore, vm_hot_plug, vm_lifecycle, vm_collect, and + vm_storage_labeling roles + ## v1.0.3 (2026-05-05) ### Bug Fixes diff --git a/playbooks/vm_backup.yml b/playbooks/vm_backup.yml index 666fbd7..c0578ca 100644 --- a/playbooks/vm_backup.yml +++ b/playbooks/vm_backup.yml @@ -12,5 +12,5 @@ vars: openshift_host: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_HOST', default=Undefined) | default('', True) }}" openshift_api_key: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_API_KEY', default=Undefined) | default('', True) }}" # noqa: yaml[line-length] - openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(false) | bool }}" # noqa: yaml[line-length] + openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(true) | bool }}" # noqa: yaml[line-length] ... diff --git a/playbooks/vm_hot_plug.yml b/playbooks/vm_hot_plug.yml index 94476f4..4414421 100644 --- a/playbooks/vm_hot_plug.yml +++ b/playbooks/vm_hot_plug.yml @@ -11,5 +11,5 @@ vars: openshift_host: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_HOST', default=Undefined) | default('', True) }}" openshift_api_key: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_API_KEY', default=Undefined) | default('', True) }}" # noqa: yaml[line-length] - openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(false) | bool }}" # noqa: yaml[line-length] + openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(true) | bool }}" # noqa: yaml[line-length] ... diff --git a/playbooks/vm_operations.yml b/playbooks/vm_operations.yml index 3a41371..3db5d5a 100644 --- a/playbooks/vm_operations.yml +++ b/playbooks/vm_operations.yml @@ -11,5 +11,5 @@ vars: openshift_host: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_HOST', default=Undefined) | default('', True) }}" openshift_api_key: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_API_KEY', default=Undefined) | default('', True) }}" # noqa: yaml[line-length] - openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(false) | bool }}" # noqa: yaml[line-length] + openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(true) | bool }}" # noqa: yaml[line-length] ... diff --git a/playbooks/vm_restore.yml b/playbooks/vm_restore.yml index eadc3aa..f0a6e6f 100644 --- a/playbooks/vm_restore.yml +++ b/playbooks/vm_restore.yml @@ -12,5 +12,5 @@ vars: openshift_host: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_HOST', default=Undefined) | default('', True) }}" openshift_api_key: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_API_KEY', default=Undefined) | default('', True) }}" # noqa: yaml[line-length] - openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(false) | bool }}" # noqa: yaml[line-length] + openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(true) | bool }}" # noqa: yaml[line-length] ... diff --git a/playbooks/vm_storage_labeling.yml b/playbooks/vm_storage_labeling.yml index add6b40..ea4a9d6 100644 --- a/playbooks/vm_storage_labeling.yml +++ b/playbooks/vm_storage_labeling.yml @@ -11,5 +11,5 @@ vars: openshift_host: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_HOST', default=Undefined) | default('', True) }}" openshift_api_key: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_API_KEY', default=Undefined) | default('', True) }}" # noqa: yaml[line-length] - openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(false) | bool }}" # noqa: yaml[line-length] + openshift_verify_ssl: "{{ lookup('ansible.builtin.env', 'K8S_AUTH_VERIFY_SSL', default='') | default(true) | bool }}" # noqa: yaml[line-length] ... diff --git a/roles/vm_backup_restore/tasks/_restore_vm.yml b/roles/vm_backup_restore/tasks/_restore_vm.yml index 9b6f80f..4e58527 100644 --- a/roles/vm_backup_restore/tasks/_restore_vm.yml +++ b/roles/vm_backup_restore/tasks/_restore_vm.yml @@ -1,6 +1,7 @@ --- - name: _restore_vm | Stop Virtual Machine + no_log: true redhat.openshift_virtualization.kubevirt_vm: api_key: "{{ vm_backup_restore_openshift_api_key }}" host: "{{ vm_backup_restore_openshift_host }}" @@ -12,6 +13,7 @@ wait_timeout: "{{ vm_backup_restore_vm_wait_timeout }}" - name: _restore_vm | Create Restore + no_log: true redhat.openshift.k8s: state: present api_key: "{{ vm_backup_restore_openshift_api_key }}" @@ -41,6 +43,7 @@ type: Ready - name: _restore_vm | Start Virtual Machine + no_log: true redhat.openshift_virtualization.kubevirt_vm: api_key: "{{ vm_backup_restore_openshift_api_key }}" host: "{{ vm_backup_restore_openshift_host }}" diff --git a/roles/vm_backup_restore/tasks/_snapshot_vm.yml b/roles/vm_backup_restore/tasks/_snapshot_vm.yml index f1f873b..19c5aee 100644 --- a/roles/vm_backup_restore/tasks/_snapshot_vm.yml +++ b/roles/vm_backup_restore/tasks/_snapshot_vm.yml @@ -1,6 +1,7 @@ --- - name: _snapshot_vm | Create Snapshot + no_log: true redhat.openshift.k8s: state: present api_key: "{{ vm_backup_restore_openshift_api_key }}" diff --git a/roles/vm_collect/tasks/main.yml b/roles/vm_collect/tasks/main.yml index 0a3dfcb..ded89b0 100644 --- a/roles/vm_collect/tasks/main.yml +++ b/roles/vm_collect/tasks/main.yml @@ -25,6 +25,7 @@ when: "'label_selectors' not in vm_collect_request_instance" block: - name: "Query Without Label Selector {{ vm_collect_obj | default(vm_collect_obj_default_kind) }}" + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_collect_openshift_api_key }}" host: "{{ vm_collect_openshift_host }}" @@ -49,6 +50,7 @@ when: "'label_selectors' in vm_collect_request_instance" block: - name: "Query (With Label Selector) - {{ vm_collect_obj | default(vm_collect_obj_default_kind) }}" + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_collect_openshift_api_key }}" host: "{{ vm_collect_openshift_host }}" diff --git a/roles/vm_hot_plug/tasks/_compute.yml b/roles/vm_hot_plug/tasks/_compute.yml index 9d30f94..7698dcc 100644 --- a/roles/vm_hot_plug/tasks/_compute.yml +++ b/roles/vm_hot_plug/tasks/_compute.yml @@ -20,6 +20,7 @@ quiet: true - name: _compute | Patch VM with Compute Modifications + no_log: true kubernetes.core.k8s_json_patch: api_key: "{{ vm_hot_plug_api_key }}" host: "{{ vm_hot_plug_openshift_host }}" diff --git a/roles/vm_hot_plug/tasks/_process_vm.yml b/roles/vm_hot_plug/tasks/_process_vm.yml index 3e5c843..d17470d 100644 --- a/roles/vm_hot_plug/tasks/_process_vm.yml +++ b/roles/vm_hot_plug/tasks/_process_vm.yml @@ -14,6 +14,7 @@ when: "'restartIfRequired' in vm_hot_plug_vm and vm_hot_plug_vm.restartIfRequired | bool" block: - name: _process_vm | Query VM for Updated Configuration + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_hot_plug_api_key }}" host: "{{ vm_hot_plug_openshift_host }}" diff --git a/roles/vm_hot_plug/tasks/_storage.yml b/roles/vm_hot_plug/tasks/_storage.yml index 8060e3d..d9846b5 100644 --- a/roles/vm_hot_plug/tasks/_storage.yml +++ b/roles/vm_hot_plug/tasks/_storage.yml @@ -19,6 +19,7 @@ default([]) | selectattr('name', 'equalto', vm_hot_plug_storage_instance.name) | list | length == 0 ) + no_log: true ansible.builtin.uri: url: "{{ vm_hot_plug_openshift_host }}/apis/subresources.{{ vm_hot_plug_kubevirt_api_version }}\ diff --git a/roles/vm_lifecycle/tasks/_collect_vms.yml b/roles/vm_lifecycle/tasks/_collect_vms.yml index 0289b9e..e64446a 100644 --- a/roles/vm_lifecycle/tasks/_collect_vms.yml +++ b/roles/vm_lifecycle/tasks/_collect_vms.yml @@ -20,6 +20,7 @@ when: "'label_selectors' not in vm_operations_request_instance" block: - name: "_collect_vms | Query VM's (Without Label Selector)" + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_lifecycle_openshift_api_key }}" host: "{{ vm_lifecycle_openshift_host }}" @@ -45,6 +46,7 @@ when: "'label_selectors' in vm_operations_request_instance" block: - name: "_collect_vms | Query VM's (With Label Selector)" + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_lifecycle_openshift_api_key }}" host: "{{ vm_lifecycle_openshift_host }}" diff --git a/roles/vm_lifecycle/tasks/_perform_operation.yml b/roles/vm_lifecycle/tasks/_perform_operation.yml index cedb815..2926258 100644 --- a/roles/vm_lifecycle/tasks/_perform_operation.yml +++ b/roles/vm_lifecycle/tasks/_perform_operation.yml @@ -1,6 +1,7 @@ --- - name: _perform_operation | Perform VM Operation + no_log: true ansible.builtin.uri: url: "{{ vm_lifecycle_openshift_host }}/apis/subresources.{{ vm_lifecycle_kubevirt_api_version }}/namespaces/{{ vm_operations_vm.vm.metadata.namespace }}/virtualmachines/{{ vm_operations_vm.vm.metadata.name }}/{{ vm_lifecycle_valid_vm_operations[vm_operations_vm['operation']].endpoint }}" # noqa: yaml[line-length] validate_certs: "{{ vm_lifecycle_openshift_verify_ssl }}" diff --git a/roles/vm_lifecycle/tasks/_verify_operation.yml b/roles/vm_lifecycle/tasks/_verify_operation.yml index d94e557..7fc3b3b 100644 --- a/roles/vm_lifecycle/tasks/_verify_operation.yml +++ b/roles/vm_lifecycle/tasks/_verify_operation.yml @@ -1,6 +1,7 @@ --- - name: _verify_operation | Verify VMs + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_lifecycle_openshift_api_key }}" host: "{{ vm_lifecycle_openshift_host }}" diff --git a/roles/vm_storage_labeling/tasks/_apply_metadata.yml b/roles/vm_storage_labeling/tasks/_apply_metadata.yml index 1f78771..c254384 100644 --- a/roles/vm_storage_labeling/tasks/_apply_metadata.yml +++ b/roles/vm_storage_labeling/tasks/_apply_metadata.yml @@ -44,6 +44,7 @@ - name: _apply_metadata | Apply Patch to PersistentVolumeClaim when: vm_storage_labeling_patch | length > 0 + no_log: true kubernetes.core.k8s_json_patch: api_key: "{{ vm_storage_labeling_api_key }}" host: "{{ vm_storage_labeling_openshift_host }}" @@ -60,6 +61,7 @@ - vm_storage_labeling_patch | length > 0 - vm_storage_labeling_volume.metadata.ownerReferences | default([]) | selectattr('kind', 'equalto', 'DataVolume') | list | length > 0 + no_log: true kubernetes.core.k8s_json_patch: api_key: "{{ vm_storage_labeling_api_key }}" host: "{{ vm_storage_labeling_openshift_host }}" diff --git a/roles/vm_storage_labeling/tasks/_process_request.yml b/roles/vm_storage_labeling/tasks/_process_request.yml index ca36e5b..68e10bb 100644 --- a/roles/vm_storage_labeling/tasks/_process_request.yml +++ b/roles/vm_storage_labeling/tasks/_process_request.yml @@ -2,6 +2,7 @@ - name: _process_request | Query PVCs by Name when: vm_storage_labeling_current_request.names | default([], true) | length > 0 + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_storage_labeling_api_key }}" host: "{{ vm_storage_labeling_openshift_host }}" @@ -18,6 +19,7 @@ - name: _process_request | Query PVCs by Label Selector when: vm_storage_labeling_current_request.label_selectors | default([], true) | length > 0 + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_storage_labeling_api_key }}" host: "{{ vm_storage_labeling_openshift_host }}" @@ -32,6 +34,7 @@ when: - vm_storage_labeling_current_request.names | default([], true) | length == 0 - vm_storage_labeling_current_request.label_selectors | default([], true) | length == 0 + no_log: true kubernetes.core.k8s_info: api_key: "{{ vm_storage_labeling_api_key }}" host: "{{ vm_storage_labeling_openshift_host }}" From 22c6b201383917db8635c8a334acfe938d8045e0 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 11 Jun 2026 15:52:24 -0400 Subject: [PATCH 12/12] feat: add audit event_query support --- extensions/audit/event_query.yml | 118 +++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 extensions/audit/event_query.yml diff --git a/extensions/audit/event_query.yml b/extensions/audit/event_query.yml new file mode 100644 index 0000000..49972de --- /dev/null +++ b/extensions/audit/event_query.yml @@ -0,0 +1,118 @@ +--- +infra.openshift_virtualization_ops.*: + query: >- + ( + { + "virtualmachine": "Virtual Machine", + "virtualmachineinstance": "VM Instance", + "backup": "VM Backup", + "restore": "VM Restore", + "snapshot": "VM Snapshot", + "datavolumetemplate": "Data Volume", + "network": "VM Network", + "storage": "VM Storage", + "migration": "Live Migration" + } as $mapping | + (.vm // .resources // .) | + (if type=="array" then .[] else if type=="object" then . else empty end end) as $data | + select($data.metadata != null or $data.name != null) | + ( + if $data | has("kind") then + ( + if $data.kind == "VirtualMachine" then "virtualmachine" + elif $data.kind == "VirtualMachineInstance" then "virtualmachineinstance" + elif $data.kind == "VirtualMachineInstanceMigration" then "migration" + elif $data.kind | test("Backup") then "backup" + elif $data.kind | test("Restore") then "restore" + elif $data.kind | test("Snapshot") then "snapshot" + elif $data.kind | test("DataVolume") then "datavolumetemplate" + elif $data.kind | test("NetworkAttachmentDefinition") then "network" + elif $data.kind | test("PersistentVolumeClaim") then "storage" + else "unknown" + end + ) + elif $data.metadata.labels then + ( + if $data.metadata.labels | has("kubevirt.io/vm") then "virtualmachine" + elif $data.metadata.labels | has("vm.kubevirt.io/name") then "virtualmachineinstance" + else "unknown" + end + ) + else "unknown" + end + ) as $node_type | + ( + if $node_type == "virtualmachine" or $node_type == "virtualmachineinstance" then + ( + if $data.status.printableStatus then $data.status.printableStatus + else "vm" + end + ) + elif $node_type == "migration" then "live-migration" + elif $node_type == "backup" then "backup" + elif $node_type == "restore" then "restore" + elif $node_type == "snapshot" then "snapshot" + elif $node_type == "datavolumetemplate" then "volume" + elif $node_type == "network" then "network" + elif $node_type == "storage" then "disk" + else "unknown" + end + ) as $sub_node_type | + { + name: ( + if $data.metadata then ($data.metadata.name // $data.metadata.uid) + else ($data.name // "UNKNOWN") + end + ), + canonical_facts: { + name: ( + if $data.metadata then ($data.metadata.name // "UNKNOWN") + else ($data.name // "UNKNOWN") + end + ), + id: ( + if $data.metadata then ($data.metadata.uid // $data.metadata.name) + else ($data.id // $data.name) + end + ), + node_type: $node_type + }, + facts: { + infra_type: "openshift_virtualization", + infra_bucket: ($mapping[$node_type] // "UNKNOWN"), + device_type: $sub_node_type, + namespace: ( + if $data.metadata then ($data.metadata.namespace // "") + else "" + end + ), + status: ( + if $data.status then + ( + if $data.status.printableStatus then $data.status.printableStatus + elif $data.status.phase then $data.status.phase + elif $data.status.conditions then + ( + $data.status.conditions | + map(select(.status == "True")) | + .[0].type // "unknown" + ) + else "unknown" + end + ) + else "unknown" + end + ), + operation: ( + if $data.operation then $data.operation + else "" + end + ), + labels: ( + if $data.metadata and $data.metadata.labels then $data.metadata.labels + else {} + end + ) + } + } + )