Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions hooks/playbooks/rally_glance_prerequisites.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
- name: Prepare local images for custom Rally Glance workloads
hosts: "{{ cifmw_target_hook_host | default('localhost') }}"
gather_facts: false
vars:
cifmw_rally_glance_artifacts_basedir: >-
{{ cifmw_rally_artifacts_basedir | default(cifmw_basedir ~ '/tests/rally') }}
# Verified against https://download.cirros-cloud.net/0.6.2/MD5SUMS.
cifmw_rally_glance_cirros_sha256: "07e44a73e54c94d988028515403c1ed762055e01b83a767edf3c2b387f78ce00"
cifmw_rally_glance_images:
- name: dummy_image.qcow2
format: qcow2
virtual_size: 104857600
- name: dummy_image.raw
format: raw
virtual_size: 104857600
- name: cirros.qcow2
format: qcow2
tasks:
- name: Initialize Glance image destinations
ansible.builtin.set_fact:
cifmw_rally_glance_image_dirs: []

- name: Select Glance image destinations
ansible.builtin.set_fact:
cifmw_rally_glance_image_dirs: >-
{{ cifmw_rally_glance_image_dirs +
[cifmw_rally_glance_artifacts_basedir ~
('/' ~ item.name if item.name | length > 0 else '') ~ '/tasks/images'] }}
loop: "{{ cifmw_rally_runs | default([{'name': ''}], true) }}"
loop_control:
label: "{{ item.name | default('single run', true) }}"
when: item.name in ['', 'glance']

- name: Prepare images for selected Glance runs
when: cifmw_rally_glance_image_dirs | length > 0
block:
- name: Install image preparation tools
become: true
ansible.builtin.package:
name: qemu-img
state: present

- name: Create Glance image directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0755"
loop: "{{ cifmw_rally_glance_image_dirs }}"

- name: Create missing dummy images
ansible.builtin.command:
argv:
- qemu-img
- create
- -f
- "{{ item.1.format }}"
- "{{ item.0 }}/{{ item.1.name }}"
- 100M
creates: "{{ item.0 }}/{{ item.1.name }}"
loop: >-
{{ cifmw_rally_glance_image_dirs |
product(cifmw_rally_glance_images | selectattr('virtual_size', 'defined')) | list }}
loop_control:
label: "{{ item.0 }}/{{ item.1.name }}"

- name: Inspect cached CirrOS checksums
ansible.builtin.stat:
path: "{{ item }}/cirros.qcow2"
checksum_algorithm: sha256
loop: "{{ cifmw_rally_glance_image_dirs }}"
register: cifmw_rally_glance_cirros_stats

- name: Reject invalid cached CirrOS images
ansible.builtin.assert:
that:
- >-
not item.stat.exists or
(item.stat.isreg | default(false) and
item.stat.checksum | default('') == cifmw_rally_glance_cirros_sha256)
fail_msg: >-
Invalid or unreadable cached image: {{ item.item }}/cirros.qcow2.
Expected the verified CirrOS 0.6.2 x86_64 disk image.
Move the invalid file aside before rerunning this hook.
loop: "{{ cifmw_rally_glance_cirros_stats.results }}"
loop_control:
label: "{{ item.item }}/cirros.qcow2"

- name: Cache verified CirrOS boot images
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: "{{ item }}/cirros.qcow2"
checksum: "sha256:{{ cifmw_rally_glance_cirros_sha256 }}"
mode: "0644"
timeout: 60
loop: "{{ cifmw_rally_glance_image_dirs }}"

- name: Make Glance image files readable inside the container
ansible.builtin.file:
path: "{{ item.0 }}/{{ item.1.name }}"
mode: "0644"
state: file
loop: "{{ cifmw_rally_glance_image_dirs | product(cifmw_rally_glance_images) | list }}"
loop_control:
label: "{{ item.0 }}/{{ item.1.name }}"

- name: Inspect Glance image formats and sizes
ansible.builtin.command:
argv:
- qemu-img
- info
- --output=json
- "{{ item.0 }}/{{ item.1.name }}"
loop: "{{ cifmw_rally_glance_image_dirs | product(cifmw_rally_glance_images) | list }}"
loop_control:
label: "{{ item.0 }}/{{ item.1.name }}"
register: cifmw_rally_glance_image_info
changed_when: false
failed_when: false
check_mode: false

