From: Chris Wheeler Date: Tue, 6 May 2025 23:36:09 +0000 (+0000) Subject: Automating O2 compliance testing and sample workload deployment for OKD O-Cloud X-Git-Tag: l-release~4^2 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=14bc113a8bdb3e4a51f190b44fe1c37d9b1f643f;p=pti%2Frtp.git Automating O2 compliance testing and sample workload deployment for OKD O-Cloud - 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 --- diff --git a/okd/playbooks/ocloud_compliance.yml b/okd/playbooks/ocloud_compliance.yml new file mode 100644 index 00000000..2b3dd72c --- /dev/null +++ b/okd/playbooks/ocloud_compliance.yml @@ -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 index 00000000..146e57df --- /dev/null +++ b/okd/playbooks/ocloud_workload.yml @@ -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 index 00000000..768de90c --- /dev/null +++ b/okd/roles/ocloud_compliance/defaults/main.yml @@ -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 index 00000000..abe8a499 --- /dev/null +++ b/okd/roles/ocloud_compliance/meta/main.yml @@ -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 index 00000000..95d530a3 --- /dev/null +++ b/okd/roles/ocloud_compliance/tasks/main.yml @@ -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 index 00000000..6bb4a2a7 --- /dev/null +++ b/okd/roles/ocloud_compliance/templates/test_configs.yaml.j2 @@ -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 index 00000000..dac37b03 --- /dev/null +++ b/okd/roles/ocloud_dms/defaults/main.yml @@ -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 index 00000000..abe8a499 --- /dev/null +++ b/okd/roles/ocloud_dms/meta/main.yml @@ -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 index 00000000..37aaca65 --- /dev/null +++ b/okd/roles/ocloud_dms/tasks/main.yml @@ -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 index 00000000..f2487d95 --- /dev/null +++ b/okd/roles/ocloud_dms/templates/kubeconfig.j2 @@ -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 index 00000000..64655f6a --- /dev/null +++ b/okd/roles/ocloud_token/defaults/main.yml @@ -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 index 00000000..4281efb6 --- /dev/null +++ b/okd/roles/ocloud_token/tasks/main.yml @@ -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 index 00000000..4bc00217 --- /dev/null +++ b/okd/roles/ocloud_workload/meta/main.yml @@ -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 index 00000000..1cdcaea9 --- /dev/null +++ b/okd/roles/ocloud_workload/tasks/main.yml @@ -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 index 00000000..3850e203 --- /dev/null +++ b/okd/roles/ocloud_workload_oaicucp/defaults/main.yml @@ -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 index 00000000..e7e8da59 --- /dev/null +++ b/okd/roles/ocloud_workload_oaicucp/tasks/main.yml @@ -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