diff --git a/.ansible-lint b/.ansible-lint index 8ffdeaeb1..4bcb5cd12 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -18,6 +18,7 @@ exclude_paths: - roles/ci_gen_kustomize_values/molecule/default/converge.yml # invalid due to calls to "lookup('file')" - roles/ci_gen_kustomize_values/molecule/default/prepare.yml # import_playbook - roles/reproducer/files/cifmw-bootstrap.yml # invalid due to calls to "lookup('file')" + - roles/rally/files/ # Rally task files, not Ansible YAML - roles/kustomize_deploy/molecule/flexible_loop/files/networking-environment-definition.yml # Generated - roles/kustomize_deploy/molecule/flexible_loop/prepare.yml # import_playbook - roles/*/molecule/*/side_effect.yml # syntax-check[empty-playbook] https://github.com/ansible/molecule/issues/3617 diff --git a/docs/dictionary/en-custom.txt b/docs/dictionary/en-custom.txt index 0d8732d56..cd4d708f5 100644 --- a/docs/dictionary/en-custom.txt +++ b/docs/dictionary/en-custom.txt @@ -77,6 +77,7 @@ baseimg baseurl bashrc bd +benchmarking bgp blockquote bmaas @@ -326,6 +327,7 @@ kerberos keycloak keypair keyring +keystoneapi keystoneauth keystoneauth1 keytab diff --git a/hooks/playbooks/rally_cinder_prerequisites.yaml b/hooks/playbooks/rally_cinder_prerequisites.yaml new file mode 100644 index 000000000..7b3b0083f --- /dev/null +++ b/hooks/playbooks/rally_cinder_prerequisites.yaml @@ -0,0 +1,56 @@ +--- +- name: Ensure Cinder Rally prerequisites exist + hosts: "{{ cifmw_target_hook_host | default('localhost') }}" + gather_facts: false + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + tasks: + - name: Create m1.tiny flavor if missing + ansible.builtin.shell: | + set -xe -o pipefail + oc -n {{ namespace }} rsh openstackclient \ + openstack flavor show m1.tiny &>/dev/null || \ + oc -n {{ namespace }} rsh openstackclient \ + openstack flavor create m1.tiny \ + --ram 512 --disk 1 --vcpus 1 --public + + - name: Create lvmdriver-1 volume type if missing + ansible.builtin.shell: | + set -xe -o pipefail + oc -n {{ namespace }} rsh openstackclient \ + openstack volume type show lvmdriver-1 &>/dev/null || \ + oc -n {{ namespace }} rsh openstackclient \ + openstack volume type create lvmdriver-1 --public + + - name: Check if cirros image already exists + ansible.builtin.shell: | + set -e -o pipefail + oc -n {{ namespace }} rsh openstackclient \ + openstack image list -f value -c Name | grep -q '^cirros' + register: _cirros_image_exists + failed_when: false + + - name: Download cirros image to hypervisor + when: _cirros_image_exists.rc != 0 + ansible.builtin.get_url: + url: "https://github.com/cirros-dev/cirros/releases/download/0.6.2/cirros-0.6.2-x86_64-disk.img" + dest: "/tmp/cirros-0.6.2-x86_64-disk.img" + mode: "0644" + + - name: Copy cirros image to openstackclient pod + when: _cirros_image_exists.rc != 0 + ansible.builtin.command: >- + oc cp /tmp/cirros-0.6.2-x86_64-disk.img + {{ namespace }}/openstackclient:/home/cloud-admin/cirros-0.6.2-x86_64-disk.img + + - name: Upload cirros image for Rally if missing + when: _cirros_image_exists.rc != 0 + ansible.builtin.shell: | + set -xe -o pipefail + oc -n {{ namespace }} rsh openstackclient \ + openstack image create cirros-0.6.2-x86_64-disk \ + --disk-format qcow2 \ + --container-format bare \ + --file /home/cloud-admin/cirros-0.6.2-x86_64-disk.img \ + --public diff --git a/hooks/playbooks/rally_manila_prerequisites.yaml b/hooks/playbooks/rally_manila_prerequisites.yaml new file mode 100644 index 000000000..c2d847410 --- /dev/null +++ b/hooks/playbooks/rally_manila_prerequisites.yaml @@ -0,0 +1,15 @@ +--- +- name: Ensure Manila Rally prerequisites exist + hosts: "{{ cifmw_target_hook_host | default('localhost') }}" + gather_facts: false + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + tasks: + - name: Create dhss_true share type if missing + ansible.builtin.shell: | + set -xe -o pipefail + oc -n {{ namespace }} rsh openstackclient \ + openstack share type show dhss_true &>/dev/null || \ + oc -n {{ namespace }} rsh openstackclient \ + openstack share type create dhss_true False diff --git a/hooks/playbooks/rally_run.yaml b/hooks/playbooks/rally_run.yaml new file mode 100644 index 000000000..b3b39a36b --- /dev/null +++ b/hooks/playbooks/rally_run.yaml @@ -0,0 +1,11 @@ +--- +- name: Run Rally benchmarks + hosts: "{{ cifmw_target_hook_host | default('localhost') }}" + gather_facts: false + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + tasks: + - name: Run rally role + ansible.builtin.include_role: + name: rally diff --git a/roles/rally/OWNERS b/roles/rally/OWNERS new file mode 100644 index 000000000..b7883e567 --- /dev/null +++ b/roles/rally/OWNERS @@ -0,0 +1,7 @@ +# See the OWNERS docs at https://www.kubernetes.dev/docs/guide/owners/ + +approvers: + - ciops-team + +reviewers: + - ciops-team diff --git a/roles/rally/README.md b/roles/rally/README.md new file mode 100644 index 000000000..8e22e08b4 --- /dev/null +++ b/roles/rally/README.md @@ -0,0 +1,81 @@ +# rally +Role to setup and run Rally benchmarking tests against an OpenStack deployment. + +Rally is run inside the `quay.io/airshipit/xrally-openstack` container via podman. +OpenStack credentials are discovered automatically from the Kubernetes KeystoneAPI resource, +or can be supplied directly via `cifmw_rally_os_*` variables. + +## Prerequisites +- `oc` CLI available and pointing to the target OpenStack cluster (used for credential and CA discovery). +- `cifmw_openstack_namespace` must be set to the OpenStack namespace (typically `openstack`). + +## Privilege escalation +become - Required to install podman and fix artifact directory ownership after the container run. + +## Parameters + +* `cifmw_rally_artifacts_basedir`: (String) Directory where all Rally artifacts are stored. + Default: `{{ cifmw_basedir }}/tests/rally` +* `cifmw_rally_registry`: (String) Container registry. Default: `quay.io` +* `cifmw_rally_namespace`: (String) Registry namespace. Default: `airshipit` +* `cifmw_rally_container`: (String) Container image name. Default: `xrally-openstack` +* `cifmw_rally_image`: (String) Full image reference. Composed from registry/namespace/container. +* `cifmw_rally_image_tag`: (String) Container image tag. Default: `3.0.0` +* `cifmw_rally_dry_run`: (Boolean) Skip actual container execution. Default: `false` +* `cifmw_rally_remove_container`: (Boolean) Remove container after run. Default: `true` +* `cifmw_rally_fail_on_task_failure`: (Boolean) Fail the play if Rally exits non-zero. Default: `true` +* `cifmw_rally_deployment_name`: (String) Rally deployment name. Default: `cifmw` +* `cifmw_rally_concurrency`: (Integer) Concurrency passed to the Rally task via `--task-args`. Default: `1` +* `cifmw_rally_task_file`: (String) Absolute path to a custom Rally task YAML on the host. + Mutually exclusive with `cifmw_rally_openstack_tests`. Default: `""` +* `cifmw_rally_task_extra_args`: (String) Extra arguments passed verbatim to `rally task start`. Default: `""` +* `cifmw_rally_dns_servers`: (List) DNS servers used inside the Rally container. Default: `["192.168.122.10"]` +* `cifmw_rally_os_auth_url`: (String) OpenStack auth URL. Auto-discovered from KeystoneAPI if unset. +* `cifmw_rally_os_username`: (String) OpenStack username. Default: `admin` +* `cifmw_rally_os_password`: (String) OpenStack password. Auto-discovered from Kubernetes secret if unset. +* `cifmw_rally_os_project_name`: (String) OpenStack project. Default: `admin` +* `cifmw_rally_os_user_domain_name`: (String) User domain. Default: `Default` +* `cifmw_rally_os_project_domain_name`: (String) Project domain. Default: `Default` +* `cifmw_rally_os_region_name`: (String) OpenStack region. Default: `regionOne` +* `cifmw_rally_runs`: (List) List of run definitions for sequential multi-run mode. + When empty (default), the role runs once using the top-level `cifmw_rally_*` variables. + When non-empty, the role loops over the list; each entry may override any `cifmw_rally_*` + variable for that run and **must** include a `name` key used to namespace artifacts. + Default: `[]` + +## Standalone usage (single run) + +```yaml +- hosts: hypervisor + roles: + - role: rally + vars: + cifmw_rally_openstack_tests: "cinder" + cifmw_rally_concurrency: 2 + cifmw_rally_fail_on_task_failure: false +``` + +## Usage via hook (multiple runs) + +Add a `post_tests_*` hook in your job vars and define `cifmw_rally_runs`: + +```yaml +post_tests_90_rally_run: + type: playbook + source: rally_run.yaml +cifmw_rally_runs: + - name: cinder + cifmw_rally_openstack_tests: "cinder" + cifmw_rally_concurrency: 1 + - name: nova + cifmw_rally_openstack_tests: "nova" + cifmw_rally_concurrency: 2 + cifmw_rally_fail_on_task_failure: false +``` + +Each run stores its artifacts under `cifmw_rally_artifacts_basedir//`. + +## Custom task files + +To use a custom Rally task file, set `cifmw_rally_task_file` to the absolute path of the +YAML on the hypervisor host (pre-stage it via an earlier hook if needed). diff --git a/roles/rally/defaults/main.yml b/roles/rally/defaults/main.yml new file mode 100644 index 000000000..eeba69fb5 --- /dev/null +++ b/roles/rally/defaults/main.yml @@ -0,0 +1,36 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +# All variables intended for modification should be placed in this file. +# All variables within this role should have a prefix of "cifmw_rally" +cifmw_rally_artifacts_basedir: "{{ cifmw_basedir }}/tests/rally" +cifmw_rally_registry: "quay.io" +cifmw_rally_namespace: "airshipit" +cifmw_rally_container: "xrally-openstack" +cifmw_rally_image: "{{ cifmw_rally_registry }}/{{ cifmw_rally_namespace }}/{{ cifmw_rally_container }}" +cifmw_rally_image_tag: "3.0.0" +cifmw_rally_dry_run: false +cifmw_rally_remove_container: true +cifmw_rally_fail_on_task_failure: true +cifmw_rally_deployment_name: "cifmw" +cifmw_rally_concurrency: 1 +cifmw_rally_task_file: "" +cifmw_rally_openstack_tests: "" +cifmw_rally_task_extra_args: "" +cifmw_rally_dns_servers: + - "192.168.122.10" +cifmw_rally_runs: [] diff --git a/roles/rally/meta/main.yml b/roles/rally/meta/main.yml new file mode 100644 index 000000000..0891072bf --- /dev/null +++ b/roles/rally/meta/main.yml @@ -0,0 +1,29 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +galaxy_info: + author: CI Framework + description: CI Framework Role -- rally + company: Red Hat + license: Apache-2.0 + min_ansible_version: "2.14" + namespace: cifmw + galaxy_tags: + - cifmw + - rally + +dependencies: [] diff --git a/roles/rally/molecule/default/converge.yml b/roles/rally/molecule/default/converge.yml new file mode 100644 index 000000000..cc07f8c22 --- /dev/null +++ b/roles/rally/molecule/default/converge.yml @@ -0,0 +1,24 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +- name: Converge + hosts: all + vars: + cifmw_rally_dry_run: true + cifmw_rally_openstack_tests: "cinder" + roles: + - role: "rally" diff --git a/roles/rally/molecule/default/molecule.yml b/roles/rally/molecule/default/molecule.yml new file mode 100644 index 000000000..8162360ec --- /dev/null +++ b/roles/rally/molecule/default/molecule.yml @@ -0,0 +1,9 @@ +--- +# Mainly used to override the defaults set in .config/molecule/ +# By default, it uses the "config_podman.yml" - in CI, it will use +# "config_local.yml". +log: true + +provisioner: + name: ansible + log: true diff --git a/roles/rally/molecule/default/prepare.yml b/roles/rally/molecule/default/prepare.yml new file mode 100644 index 000000000..0c6d52693 --- /dev/null +++ b/roles/rally/molecule/default/prepare.yml @@ -0,0 +1,28 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +- name: Prepare + hosts: all + vars: + cifmw_basedir: "{{ ansible_user_dir }}/ci-framework-data" + cifmw_install_yamls_tasks_out: "{{ ansible_user_dir }}/zuul-jobs/roles/install_yamls_makes/tasks" + cifmw_install_yamls_defaults: + NAMESPACE: openstack + roles: + - role: test_deps + - role: ci_setup + - role: install_yamls diff --git a/roles/rally/tasks/create-deployment.yml b/roles/rally/tasks/create-deployment.yml new file mode 100644 index 000000000..5db4d2930 --- /dev/null +++ b/roles/rally/tasks/create-deployment.yml @@ -0,0 +1,55 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Discover credentials from Kubernetes when not overridden + when: cifmw_rally_os_auth_url is not defined + block: + - name: Get keystone data + register: _cifmw_rally_keystone_data + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + ansible.builtin.command: + cmd: "oc get keystoneapi keystone -n {{ cifmw_openstack_namespace }} -o json" + + - name: Set keystone vars + vars: + _keystone_json: "{{ _cifmw_rally_keystone_data.stdout | from_json }}" + ansible.builtin.set_fact: + _cifmw_rally_keystone_secret_name: "{{ _keystone_json['spec']['secret'] }}" + _cifmw_rally_keystone_passwd_select: "{{ _keystone_json['spec']['passwordSelectors']['admin'] }}" + _cifmw_rally_keystone_api: "{{ _keystone_json['status']['apiEndpoints']['public'] }}" + + - name: Get credentials data + register: _cifmw_rally_os_password_data + environment: + KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" + PATH: "{{ cifmw_path }}" + ansible.builtin.command: + cmd: >- + oc get secret {{ _cifmw_rally_keystone_secret_name }} + -n {{ cifmw_openstack_namespace }} -o json + + - name: Set OpenStack credentials facts + vars: + _pw_json: "{{ _cifmw_rally_os_password_data.stdout | from_json }}" + ansible.builtin.set_fact: + cifmw_rally_os_auth_url: "{{ _cifmw_rally_keystone_api }}" + cifmw_rally_os_password: >- + {{ + _pw_json['data'][_cifmw_rally_keystone_passwd_select] | + ansible.builtin.b64decode + }} diff --git a/roles/rally/tasks/main.yml b/roles/rally/tasks/main.yml new file mode 100644 index 000000000..ea243cc04 --- /dev/null +++ b/roles/rally/tasks/main.yml @@ -0,0 +1,64 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Ensure podman is installed + become: true + ansible.builtin.package: + name: podman + state: present + +- name: Create rally base artifacts directory + ansible.builtin.file: + path: "{{ cifmw_rally_artifacts_basedir }}" + state: directory + mode: "0755" + +- name: Create rally deployment configuration + ansible.builtin.include_tasks: create-deployment.yml + when: not cifmw_rally_dry_run | bool + +- name: Get OpenStack public CA secret + ansible.builtin.command: + cmd: >- + oc get secret rootca-public + -n {{ cifmw_openstack_namespace }} + -o json + register: _cifmw_rally_rootca_secret + failed_when: false + when: not cifmw_rally_dry_run | bool + +- name: Ensure we have rally container image + register: _cifmw_rally_fetch_img + containers.podman.podman_image: + name: "{{ cifmw_rally_image }}:{{ cifmw_rally_image_tag }}" + retries: 5 + delay: 5 + until: _cifmw_rally_fetch_img is success + +- name: Run rally (single run) + when: cifmw_rally_runs | length == 0 + ansible.builtin.include_tasks: run_once.yml + vars: + _cifmw_rally_run_name: "" + _cifmw_rally_run_vars: {} + +- name: Run rally (multiple runs) + when: cifmw_rally_runs | length > 0 + ansible.builtin.include_tasks: run_once.yml + vars: + _cifmw_rally_run_name: "{{ item.name }}" + _cifmw_rally_run_vars: "{{ item }}" + loop: "{{ cifmw_rally_runs }}" diff --git a/roles/rally/tasks/run_once.yml b/roles/rally/tasks/run_once.yml new file mode 100644 index 000000000..791733adf --- /dev/null +++ b/roles/rally/tasks/run_once.yml @@ -0,0 +1,171 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Set effective variables for this run + ansible.builtin.set_fact: + _cifmw_rally_effective_basedir: >- + {{ (cifmw_rally_artifacts_basedir ~ '/' ~ _cifmw_rally_run_name) + if _cifmw_rally_run_name | length > 0 + else cifmw_rally_artifacts_basedir }} + _cifmw_rally_effective_openstack_tests: >- + {{ _cifmw_rally_run_vars.cifmw_rally_openstack_tests + | default(cifmw_rally_openstack_tests) }} + _cifmw_rally_effective_task_file: >- + {{ _cifmw_rally_run_vars.cifmw_rally_task_file + | default(cifmw_rally_task_file) }} + _cifmw_rally_effective_concurrency: >- + {{ _cifmw_rally_run_vars.cifmw_rally_concurrency + | default(cifmw_rally_concurrency) }} + _cifmw_rally_effective_fail_on_task_failure: >- + {{ _cifmw_rally_run_vars.cifmw_rally_fail_on_task_failure + | default(cifmw_rally_fail_on_task_failure) }} + _cifmw_rally_effective_task_extra_args: >- + {{ _cifmw_rally_run_vars.cifmw_rally_task_extra_args + | default(cifmw_rally_task_extra_args) }} + _cifmw_rally_effective_container_name: >- + {{ 'rally-' ~ _cifmw_rally_run_name + if _cifmw_rally_run_name | length > 0 + else 'rally' }} + +- name: Assert that a workload source is specified for this run + ansible.builtin.assert: + that: + - >- + _cifmw_rally_effective_task_file | length > 0 or + _cifmw_rally_effective_openstack_tests | length > 0 + fail_msg: >- + Either cifmw_rally_task_file (absolute path to a custom YAML on the host) + or cifmw_rally_openstack_tests (name of a bundled workload, e.g. 'cinder', + 'nova') must be set for run + '{{ _cifmw_rally_run_name | default("default") }}'. + +- name: Create per-run directories + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + mode: "{{ item.mode }}" + loop: + - {path: "{{ _cifmw_rally_effective_basedir }}", mode: "0755"} + - {path: "{{ _cifmw_rally_effective_basedir }}/tasks", mode: "0755"} + - {path: "{{ _cifmw_rally_effective_basedir }}/reports", mode: "0777"} + +- name: Copy custom task file to run tasks directory + when: _cifmw_rally_effective_task_file | length > 0 + ansible.builtin.copy: + src: "{{ _cifmw_rally_effective_task_file }}" + dest: >- + {{ _cifmw_rally_effective_basedir }}/tasks/{{ + _cifmw_rally_effective_task_file | basename }} + mode: "0644" + remote_src: true + +- name: Copy CA bundle to run artifacts directory + ansible.builtin.copy: + src: "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" + dest: "{{ _cifmw_rally_effective_basedir }}/tls-ca-bundle.pem" + mode: "0644" + owner: "{{ ansible_user | default(lookup('env', 'USER')) }}" + group: "{{ ansible_user | default(lookup('env', 'USER')) }}" + remote_src: true + force: true + when: not cifmw_rally_dry_run | bool + +- name: Append OpenStack public CA to tls-ca-bundle + when: + - not cifmw_rally_dry_run | bool + - _cifmw_rally_rootca_secret.rc is defined + - _cifmw_rally_rootca_secret.rc == 0 + vars: + _rootca_pem: >- + {{ (_cifmw_rally_rootca_secret.stdout | from_json).data['ca.crt'] | b64decode }} + ansible.builtin.shell: + cmd: >- + cat >> {{ _cifmw_rally_effective_basedir }}/tls-ca-bundle.pem + stdin: "{{ _rootca_pem }}" + +- name: Create rally run script + ansible.builtin.template: + src: rally-run.sh.j2 + dest: "{{ _cifmw_rally_effective_basedir }}/tasks/rally-run.sh" + mode: "0755" + vars: + cifmw_rally_task_file: "{{ _cifmw_rally_effective_task_file }}" + cifmw_rally_openstack_tests: "{{ _cifmw_rally_effective_openstack_tests }}" + cifmw_rally_concurrency: "{{ _cifmw_rally_effective_concurrency }}" + cifmw_rally_task_extra_args: "{{ _cifmw_rally_effective_task_extra_args }}" + when: not cifmw_rally_dry_run | bool + +- name: Run rally + ignore_errors: true + containers.podman.podman_container: + name: "{{ _cifmw_rally_effective_container_name }}" + image: "{{ cifmw_rally_image }}:{{ cifmw_rally_image_tag }}" + state: started + auto_remove: "{{ cifmw_rally_remove_container }}" + network: host + dns: "{{ cifmw_rally_dns_servers }}" + volume: + - "{{ _cifmw_rally_effective_basedir }}/tasks:{{ _cifmw_rally_container_tasks_dir }}:Z" + - "{{ _cifmw_rally_effective_basedir }}/reports:{{ _cifmw_rally_container_reports_dir }}:Z" + - "{{ _cifmw_rally_effective_basedir }}/tls-ca-bundle.pem:\ + /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:Z" + detach: false + entrypoint: "/bin/bash" + command: "{{ _cifmw_rally_container_tasks_dir }}/rally-run.sh" + env: + OS_AUTH_URL: "{{ cifmw_rally_os_auth_url | default('') }}" + OS_USERNAME: "{{ cifmw_rally_os_username | default('admin') }}" + OS_PASSWORD: "{{ cifmw_rally_os_password | default('') }}" + OS_PROJECT_NAME: "{{ cifmw_rally_os_project_name | default('admin') }}" + OS_USER_DOMAIN_NAME: "{{ cifmw_rally_os_user_domain_name | default('Default') }}" + OS_PROJECT_DOMAIN_NAME: "{{ cifmw_rally_os_project_domain_name | default('Default') }}" + OS_REGION_NAME: "{{ cifmw_rally_os_region_name | default('regionOne') }}" + OS_IDENTITY_API_VERSION: "3" + OS_CACERT: "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" + REQUESTS_CA_BUNDLE: "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" + when: not cifmw_rally_dry_run | bool + register: _cifmw_rally_run_output + +- name: Restore ownership of run artifacts directory + become: true + ansible.builtin.file: + path: "{{ _cifmw_rally_effective_basedir }}" + state: directory + recurse: true + owner: "{{ ansible_user | default(lookup('env', 'USER')) }}" + group: "{{ ansible_user | default(lookup('env', 'USER')) }}" + when: not cifmw_rally_dry_run | bool + +- name: Save logs from podman + when: not cifmw_rally_dry_run | bool + ansible.builtin.copy: + mode: "0644" + dest: "{{ _cifmw_rally_effective_basedir }}/podman_rally.log" + content: | + "{{ _cifmw_rally_run_output.stdout }}" + +- name: Fail if podman container did not succeed + when: + - not cifmw_rally_dry_run | bool + - _cifmw_rally_effective_fail_on_task_failure | bool + ansible.builtin.assert: + that: + - "_cifmw_rally_run_output.failed == false" + fail_msg: >- + Rally task execution failed for run + '{{ _cifmw_rally_run_name | default("default") }}'. + Check logs at {{ _cifmw_rally_effective_basedir }}/podman_rally.log + and reports at {{ _cifmw_rally_effective_basedir }}/reports/ diff --git a/roles/rally/templates/rally-run.sh.j2 b/roles/rally/templates/rally-run.sh.j2 new file mode 100644 index 000000000..0212893da --- /dev/null +++ b/roles/rally/templates/rally-run.sh.j2 @@ -0,0 +1,15 @@ +#!/bin/bash +set -e +rally db ensure +rally deployment create --fromenv --name {{ cifmw_rally_deployment_name }} +{% if cifmw_rally_task_file | length > 0 %} +rally task start {{ _cifmw_rally_container_tasks_dir }}/{{ cifmw_rally_task_file | basename }} \ +{% else %} +rally task start /rally/xrally_openstack/rally-jobs/{{ cifmw_rally_openstack_tests }}.yaml \ +{% endif %} + --task-args '{"concurrency": {{ cifmw_rally_concurrency }}}' \ + {{ cifmw_rally_task_extra_args }} || RALLY_TASK_RC=$? +rally task report --out {{ _cifmw_rally_container_reports_dir }}/rally-report.html || true +rally task report --json \ + --out {{ _cifmw_rally_container_reports_dir }}/rally-report.json || true +exit ${RALLY_TASK_RC:-0} diff --git a/roles/rally/vars/main.yml b/roles/rally/vars/main.yml new file mode 100644 index 000000000..1c8c0b9d6 --- /dev/null +++ b/roles/rally/vars/main.yml @@ -0,0 +1,18 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +_cifmw_rally_container_tasks_dir: "/var/lib/rally/tasks" +_cifmw_rally_container_reports_dir: "/var/lib/rally/reports" diff --git a/zuul.d/molecule.yaml b/zuul.d/molecule.yaml index 84a9fee42..ff6ddce04 100644 --- a/zuul.d/molecule.yaml +++ b/zuul.d/molecule.yaml @@ -672,6 +672,17 @@ parent: cifmw-molecule-base vars: TEST_RUN: radvd +- job: + files: + - ^common-requirements.txt + - ^test-requirements.txt + - ^roles/rally/.* + - ^ci/playbooks/molecule.* + - ^.config/molecule/.* + name: cifmw-molecule-rally + parent: cifmw-molecule-base + vars: + TEST_RUN: rally - job: files: - ^common-requirements.txt diff --git a/zuul.d/projects.yaml b/zuul.d/projects.yaml index f7f8ef64f..a2e3f28ef 100644 --- a/zuul.d/projects.yaml +++ b/zuul.d/projects.yaml @@ -93,6 +93,7 @@ - cifmw-molecule-podman - cifmw-molecule-polarion - cifmw-molecule-radvd + - cifmw-molecule-rally - cifmw-molecule-recognize_ssh_keypair - cifmw-molecule-registry_deploy - cifmw-molecule-repo_setup