From 55b6cddac57c1c05ff1a99d9ecad18a0c51c102a Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 07:44:38 +0100 Subject: [PATCH 01/14] First try for cnv_instances --- .../cnv_instances/tasks/create_instance.yaml | 231 ++++++++++++++++++ roles/cnv_instances/tasks/create_routes.yaml | 85 +++++++ roles/cnv_instances/tasks/create_service.yaml | 72 ++++++ .../cnv_instances/tasks/create_services.yaml | 61 +++++ roles/cnv_instances/tasks/main.yml | 11 + roles/cnv_instances/tasks/remove_workload.yml | 8 + roles/cnv_instances/tasks/workload.yml | 26 ++ 7 files changed, 494 insertions(+) create mode 100644 roles/cnv_instances/tasks/create_instance.yaml create mode 100644 roles/cnv_instances/tasks/create_routes.yaml create mode 100644 roles/cnv_instances/tasks/create_service.yaml create mode 100644 roles/cnv_instances/tasks/create_services.yaml create mode 100644 roles/cnv_instances/tasks/main.yml create mode 100644 roles/cnv_instances/tasks/remove_workload.yml create mode 100644 roles/cnv_instances/tasks/workload.yml diff --git a/roles/cnv_instances/tasks/create_instance.yaml b/roles/cnv_instances/tasks/create_instance.yaml new file mode 100644 index 0000000..a5e922c --- /dev/null +++ b/roles/cnv_instances/tasks/create_instance.yaml @@ -0,0 +1,231 @@ +--- +- name: Empty variable _instance_ + ansible.builtin.set_fact: + _instance_interfaces: [] + _instance_networks: [] + _instance_volumes: + - dataVolume: + name: "INSTANCENAME-{{guid}}" + name: "INSTANCENAME-{{guid}}" + _instance_disks: + - disk: + bus: "{{ _instance.disk_type | default('virtio') }}" + name: "INSTANCENAME-{{guid}}" + +- name: Set the instances interfaces + ansible.builtin.set_fact: + _instance_interfaces: >- + {{ + _instance_interfaces + [{ + 'name': _network.split('/')[1] if '/' in _network else _network + guid, + 'macAddress': _instance.fixed_macs[_network] | default('2c:c2:60' | random_mac), + 'bridge': {}, + 'model': _instance.interface_model | default('virtio'), + } + if _network != 'default' + else { + 'name': 'default', + 'model': _instance.interface_model | default('virtio'), + 'masquerade': {} + }] + }} + _instance_networks: >- + {{ _instance_networks + [ + { + 'name': _network.split('/')[1] if '/' in _network else _network + guid, + 'multus': {'networkName': _network if '/' in _network else _network + guid} + } + if _network != 'default' + else { + 'name': 'default', + 'pod': {} + } + ] }} + loop: "{{ _instance.networks | default(['default']) | list }}" + loop_control: + loop_var: _network + index_var: _network_idx + +- name: Set the instances disks + ansible.builtin.set_fact: + _instance_disks: "{{ _instance_disks | from_yaml + [ + { + 'name': _disk.metadata.name, + 'disk': {'bus': _instance.disk_type | default('virtio')} + } + ] }}" + _instance_volumes: "{{ _instance_volumes | from_yaml + [ + { + 'name': _disk.metadata.name, + 'dataVolume': {'name': _disk.metadata.name} + } + ] }}" + loop: "{{ _instance.disks | default([]) | list }}" + loop_control: + loop_var: _disk + +- name: Set the instances cdroms + ansible.builtin.set_fact: + _instance_disks: "{{ _instance_disks | from_yaml + [ + { + 'name': _disk.metadata.name, + 'cdrom': {'bus': 'sata'} + } + ] }}" + _instance_volumes: "{{ _instance_volumes | from_yaml + [ + { + 'name': _disk.metadata.name, + 'dataVolume': {'name': _disk.metadata.name} + } + ] }}" + loop: "{{ _instance.cdroms | default([]) | list }}" + loop_control: + loop_var: _disk + + +- name: Set cloud_config + ansible.builtin.set_fact: + _cloud_config: |- + #cloud-config + ssh_authorized_keys: + - {{ lookup('file', ssh_provision_pubkey_path ) }} + {{ _instance.userdata | default('') | replace('#cloud-config','') | replace('INSTANCEGUID', guid) | default('') }} + +- name: Set cloud init disk if needed + when: _instance.disable_cloud_init | default(false) == false + set_fact: + _instance_volumes: "{{ _instance_volumes | from_yaml + [ + { + 'name': 'cloudinitdisk', + 'cloudInitNoCloud': { + 'userDataBase64': _cloud_config | b64encode, + 'networkDataBase64': _instance.networkdata | default('network: 2') | b64encode + } + } + ] }}" + _instance_disks: "{{ _instance_disks | from_yaml + [ + { + 'disk': {'bus': 'virtio'}, + 'name': 'cloudinitdisk' + } + ] }}" + +- name: Fail if image (pvc) doesn't exist on namespace cnv-images + when: _instance.image_type | default('pvc') == 'pvc' + kubernetes.core.k8s_info: + api_version: v1 + kind: PersistentVolumeClaim + name: "{{ _instance.image }}" + namespace: cnv-images + register: r_pvc_info + +- name: Fail if PVC does not exist + ansible.builtin.fail: + msg: "PersistentVolumeClaim {{ _instance.image }} does not exist in namespace cnv-images" + when: + - _instance.image_type | default('pvc') == 'pvc' + - r_pvc_info.resources | default([]) | length == 0 + + +- name: Create instance(s) "{{ _instance.name }}" + vars: + _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count|d(1)|int > 1 }}" + _datavolume: | + - metadata: + name: "{{ _instance_name }}-{{ guid }}" + spec: + source: + {% if _instance.image_type | default('pvc') == 'pvc' %} + pvc: + namespace: "cnv-images" + name: "{{ _instance.image }}" + {% elif _instance.image_type | default('pvc') == 'registry' %} + registry: + url: "{{ _instance.image }}" + {% elif _instance.image_type | default('pvc') in ['url','http'] %} + http: + url: "{{ _instance.image }}" + {% elif _instance.image_type | default('pvc') == 'blank' %} + blank: {} + {% endif %} + pvc: + accessModes: + - ReadWriteMany + volumeMode: Block + resources: + requests: + storage: "{{ _instance.image_size }}" + _spec: | + hostname: "{{ _instance_name }}" + subdomain: "{{ 'lab' if openshift_cnv_add_lab_subdomain | default(True) else '' }}" + domain: + firmware: + uuid: "{{ 99999999 | random | to_uuid }}" + bootloader: + {% if _instance.bootloader | default('bios') == 'bios' %} + bios: {} + {% elif _instance.bootloader | default('bios') in ['efi', 'uefi'] %} + efi: + secureBoot: false + {% endif %} + cpu: + cores: {{ _instance.cores }} + model: host-passthrough + machine: + type: "{{ _instance.machine_type | default('pc-q35-rhel9.2.0') }}" + memory: + guest: "{{ _instance.memory }}" + memory: + hugepages: + pageSize: "1Gi" + devices: + disks: {{ _instance_disks | replace('INSTANCENAME', _instance_name) }} + interfaces: {{ _instance_interfaces }} + networks: {{ _instance_networks }} + volumes: {{ _instance_volumes | replace('INSTANCENAME', _instance_name) }} + kubernetes.core.k8s: + definition: + apiVersion: kubevirt.io/v1 + kind: VirtualMachine + metadata: + name: "{{ _instance_name }}" + namespace: "{{ openshift_cnv_namespace }}" + annotations: >- + {{ cloud_tags_final + | combine(_instance.metadata|default({})) | combine(_instance.tags|default({}) | ec2_tags_to_dict) }} + spec: + dataVolumeTemplates: >- + {{ _datavolume | from_yaml + (_instance.disks | default([]) | to_json | replace('INSTANCENAME',_instance_name) | from_json) + (_instance.cdroms | default([]) | to_json | replace('INSTANCENAME',_instance_name) | from_json) }} + running: true + template: + metadata: + labels: + vm.cnv.io/name: "{{ _instance_name }}" + spec: "{{ _spec | from_yaml }}" + loop: "{{ range(1, _instance.count|default(1)|int+1) | list }}" + loop_control: + index_var: _index + register: r_openshift_cnv_instance + until: r_openshift_cnv_instance is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" + +- name: Wait till VM is running + vars: + _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count | default(1) | int > 1 }}" + kubernetes.core.k8s_info: + api_version: kubevirt.io/v1 + kind: VirtualMachine + name: "{{ _instance_name }}" + namespace: "{{ openshift_cnv_namespace }}" + register: r_vm_status + until: r_vm_status.resources[0].status.printableStatus | default('') == "Running" + retries: 30 + delay: 10 + loop: "{{ range(1, _instance.count | default(1) | int+1) | list }}" + loop_control: + index_var: _index + +- ansible.builtin.set_fact: + r_openshift_cnv_instances: "{{ r_openshift_cnv_instances + [item] }}" + loop: "{{ r_openshift_cnv_instance.results | list }}" diff --git a/roles/cnv_instances/tasks/create_routes.yaml b/roles/cnv_instances/tasks/create_routes.yaml new file mode 100644 index 0000000..d5ec446 --- /dev/null +++ b/roles/cnv_instances/tasks/create_routes.yaml @@ -0,0 +1,85 @@ +--- +- name: Create routes with tls + kubernetes.core.k8s: + definition: + apiVersion: route.openshift.io/v1 + kind: Route + metadata: + name: "{{ route.name }}" + namespace: "{{ openshift_cnv_namespace }}" + spec: + host: >- + {{ + (route.host | default(route.name) ~ '.' ~ guid ~ '.' ~ sandbox_openshift_apps_domain) + if (openshift_cnv_legacy_routes | default(false) and route.legacy | default(true)) or route.legacy | default(false) + else + (route.host | default(route.name) ~ '-' ~ guid ~ '.' ~ sandbox_openshift_apps_domain) + }} + port: + targetPort: "{{ route.targetPort }}" + tls: + termination: "{{ route.tls_termination | default('passthrough') }}" + insecureEdgeTerminationPolicy: None + destinationCACertificate: "{{ route.tls_destinationCACertificate | default('') }}" + to: + kind: Service + name: "{{ route.service }}" + httpHeaders: "{{ + ( + openshift_cnv_route_remove_x_frame_options_header + and (route.tls_termination | default('passthrough') != 'passthrough') + ) + | ternary( + { + 'actions': { + 'response': [ + { 'name': 'X-Frame-Options', 'action': { 'type': 'Delete' } }, + { 'name': 'Content-Security-Policy', 'action': { 'type': 'Delete' } }, + { 'name': 'referrer-policy', 'action': { 'type': 'Delete' } } + ] + } + }, + omit + ) + }}" + when: + - route.tls|default(False) == True + loop: "{{ _instance.routes|default([]) }}" + loop_control: + loop_var: route + register: r_createroute + until: r_createroute is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" + +- name: Create routes without tls + kubernetes.core.k8s: + definition: + apiVersion: route.openshift.io/v1 + kind: Route + metadata: + name: "{{ route.name }}" + namespace: "{{ openshift_cnv_namespace }}" + spec: + host: >- + {{ + (route.host | default(route.name) ~ '.' ~ guid ~ '.' ~ sandbox_openshift_apps_domain) + if openshift_cnv_legacy_routes | default(false) + else + (route.host | default(route.name) ~ '-' ~ guid ~ '.' ~ sandbox_openshift_apps_domain) + }} + path: "{{ route.path|default('/') }}" + port: + targetPort: "{{ route.targetPort }}" + to: + kind: Service + name: "{{ route.service }}" + httpHeaders: "{{ (openshift_cnv_route_remove_x_frame_options_header) | ternary({'actions': {'response': [{'name': 'X-Frame-Options', 'action': {'type': 'Delete'}}]}}, omit) }}" + when: "{{ route.tls|default(false) == false }}" + loop: "{{ _instance.routes|default([]) }}" + loop_control: + loop_var: route + register: r_createroute + until: r_createroute is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" diff --git a/roles/cnv_instances/tasks/create_service.yaml b/roles/cnv_instances/tasks/create_service.yaml new file mode 100644 index 0000000..7cdfc52 --- /dev/null +++ b/roles/cnv_instances/tasks/create_service.yaml @@ -0,0 +1,72 @@ +--- +- name: Create services for instance "{{ _instance.name }}" + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: "{{ service.name }}" + namespace: "{{ openshift_cnv_namespace }}" + spec: "{{ spec | from_yaml }}" + vars: + _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count|d(1)|int > 1 }}" + spec: | + ports: + {{ service.ports }} + selector: + vm.cnv.io/name: "{{ _instance_name }}" + type: {{ service.type | default('ClusterIP') }} + loop: "{{ range(1, _instance.count|default(1)|int+1) | list }}" + loop_control: + index_var: _index + register: r_service + until: r_service is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" + +- name: Wait for the LoadBalancer value + register: svc_fip + kubernetes.core.k8s_info: + api_version: v1 + kind: Service + name: "{{ service.name }}" + namespace: "{{ openshift_cnv_namespace }}" + until: svc_fip.resources[0].status.loadBalancer.ingress[0].ip | default('') != '' + retries: 10 + delay: 2 + when: + - service.type | default('ClusterIP') == "LoadBalancer" + +- name: If exist set the external IP for the instance and the ports + set_fact: + _instance_external_ip: "{{ svc_fip.resources[0].status.loadBalancer.ingress[0].ip }}" + _instance_external_ports: "{{ service.ports | map(attribute='port') | join(',') }}" + when: + - service.type | default('ClusterIP') == "LoadBalancer" + +- name: Add external_ip and external_ports to the instance + when: + - service.type | default('ClusterIP') == "LoadBalancer" + kubernetes.core.k8s: + state: patched + api_version: v1 + kind: VirtualMachine + name: "{{ _instance_name }}" + definition: + apiVersion: v1 + kind: VirtualMachine + metadata: + name: "{{ _instance_name }}" + namespace: "{{ openshift_cnv_namespace }}" + annotations: + external_ip: "{{ _instance_external_ip }}" + external_ports: "{{ _instance_external_ports }}" + vars: + _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count|d(1)|int > 1 }}" + loop: "{{ range(1, _instance.count|default(1)|int+1) | list }}" + loop_control: + index_var: _index + register: r_service + until: r_service is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" diff --git a/roles/cnv_instances/tasks/create_services.yaml b/roles/cnv_instances/tasks/create_services.yaml new file mode 100644 index 0000000..49405d6 --- /dev/null +++ b/roles/cnv_instances/tasks/create_services.yaml @@ -0,0 +1,61 @@ +- name: Create a SSH (or defined one) service for internal connections for node {{ _instance.name }} + vars: + _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count|d(1)|int > 1 }}" + _definition: | + apiVersion: v1 + kind: Service + metadata: + name: "{{ _instance_name }}" + namespace: "{{ openshift_cnv_namespace }}" + spec: + clusterIP: None + ports: + - port: {{ _instance.servicePort | default(22) |int}} + protocol: TCP + targetPort: {{ _instance.servicePort | default(22)|int }} + selector: + vm.cnv.io/name: "{{ _instance_name }}" + + kubernetes.core.k8s: + definition: "{{ _definition }}" + loop: "{{ range(1, _instance.count|default(1)|int+1) | list }}" + loop_control: + index_var: _index + register: r_service + until: r_service is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" + +- name: Create a service for subdomain lab + vars: + _definition: | + apiVersion: v1 + kind: Service + metadata: + name: "lab" + namespace: "{{ openshift_cnv_namespace }}" + spec: + clusterIP: None + ipFamilies: + - IPv4 + ports: + - name: foo + protocol: TCP + port: 1234 + targetPort: 1234 + selector: + kubevirt.io: virt-launcher + kubernetes.core.k8s: + definition: "{{ _definition }}" + register: r_service_lab + until: r_service_lab is success + retries: "{{ openshift_cnv_retries }}" + delay: "{{ openshift_cnv_delay }}" + when: "{{ openshift_cnv_add_lab_subdomain | default(True) }}" + + +- name: Create services for the instances + loop: "{{ _instance.services|default([]) }}" + loop_control: + loop_var: service + ansible.builtin.include_tasks: create_service.yaml diff --git a/roles/cnv_instances/tasks/main.yml b/roles/cnv_instances/tasks/main.yml new file mode 100644 index 0000000..23308e3 --- /dev/null +++ b/roles/cnv_instances/tasks/main.yml @@ -0,0 +1,11 @@ +--- +# -------------------------------------------------- +# Do not modify this file +# -------------------------------------------------- +- name: Running workload provision tasks + when: ACTION == "provision" + ansible.builtin.include_tasks: workload.yml + +- name: Running workload removal tasks + when: ACTION == "destroy" + ansible.builtin.include_tasks: remove_workload.yml diff --git a/roles/cnv_instances/tasks/remove_workload.yml b/roles/cnv_instances/tasks/remove_workload.yml new file mode 100644 index 0000000..37c8895 --- /dev/null +++ b/roles/cnv_instances/tasks/remove_workload.yml @@ -0,0 +1,8 @@ +--- +# ------------------------------------------ +# Implement your workload removal tasks here +# ------------------------------------------ + +- name: Deprovision your workload + ansible.builtin.debug: + msg: "Nothing to deprovision for example workload." diff --git a/roles/cnv_instances/tasks/workload.yml b/roles/cnv_instances/tasks/workload.yml new file mode 100644 index 0000000..91955eb --- /dev/null +++ b/roles/cnv_instances/tasks/workload.yml @@ -0,0 +1,26 @@ +--- +# ------------------------------------------------------------------------- +# To Do: Implement your workload deployment tasks here +# ------------------------------------------------------------------------- + +- set_fact: + r_openshift_cnv_instances: [] + +- name: Create Instances + loop: "{{ instances|default([]) }}" + loop_control: + loop_var: _instance + ansible.builtin.include_tasks: create_instance.yaml + + +- name: Create services for the nodes + ansible.builtin.include_tasks: create_services.yaml + loop: "{{ instances|default([]) }}" + loop_control: + loop_var: _instance + +- name: Create routes for the nodes + ansible.builtin.include_tasks: create_routes.yaml + loop: "{{ instances|default([]) }}" + loop_control: + loop_var: _instance From b766777bcd7b4bfd3199416cd1be169d66a82163 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 07:54:21 +0100 Subject: [PATCH 02/14] First try for cnv_instances --- roles/cnv_instances/defaults/main.yml | 33 ++++++++++++++++++++++++ roles/cnv_instances/meta/main.yml | 13 ++++++++++ roles/cnv_instances/readme.adoc | 37 +++++++++++++++++++++++++++ roles/cnv_instances/vars/main.yml | 6 +++++ 4 files changed, 89 insertions(+) create mode 100644 roles/cnv_instances/defaults/main.yml create mode 100644 roles/cnv_instances/meta/main.yml create mode 100644 roles/cnv_instances/readme.adoc create mode 100644 roles/cnv_instances/vars/main.yml diff --git a/roles/cnv_instances/defaults/main.yml b/roles/cnv_instances/defaults/main.yml new file mode 100644 index 0000000..f951813 --- /dev/null +++ b/roles/cnv_instances/defaults/main.yml @@ -0,0 +1,33 @@ +--- +# If your workload needs customization options provide variables to be used. +# +# Variable names must be prefixed by the role name, e.g. "_". +# +# Therefore because this example workload is called "ns_example" the variables +# must be named "ns_example_variable". +# +# You can override the defaults as parameters to the Ansible run that deploys +# your workload via the AgnosticV configuration. + +cnv_instances: [] + +instances: {{ cnv_instances }} + +openshift_cnv_namespace: "{{ sandbox_openshift_namespace }}" + +# Naming of instances +openshift_cnv_instance_numeration: '%d' + +# Delete device retry +openshift_cnv_delete_retries: 20 +openshift_cnv_delete_delay: 60 + +# Retries and delay variable +openshift_cnv_retries: 6 +openshift_cnv_delay: 10 + +# Remove X-Frame-Options header (to iframe apps, for example in showroom) +openshift_cnv_route_remove_x_frame_options_header: false + +# Use host.guid.domain +openshift_cnv_legacy_routes: false diff --git a/roles/cnv_instances/meta/main.yml b/roles/cnv_instances/meta/main.yml new file mode 100644 index 0000000..8082e18 --- /dev/null +++ b/roles/cnv_instances/meta/main.yml @@ -0,0 +1,13 @@ +--- +galaxy_info: + role_name: cnv_instances + author: Red Hat, Alberto Gonzalez (josegonz@redhat.com) + description: | + Example workload to be deployed onto OpenShift 4 + license: MIT + min_ansible_version: "2.9" + platforms: [] + galaxy_tags: + - ocp + - openshift +dependencies: [] diff --git a/roles/cnv_instances/readme.adoc b/roles/cnv_instances/readme.adoc new file mode 100644 index 0000000..f1613d2 --- /dev/null +++ b/roles/cnv_instances/readme.adoc @@ -0,0 +1,37 @@ += cnv_instances - Create instances on CNV cluster + +== Role overview + +* This is a working no-op role that can be used as a template to develop new workload roles to deploy to a cnv instances config. It consists of the following tasks files: + +** Tasks: link:./tasks/workload.yml[workload.yml] - Used to deploy the actual workload, i.e, 3scale, some Demo or OpenShift customization +*** This role only prints the current username for which this role is provisioning. + +** Tasks: link:./tasks/remove_workload.yml[remove_workload.yml] - Used to delete the workload +*** This role doesn't do anything here + +The provisioning infrastructure will set a variable `ACTION` to be either `provision` or `destroy` depending on the operation. + +== The defaults variable file + +=== Variable Naming + +Since Ansible lacks robust variable scoping you *must* use long-name scope parameters for your workload to avoid variable clashing. + +For example, parameters named `ns_example_*` would be recognized as unique to this workload. + +* This file link:./defaults/main.yml[./defaults/main.yml] contains all the variables you need to define to control the deployment of your workload. +* The variable *ocp_username* is mandatory to assign the workload to the correct OpenShift user when deploying to a shared cluster. For most workloads the default of `system:admin` is the correct value unless this is a workload to be applied to a shared cluster. +* You can modify any of these default values by adding `-e "variable_name=variable_value"` to the command line +* Your deployer will override any of these variables based on configuration in AgnosticV +* Add long-name scoped workload parameters. Example: `ns_example_machineconfigpool_name: worker` + +== The internal variable file + +If the workload needs to set some internal variables define them in the file link:./vars/main.yml[./vars/main.yml]. + +Variables should be named just like external variables with the exception that they should start with an underscore (`_`). + +Examples: + +* `cnv_instances` diff --git a/roles/cnv_instances/vars/main.yml b/roles/cnv_instances/vars/main.yml new file mode 100644 index 0000000..0beb869 --- /dev/null +++ b/roles/cnv_instances/vars/main.yml @@ -0,0 +1,6 @@ +--- +# Any internal variables should be defined here. +# Variable names must start with a single underscore (_) followed by the workload role name +# Variable values should be empty to indicate that they will be set during the workload run. +# Add comments for documentation if so required. +_cnv_instances_internal: [] From a5ab1e067fe8c042ce7d60ed7f4ddd2df747dba0 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 07:55:35 +0100 Subject: [PATCH 03/14] First try for cnv_instances --- roles/cnv_instances/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/cnv_instances/defaults/main.yml b/roles/cnv_instances/defaults/main.yml index f951813..e295051 100644 --- a/roles/cnv_instances/defaults/main.yml +++ b/roles/cnv_instances/defaults/main.yml @@ -11,7 +11,7 @@ cnv_instances: [] -instances: {{ cnv_instances }} +instances: "{{ cnv_instances }}" openshift_cnv_namespace: "{{ sandbox_openshift_namespace }}" From 6292a9e62e55379c69ecc8cc16cea7a87b5c3a66 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 07:57:40 +0100 Subject: [PATCH 04/14] First try for cnv_instances --- roles/cnv_instances/tasks/create_instance.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/cnv_instances/tasks/create_instance.yaml b/roles/cnv_instances/tasks/create_instance.yaml index a5e922c..8decb2a 100644 --- a/roles/cnv_instances/tasks/create_instance.yaml +++ b/roles/cnv_instances/tasks/create_instance.yaml @@ -88,7 +88,6 @@ _cloud_config: |- #cloud-config ssh_authorized_keys: - - {{ lookup('file', ssh_provision_pubkey_path ) }} {{ _instance.userdata | default('') | replace('#cloud-config','') | replace('INSTANCEGUID', guid) | default('') }} - name: Set cloud init disk if needed From 7f13eb66a8856c0cf0cf7aa899666c523c2a271f Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 08:02:20 +0100 Subject: [PATCH 05/14] First try for cnv_instances --- roles/cnv_instances/tasks/workload.yml | 37 +++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/roles/cnv_instances/tasks/workload.yml b/roles/cnv_instances/tasks/workload.yml index 91955eb..11b60b5 100644 --- a/roles/cnv_instances/tasks/workload.yml +++ b/roles/cnv_instances/tasks/workload.yml @@ -6,21 +6,28 @@ - set_fact: r_openshift_cnv_instances: [] -- name: Create Instances - loop: "{{ instances|default([]) }}" - loop_control: - loop_var: _instance - ansible.builtin.include_tasks: create_instance.yaml +- name: Create instances, services and routes + module_defaults: + group/k8s: + host: "{{ sandbox_openshift_api_url }}" + api_key: "{{ sandbox_openshift_api_key }}" + validate_certs: false + block: + - name: Create Instances + loop: "{{ instances|default([]) }}" + loop_control: + loop_var: _instance + ansible.builtin.include_tasks: create_instance.yaml -- name: Create services for the nodes - ansible.builtin.include_tasks: create_services.yaml - loop: "{{ instances|default([]) }}" - loop_control: - loop_var: _instance + - name: Create services for the nodes + ansible.builtin.include_tasks: create_services.yaml + loop: "{{ instances|default([]) }}" + loop_control: + loop_var: _instance -- name: Create routes for the nodes - ansible.builtin.include_tasks: create_routes.yaml - loop: "{{ instances|default([]) }}" - loop_control: - loop_var: _instance + - name: Create routes for the nodes + ansible.builtin.include_tasks: create_routes.yaml + loop: "{{ instances|default([]) }}" + loop_control: + loop_var: _instance From 9eac4dff5461100ae55f18762a4b84515f4d2198 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 08:11:40 +0100 Subject: [PATCH 06/14] First try for cnv_instances --- roles/cnv_instances/tasks/create_instance.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/roles/cnv_instances/tasks/create_instance.yaml b/roles/cnv_instances/tasks/create_instance.yaml index 8decb2a..fc69637 100644 --- a/roles/cnv_instances/tasks/create_instance.yaml +++ b/roles/cnv_instances/tasks/create_instance.yaml @@ -190,8 +190,7 @@ name: "{{ _instance_name }}" namespace: "{{ openshift_cnv_namespace }}" annotations: >- - {{ cloud_tags_final - | combine(_instance.metadata|default({})) | combine(_instance.tags|default({}) | ec2_tags_to_dict) }} + {{ _instance.metadata|default({}) | combine(_instance.tags|default({})) | default({}) }} spec: dataVolumeTemplates: >- {{ _datavolume | from_yaml + (_instance.disks | default([]) | to_json | replace('INSTANCENAME',_instance_name) | from_json) + (_instance.cdroms | default([]) | to_json | replace('INSTANCENAME',_instance_name) | from_json) }} From f86a6b945137992d203fd9173e63825d6b832b77 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 08:15:37 +0100 Subject: [PATCH 07/14] First try for cnv_instances --- roles/cnv_instances/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/cnv_instances/defaults/main.yml b/roles/cnv_instances/defaults/main.yml index e295051..f873cbd 100644 --- a/roles/cnv_instances/defaults/main.yml +++ b/roles/cnv_instances/defaults/main.yml @@ -13,7 +13,7 @@ cnv_instances: [] instances: "{{ cnv_instances }}" -openshift_cnv_namespace: "{{ sandbox_openshift_namespace }}" +openshift_cnv_namespace: "{{ sandbox_openshift_namespace.split('-')[0] }}" # Naming of instances openshift_cnv_instance_numeration: '%d' From cdc1084f4ab461c8de7379b5366a9e41591c5899 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 19 Dec 2025 08:17:32 +0100 Subject: [PATCH 08/14] First try for cnv_instances --- roles/cnv_instances/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/cnv_instances/defaults/main.yml b/roles/cnv_instances/defaults/main.yml index f873cbd..e295051 100644 --- a/roles/cnv_instances/defaults/main.yml +++ b/roles/cnv_instances/defaults/main.yml @@ -13,7 +13,7 @@ cnv_instances: [] instances: "{{ cnv_instances }}" -openshift_cnv_namespace: "{{ sandbox_openshift_namespace.split('-')[0] }}" +openshift_cnv_namespace: "{{ sandbox_openshift_namespace }}" # Naming of instances openshift_cnv_instance_numeration: '%d' From 008fea13d6ea39e188049af4a7ac4c239bd779a5 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Rodriguez Date: Thu, 25 Dec 2025 22:45:44 +0100 Subject: [PATCH 09/14] Update create_services.yaml --- roles/cnv_instances/tasks/create_services.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/cnv_instances/tasks/create_services.yaml b/roles/cnv_instances/tasks/create_services.yaml index 49405d6..d1558e3 100644 --- a/roles/cnv_instances/tasks/create_services.yaml +++ b/roles/cnv_instances/tasks/create_services.yaml @@ -8,7 +8,6 @@ name: "{{ _instance_name }}" namespace: "{{ openshift_cnv_namespace }}" spec: - clusterIP: None ports: - port: {{ _instance.servicePort | default(22) |int}} protocol: TCP From 2d2abb4feda7318b685a17f9cbe700699ef15ba1 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 28 Dec 2025 23:22:28 +0100 Subject: [PATCH 10/14] Add cnv_instances_passthrough_namespace --- roles/cnv_instances/tasks/create_service.yaml | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/roles/cnv_instances/tasks/create_service.yaml b/roles/cnv_instances/tasks/create_service.yaml index 7cdfc52..7f89b31 100644 --- a/roles/cnv_instances/tasks/create_service.yaml +++ b/roles/cnv_instances/tasks/create_service.yaml @@ -9,21 +9,54 @@ namespace: "{{ openshift_cnv_namespace }}" spec: "{{ spec | from_yaml }}" vars: - _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count|d(1)|int > 1 }}" spec: | ports: {{ service.ports }} selector: - vm.cnv.io/name: "{{ _instance_name }}" + vm.cnv.io/name: "{{ _instance.name }}" type: {{ service.type | default('ClusterIP') }} - loop: "{{ range(1, _instance.count|default(1)|int+1) | list }}" - loop_control: - index_var: _index register: r_service until: r_service is success retries: "{{ openshift_cnv_retries }}" delay: "{{ openshift_cnv_delay }}" +- name: Add passthrough service to the nested OCP cluster + when: cnv_instances_passthrough_namespace | default("") != "" + block: + - name: Add Service + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: "{{ service.name }}" + namespace: "{{ cnv_instances_passthrough_namespace }}" + spec: "{{ spec | from_yaml }}" + vars: + spec: | + ports: + {{ service.ports }} + selector: + vm.cnv.io/name: "{{ _instance.name }}" + type: {{ service.type | default('ClusterIP') }} + - name: Add EndpointSlice + kubernetes.core.k8s: + definition: + apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: "{{ service.name }}" + namespace: "{{ cnv_instances_passthrough_namespace }}" + labels: + kubernetes.io/service-name: "{{ service.name }}" + addressType: IPv4 + endpoints: + - addresses: + - "{{ r_service.resources[0].spec.clusterIP }}" + conditions: + ready: true + ports: "{{ service.ports }}" + - name: Wait for the LoadBalancer value register: svc_fip kubernetes.core.k8s_info: @@ -51,21 +84,16 @@ state: patched api_version: v1 kind: VirtualMachine - name: "{{ _instance_name }}" + name: "{{ _instance.name }}" definition: apiVersion: v1 kind: VirtualMachine metadata: - name: "{{ _instance_name }}" + name: "{{ _instance.name }}" namespace: "{{ openshift_cnv_namespace }}" annotations: external_ip: "{{ _instance_external_ip }}" external_ports: "{{ _instance_external_ports }}" - vars: - _instance_name: "{{ _instance.name }}{{ _index+1 if _instance.count|d(1)|int > 1 }}" - loop: "{{ range(1, _instance.count|default(1)|int+1) | list }}" - loop_control: - index_var: _index register: r_service until: r_service is success retries: "{{ openshift_cnv_retries }}" From 0cebc1d7bd3abdb9624ec9d020717dae2d4f6fa8 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 28 Dec 2025 23:24:26 +0100 Subject: [PATCH 11/14] Add cnv_instances_passthrough_namespace --- roles/cnv_instances/tasks/create_service.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/roles/cnv_instances/tasks/create_service.yaml b/roles/cnv_instances/tasks/create_service.yaml index 7f89b31..08b0ab9 100644 --- a/roles/cnv_instances/tasks/create_service.yaml +++ b/roles/cnv_instances/tasks/create_service.yaml @@ -22,6 +22,11 @@ - name: Add passthrough service to the nested OCP cluster when: cnv_instances_passthrough_namespace | default("") != "" + module_defaults: + group/k8s: + host: "{{ openshift_api_url }}" + api_key: "{{ openshift_cluster_admin_token }}" + validate_certs: false block: - name: Add Service kubernetes.core.k8s: From c1fcde699683b16b56d8c79af00005f05b5bac77 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 28 Dec 2025 23:26:38 +0100 Subject: [PATCH 12/14] Add cnv_instances_passthrough_namespace --- roles/cnv_instances/tasks/create_service.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/cnv_instances/tasks/create_service.yaml b/roles/cnv_instances/tasks/create_service.yaml index 08b0ab9..abb6454 100644 --- a/roles/cnv_instances/tasks/create_service.yaml +++ b/roles/cnv_instances/tasks/create_service.yaml @@ -57,7 +57,7 @@ addressType: IPv4 endpoints: - addresses: - - "{{ r_service.resources[0].spec.clusterIP }}" + - "{{ r_service.result.resources[0].spec.clusterIP }}" conditions: ready: true ports: "{{ service.ports }}" From f074fb88be9a9c1568db809c05165d9ccaa35242 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 28 Dec 2025 23:34:06 +0100 Subject: [PATCH 13/14] Add cnv_instances_passthrough_namespace --- roles/cnv_instances/tasks/create_service.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/cnv_instances/tasks/create_service.yaml b/roles/cnv_instances/tasks/create_service.yaml index abb6454..4d531ed 100644 --- a/roles/cnv_instances/tasks/create_service.yaml +++ b/roles/cnv_instances/tasks/create_service.yaml @@ -57,7 +57,7 @@ addressType: IPv4 endpoints: - addresses: - - "{{ r_service.result.resources[0].spec.clusterIP }}" + - "{{ r_service.result.spec.clusterIP }}" conditions: ready: true ports: "{{ service.ports }}" From 44d2ebf2e1df8d2afc48bee674725013aeab3db2 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 28 Dec 2025 23:39:31 +0100 Subject: [PATCH 14/14] Add cnv_instances_passthrough_namespace --- roles/cnv_instances/tasks/create_service.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/roles/cnv_instances/tasks/create_service.yaml b/roles/cnv_instances/tasks/create_service.yaml index 4d531ed..e3eca98 100644 --- a/roles/cnv_instances/tasks/create_service.yaml +++ b/roles/cnv_instances/tasks/create_service.yaml @@ -41,8 +41,6 @@ spec: | ports: {{ service.ports }} - selector: - vm.cnv.io/name: "{{ _instance.name }}" type: {{ service.type | default('ClusterIP') }} - name: Add EndpointSlice kubernetes.core.k8s: @@ -52,8 +50,8 @@ metadata: name: "{{ service.name }}" namespace: "{{ cnv_instances_passthrough_namespace }}" - labels: - kubernetes.io/service-name: "{{ service.name }}" + labels: + kubernetes.io/service-name: "{{ service.name }}" addressType: IPv4 endpoints: - addresses: