Automating O2 compliance testing and sample workload deployment for OKD O-Cloud 77/14377/7
authorChris Wheeler <chwheele@redhat.com>
Tue, 6 May 2025 23:36:09 +0000 (23:36 +0000)
committerChris Wheeler <chwheele@redhat.com>
Wed, 11 Jun 2025 23:17:33 +0000 (23:17 +0000)
- Added ocloud_compliance.yml and ocloud_workload.yml playbooks/roles
- Added ocloud_token role to obtain an O2 access token
- Added ocloud_dms role to retrieve deployment manager and generate
  kubeconfig

Issue-ID: INF-494
Change-Id: Ib8c13b6324928665720dfd244c39e36a16833bcf
Signed-Off-By: Chris Wheeler <chwheele@redhat.com>
16 files changed:
okd/playbooks/ocloud_compliance.yml [new file with mode: 0644]
okd/playbooks/ocloud_workload.yml [new file with mode: 0644]
okd/roles/ocloud_compliance/defaults/main.yml [new file with mode: 0644]
okd/roles/ocloud_compliance/meta/main.yml [new file with mode: 0644]
okd/roles/ocloud_compliance/tasks/main.yml [new file with mode: 0644]
okd/roles/ocloud_compliance/templates/test_configs.yaml.j2 [new file with mode: 0644]
okd/roles/ocloud_dms/defaults/main.yml [new file with mode: 0644]
okd/roles/ocloud_dms/meta/main.yml [new file with mode: 0644]
okd/roles/ocloud_dms/tasks/main.yml [new file with mode: 0644]
okd/roles/ocloud_dms/templates/kubeconfig.j2 [new file with mode: 0644]
okd/roles/ocloud_token/defaults/main.yml [new file with mode: 0644]
okd/roles/ocloud_token/tasks/main.yml [new file with mode: 0644]
okd/roles/ocloud_workload/meta/main.yml [new file with mode: 0644]
okd/roles/ocloud_workload/tasks/main.yml [new file with mode: 0644]
okd/roles/ocloud_workload_oaicucp/defaults/main.yml [new file with mode: 0644]
okd/roles/ocloud_workload_oaicucp/tasks/main.yml [new file with mode: 0644]

diff --git a/okd/playbooks/ocloud_compliance.yml b/okd/playbooks/ocloud_compliance.yml
new file mode 100644 (file)
index 0000000..2b3dd72
--- /dev/null
@@ -0,0 +1,18 @@
+---
+- name: Execute O2 compliance tests
+  hosts: deployer
+  gather_facts: true
+  pre_tasks:
+    - ansible.builtin.fail:
+        msg: "ocloud_kubeconfig must be set to the path of the kubeconfig for the cluster hosting the O2 API server"
+      when: ocloud_kubeconfig is undefined or not ocloud_kubeconfig
+
+    - ansible.builtin.fail:
+        msg: "ocloud_compliance_resource_type must be set to the name of a resource type associated with the target O-Cloud"
+      when: ocloud_compliance_resource_type is undefined or not ocloud_compliance_resource_type
+
+    - ansible.builtin.fail:
+        msg: "ocloud_compliance_resource_desc_substring must be set to a substring of a resource description associated with the target O-Cloud"
+      when: ocloud_compliance_resource_desc_substring is undefined or not ocloud_compliance_resource_desc_substring
+  roles:
+    - ocloud_compliance
diff --git a/okd/playbooks/ocloud_workload.yml b/okd/playbooks/ocloud_workload.yml
new file mode 100644 (file)
index 0000000..146e57d
--- /dev/null
@@ -0,0 +1,22 @@
+---
+- name: Deploy sample workload(s) via O2 DMS interface
+  hosts: deployer
+  gather_facts: true
+  pre_tasks:
+    - ansible.builtin.fail:
+        msg: "ocloud_workloads must be set to a comma-delimited list of workloads to deploy"
+      when: ocloud_workloads is undefined or not ocloud_workloads
+
+    - ansible.builtin.fail:
+        msg: "ocloud_dms_host must be set to the hostname of the O2 API server providing the DMS interface"
+      when: ocloud_dms_host is undefined or not ocloud_dms_host
+
+    - ansible.builtin.fail:
+        msg: "ocloud_dms_deployment_mgr_id must be set to the deployment manager ID where the sample workload(s) will be deployed"
+      when: ocloud_dms_deployment_mgr_id is undefined or not ocloud_dms_deployment_mgr_id
+
+    - ansible.builtin.fail:
+        msg: "ocloud_kubeconfig must be set to the path of the kubeconfig for the cluster hosting the O2 API server"
+      when: ocloud_kubeconfig is undefined or not ocloud_kubeconfig
+  roles:
+    - ocloud_workload
diff --git a/okd/roles/ocloud_compliance/defaults/main.yml b/okd/roles/ocloud_compliance/defaults/main.yml
new file mode 100644 (file)
index 0000000..768de90
--- /dev/null
@@ -0,0 +1,16 @@
+---
+ocloud_compliance_deployment_manager: ~
+ocloud_compliance_repo: "https://gerrit.o-ran-sc.org/r/it/test.git"
+ocloud_compliance_o2ims_port: 443
+ocloud_compliance_o2ims_protocol: https
+ocloud_compliance_ocloud_id: ~
+ocloud_compliance_location_id: ~
+ocloud_compliance_resource_type: ~
+ocloud_compliance_resource_desc_substring: ~
+ocloud_compliance_ssh_host: localhost
+ocloud_compliance_ssh_port: 22
+ocloud_compliance_ssh_user: robot
+ocloud_compliance_ssh_password: robot
+ocloud_compliance_smo_host: "{{ ansible_default_ipv4['address'] }}"
+ocloud_compliance_smo_port: 1080
+ocloud_compliance_smo_protocol: https
diff --git a/okd/roles/ocloud_compliance/meta/main.yml b/okd/roles/ocloud_compliance/meta/main.yml
new file mode 100644 (file)
index 0000000..abe8a49
--- /dev/null
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - role: ocloud_token
diff --git a/okd/roles/ocloud_compliance/tasks/main.yml b/okd/roles/ocloud_compliance/tasks/main.yml
new file mode 100644 (file)
index 0000000..95d530a
--- /dev/null
@@ -0,0 +1,118 @@
+---
+- name: Create staging dir for O-Cloud compliance testing
+  ansible.builtin.tempfile:
+    path: "{{ lookup('env', 'HOME') }}"
+    prefix: "ocloud_compliance.{{ ansible_date_time['date'] }}."
+    state: directory
+  register: ocloud_compliance_staging_dir
+
+- name: Clone it/test repo
+  ansible.builtin.git:
+    repo: "{{ ocloud_compliance_repo }}"
+    dest: "{{ ocloud_compliance_staging_dir['path'] }}/git"
+
+- name: Install pip requirements
+  ansible.builtin.pip:
+    name:
+      - robotframework
+      - RESTinstance
+      - robotframework-sshlibrary
+    virtualenv: "{{ ocloud_compliance_staging_dir['path'] }}/venv"
+
+- name: Create SSH user
+  become: true
+  ansible.builtin.user:
+    name: "{{ ocloud_compliance_ssh_user }}"
+    state: present
+    password: "{{ ocloud_compliance_ssh_password | password_hash('sha512', 'salt') }}"
+  delegate_to: "{{ ocloud_compliance_ssh_host }}"
+
+- name: Get oran-o2ims Inventory
+  kubernetes.core.k8s_info:
+    name: default
+    api_version: o2ims.oran.openshift.io/v1alpha1
+    kind: Inventory
+    namespace: oran-o2ims
+    kubeconfig: "{{ ocloud_kubeconfig }}"
+  register: o2ims_inventory
+
+- set_fact:
+    ocloud_compliance_o2ims_host: "{{ o2ims_inventory['resources'][0]['status']['ingressHost'] }}"
+
+- name: Set ocloud_compliance_ocloud_id
+  block:
+  - name: Get O-Cloud
+    ansible.builtin.uri:
+      url: "https://{{ ocloud_compliance_o2ims_host }}/o2ims-infrastructureInventory/v1"
+      headers:
+        Authorization: "Bearer {{ ocloud_token }}"
+      validate_certs: false
+    register: o2ims_ocloud
+
+  - set_fact:
+      ocloud_compliance_ocloud_id: "{{ o2ims_ocloud['json']['globalCloudId'] }}"
+  when: not ocloud_compliance_ocloud_id
+
+- name: Set ocloud_compliance_location_id
+  block:
+  - name: Get O-Cloud resource pools
+    ansible.builtin.uri:
+      url: "https://{{ ocloud_compliance_o2ims_host }}/o2ims-infrastructureInventory/v1/resourcePools"
+      headers:
+        Authorization: "Bearer {{ ocloud_token }}"
+      validate_certs: false
+    register: o2ims_resource_pools
+
+  - set_fact:
+      ocloud_compliance_location_id: "{{ o2ims_resource_pools['json'][0]['globalLocationId'] }}"
+  when: not ocloud_compliance_location_id
+
+- name: Set ocloud_compliance_deployment_manager
+  block:
+  - name: Get O-Cloud deployment managers
+    ansible.builtin.uri:
+      url: "https://{{ ocloud_compliance_o2ims_host }}/o2ims-infrastructureInventory/v1/deploymentManagers"
+      headers:
+        Authorization: "Bearer {{ ocloud_token }}"
+      validate_certs: false
+    register: o2ims_deployment_managers
+
+  - set_fact:
+      ocloud_compliance_deployment_manager: "{{ o2ims_deployment_managers['json'][0]['name'] }}"
+  when: not ocloud_compliance_deployment_manager
+
+- name: Run mock SMO container
+  containers.podman.podman_container:
+    name: "mocksmo"
+    image: mockserver/mockserver
+    publish:
+      - "{{ ocloud_compliance_smo_port }}:{{ ocloud_compliance_smo_port }}"
+    state: started
+    rm: true
+  register: mock_smo_container
+
+- name: Wait for mock SMO container to start listening
+  ansible.builtin.wait_for:
+    host: "{{ ocloud_compliance_smo_host }}"
+    port: "{{ ocloud_compliance_smo_port }}"
+    delay: 5
+
+- name: Register mock server endpoints
+  ansible.builtin.shell:
+    cmd: "/bin/bash mock.sh {{ ocloud_compliance_smo_host }} {{ ocloud_compliance_smo_port }}"
+    chdir: "{{ ocloud_compliance_staging_dir['path'] }}/git/test_scripts/O2IMS_Compliance_Test"
+
+- name: Template test configuration
+  ansible.builtin.template:
+    src: "test_configs.yaml.j2"
+    dest: "{{ ocloud_compliance_staging_dir['path'] }}/git/test_scripts/O2IMS_Compliance_Test/test_configs.yaml"
+
+- name: Execute compliance tests
+  ansible.builtin.shell:
+    cmd: "{{ ocloud_compliance_staging_dir['path'] }}/venv/bin/robot -L debug -d {{ ocloud_compliance_staging_dir['path'] }}/reports ./o2ims_compliance"
+    chdir: "{{ ocloud_compliance_staging_dir['path'] }}/git/test_scripts/O2IMS_Compliance_Test"
+
+- name: Stop mock SMO container
+  containers.podman.podman_container:
+    name: "mocksmo"
+    state: stopped
diff --git a/okd/roles/ocloud_compliance/templates/test_configs.yaml.j2 b/okd/roles/ocloud_compliance/templates/test_configs.yaml.j2
new file mode 100644 (file)
index 0000000..6bb4a2a
--- /dev/null
@@ -0,0 +1,35 @@
+#olcoud ssh info
+ocloud:
+  ssh:
+    host: {{ ocloud_compliance_ssh_host }}
+    port: {{ ocloud_compliance_ssh_port }}
+    username: {{ ocloud_compliance_ssh_user }}
+    password: {{ ocloud_compliance_ssh_password }}
+    openrc: /etc/platform/openrc
+  #oran_o2_ims_info 
+  oran_o2_app:
+    g_location_id: {{ ocloud_compliance_location_id }}
+    g_ocloud_id: {{ ocloud_compliance_ocloud_id }}
+    smo_token_data: {{ ocloud_token }}
+    deploymentmanager_name: {{ ocloud_compliance_deployment_manager }}
+    resourcetype_name: {{ ocloud_compliance_resource_type }}
+    resource_description_substring: {{ ocloud_compliance_resource_desc_substring }}
+
+    api:
+      host: {{ ocloud_compliance_o2ims_host }}
+      node_port: {{ ocloud_compliance_o2ims_port }}
+      protocol: {{ ocloud_compliance_o2ims_protocol }}
+#smo mock server ip and callback endpoints
+smo:
+  service:
+    protocol: {{ ocloud_compliance_smo_protocol }}
+    host: {{ ocloud_compliance_smo_host }}
+    port: {{ ocloud_compliance_smo_port }}
+    verify_endpoint: /mockserver/verify
+  ocloud_observer:
+    path: /mock_smo/v1/ocloud_observer
+  o2ims_inventory_observer:
+    path: /mock_smo/v1/o2ims_inventory_observer
+  o2ims_alarm_observer:
+    path: /mock_smo/v1/o2ims_alarm_observer
+
diff --git a/okd/roles/ocloud_dms/defaults/main.yml b/okd/roles/ocloud_dms/defaults/main.yml
new file mode 100644 (file)
index 0000000..dac37b0
--- /dev/null
@@ -0,0 +1,4 @@
+---
+ocloud_dms_host: ~
+ocloud_dms_deployment_mgr_id: ~
+ocloud_dms_kubeconfig: "~/.kube/kubeconfig.{{ ocloud_dms_deployment_mgr_id }}"
diff --git a/okd/roles/ocloud_dms/meta/main.yml b/okd/roles/ocloud_dms/meta/main.yml
new file mode 100644 (file)
index 0000000..abe8a49
--- /dev/null
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - role: ocloud_token
diff --git a/okd/roles/ocloud_dms/tasks/main.yml b/okd/roles/ocloud_dms/tasks/main.yml
new file mode 100644 (file)
index 0000000..37aaca6
--- /dev/null
@@ -0,0 +1,14 @@
+---
+- name: Get deployment managers
+  ansible.builtin.uri:
+    url: "https://{{ ocloud_dms_host }}/o2ims-infrastructureInventory/v1/deploymentManagers/{{ ocloud_dms_deployment_mgr_id }}"
+    headers:
+      Authorization: "Bearer {{ ocloud_token }}"
+    validate_certs: false
+  register: o2_dms_deployment_mgr_profile
+
+- name: Template deployment manager kubeconfig
+  ansible.builtin.template:
+    src: "kubeconfig.j2"
+    dest: "{{ ocloud_dms_kubeconfig }}"
+    mode: "600"
diff --git a/okd/roles/ocloud_dms/templates/kubeconfig.j2 b/okd/roles/ocloud_dms/templates/kubeconfig.j2
new file mode 100644 (file)
index 0000000..f2487d9
--- /dev/null
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Config
+clusters:
+- cluster:
+    certificate-authority-data: {{ o2_dms_deployment_mgr_profile['json']['extensions']['profileData']['cluster_ca_cert'] }}
+    server: {{ o2_dms_deployment_mgr_profile['json']['extensions']['profileData']['cluster_api_endpoint'] }}
+  name: {{ o2_dms_deployment_mgr_profile['json']['name'] }}
+contexts:
+- context:
+    cluster: {{ o2_dms_deployment_mgr_profile['json']['name'] }}
+    user: admin
+  name: admin
+current-context: admin
+preferences: {}
+users:
+- name: admin
+  user:
+    client-certificate-data: |-
+      {{ o2_dms_deployment_mgr_profile['json']['extensions']['profileData']['admin_client_cert'] | indent(6) }}
+    client-key-data: |-
+      {{ o2_dms_deployment_mgr_profile['json']['extensions']['profileData']['admin_client_key']  | indent(6) }}
diff --git a/okd/roles/ocloud_token/defaults/main.yml b/okd/roles/ocloud_token/defaults/main.yml
new file mode 100644 (file)
index 0000000..64655f6
--- /dev/null
@@ -0,0 +1,2 @@
+---
+ocloud_kubeconfig: ~
diff --git a/okd/roles/ocloud_token/tasks/main.yml b/okd/roles/ocloud_token/tasks/main.yml
new file mode 100644 (file)
index 0000000..4281efb
--- /dev/null
@@ -0,0 +1,53 @@
+---
+- name: Create test-client service account
+  kubernetes.core.k8s:
+    name: test-client
+    api_version: v1
+    kind: ServiceAccount
+    namespace: oran-o2ims
+    state: present
+    kubeconfig: "{{ ocloud_kubeconfig }}"
+
+- name: Create test-client cluster role binding
+  kubernetes.core.k8s:
+    name: oran-o2ims-test-client-binding
+    api_version: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    namespace: oran-o2ims
+    resource_definition:
+      roleRef:
+        apiGroup: rbac.authorization.k8s.io
+        kind: ClusterRole
+        name: oran-o2ims-admin-role
+      subjects:
+        - kind: ServiceAccount
+          name: test-client
+          namespace: oran-o2ims
+    state: present
+    kubeconfig: "{{ ocloud_kubeconfig }}"
+
+- name: Create test-client token
+  kubernetes.core.k8s:
+    name: test-client-token
+    api_version: v1
+    kind: Secret
+    namespace: oran-o2ims
+    resource_definition:
+      metadata:
+        annotations:
+          kubernetes.io/service-account.name: test-client
+      type: kubernetes.io/service-account-token
+    state: present
+    kubeconfig: "{{ ocloud_kubeconfig }}"
+
+- name: get test-client token
+  kubernetes.core.k8s_info:
+    name: test-client-token
+    api_version: v1
+    kind: Secret
+    namespace: oran-o2ims
+    kubeconfig: "{{ ocloud_kubeconfig }}"
+  register: test_client_token
+
+- set_fact:
+    ocloud_token: "{{ test_client_token['resources'][0]['data']['token'] | b64decode }}"
diff --git a/okd/roles/ocloud_workload/meta/main.yml b/okd/roles/ocloud_workload/meta/main.yml
new file mode 100644 (file)
index 0000000..4bc0021
--- /dev/null
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - role: ocloud_dms
diff --git a/okd/roles/ocloud_workload/tasks/main.yml b/okd/roles/ocloud_workload/tasks/main.yml
new file mode 100644 (file)
index 0000000..1cdcaea
--- /dev/null
@@ -0,0 +1,8 @@
+---
+- set_fact:
+    ocloud_workloads_list: "{{ ocloud_workloads | split(',') }}"
+
+- name: Deploy workload - OAI CU-CP
+  ansible.builtin.import_role:
+    name: "ocloud_workload_oaicucp"
+  when: '"oaicucp" in ocloud_workloads_list'
diff --git a/okd/roles/ocloud_workload_oaicucp/defaults/main.yml b/okd/roles/ocloud_workload_oaicucp/defaults/main.yml
new file mode 100644 (file)
index 0000000..3850e20
--- /dev/null
@@ -0,0 +1,5 @@
+---
+ocloud_workload_oaicucp_repo_url: "https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git"
+ocloud_workload_oaicucp_repo_version: "master"
+ocloud_workload_oaicucp_namespace: "oai-cu-cp"
+ocloud_workload_oaicucp_helm_url: "https://get.helm.sh/helm-v3.18.2-linux-amd64.tar.gz"
diff --git a/okd/roles/ocloud_workload_oaicucp/tasks/main.yml b/okd/roles/ocloud_workload_oaicucp/tasks/main.yml
new file mode 100644 (file)
index 0000000..e7e8da5
--- /dev/null
@@ -0,0 +1,45 @@
+---
+- name: Create staging dir
+  ansible.builtin.tempfile:
+    path: "{{ lookup('env', 'HOME') }}"
+    prefix: "ocloud_workload_oaicucp.{{ ansible_date_time['date'] }}."
+    state: directory
+  register: ocloud_workload_oaicucp_staging_dir
+
+- name: Download Helm
+  ansible.builtin.get_url:
+    url: "{{ ocloud_workload_oaicucp_helm_url }}"
+    dest: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/helm-linux-amd64.tar.gz"
+
+- name: Create helm directory
+  ansible.builtin.file:
+    path: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/helm"
+    state: directory
+
+- name: Extract Helm
+  ansible.builtin.unarchive:
+    src: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/helm-linux-amd64.tar.gz"
+    dest: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/helm"
+    remote_src: true
+
+- name: Clone oai-cn5g-fed repo
+  ansible.builtin.git:
+    repo: "{{ ocloud_workload_oaicucp_repo_url }}"
+    version: "{{ ocloud_workload_oaicucp_repo_version }}"
+    dest: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/git/oai-cn5g-fed"
+    recursive: false
+
+- name: Deploy oai-cu-cp Helm chart
+  kubernetes.core.helm:
+    name: oai-cu-cp
+    chart_ref: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/git/oai-cn5g-fed/charts/oai-5g-ran/oai-cu-cp"
+    release_namespace: "{{ ocloud_workload_oaicucp_namespace }}"
+    create_namespace: true
+    values:
+      kubernetesDistribution: "Openshift"
+      nfimage:
+        repository: docker.io/oaisoftwarealliance/oai-gnb
+        version: 2025.w23
+    kubeconfig: "{{ ocloud_dms_kubeconfig }}"
+    binary_path: "{{ ocloud_workload_oaicucp_staging_dir['path'] }}/helm/linux-amd64/helm"
+    state: present