- name: Validate Glance image formats and sizes
vars:
cifmw_rally_glance_image_metadata: "{{ item.stdout | default('{}', true) | from_json }}"
ansible.builtin.assert:
that:
- item.rc == 0
- cifmw_rally_glance_image_metadata.format == item.item.1.format
- >-
item.item.1.virtual_size is not defined or
cifmw_rally_glance_image_metadata['virtual-size'] == item.item.1.virtual_size
fail_msg: >-
Invalid or unreadable image: {{ item.item.0 }}/{{ item.item.1.name }}.
Expected format {{ item.item.1.format }}{{
' and virtual size 100 MiB' if item.item.1.virtual_size is defined else '' }}.
{{ item.stderr | default('') }}
loop: "{{ cifmw_rally_glance_image_info.results }}"
loop_control:
label: "{{ item.item.0 }}/{{ item.item.1.name }}"
rescue:
- name: Warn about incomplete Glance image preparation
ansible.builtin.debug:
msg: >-
WARNING: Glance image preparation failed at '{{ ansible_failed_task.name }}':
{{ ansible_failed_result.msg | default('See the failed task output for details.') }}
Continuing to Rally execution. Scenarios that need the unavailable or invalid
images may fail; other workloads can still run.
52 changes: 52 additions & 0 deletions roles/rally/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,55 @@ Each run stores its artifacts under `cifmw_rally_artifacts_basedir/<name>/`.

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).

### Glance image preparation

For custom Glance workloads, run `rally_glance_prerequisites.yaml` on the same
host as `rally_run.yaml`. It installs `qemu-img`, creates 100 MiB dummy QCOW2
and raw disks, and caches a checksum-verified CirrOS 0.6.2 boot image. Existing
images are validated and reused; invalid files are reported and left untouched.
Image preparation errors are rescued with a warning so this hook does not
prevent Rally execution. Scenarios that require unavailable or invalid images
may fail, while other workloads can still run.
Image preparation does not depend on whether a CirrOS image already exists
in Glance: image-creation scenarios need a local file to upload themselves.

Order the hooks before Rally execution, for example:

```yaml
post_tests_70_rally_prerequisites:
type: playbook
source: rally_prerequisites.yaml
post_tests_80_rally_glance_prerequisites:
type: playbook
source: rally_glance_prerequisites.yaml
post_tests_90_rally_run:
type: playbook
source: rally_run.yaml
```

The Glance hook honors `cifmw_rally_artifacts_basedir`. In multi-run mode it
prepares entries named `glance` and skips other runs. In single-run mode
(`cifmw_rally_runs` unset or empty), it prepares the base artifacts directory.
The common prerequisites hook shown above currently expects `cifmw_rally_runs`
and handles named runs; configure those shared cloud prerequisites separately
when using single-run mode.

Images are placed under each selected run's `tasks/images/`, which the role's
existing tasks volume makes available inside the container. Update the custom
workload to use these paths for `image_location` and `contexts.images.image_url`:

- `/var/lib/rally/tasks/images/dummy_image.qcow2` for QCOW2 API tests.
- `/var/lib/rally/tasks/images/dummy_image.raw` for raw API tests.
- `/var/lib/rally/tasks/images/cirros.qcow2` for `create_image_and_boot_instances`.

An empty dummy disk cannot boot an OS. Keep the boot scenario's Rally-managed
network context and `boot_server_kwargs.auto_assign_nic: true` when temporary
tenants have no suitable shared network. Set `sla.failure_rate.max: 0` for each
workload so CI detects failures. These settings belong in the custom task YAML;
the preparation hook does not rewrite workloads or change bundled tests.

The hook does not change Rally's test-failure policy. To continue to later
component runs even if a Glance run fails, set
`cifmw_rally_fail_on_task_failure: false` in that run's `cifmw_rally_runs` entry.
Rally still records the scenario failures in its logs and reports.
Loading