Step-by-step playbook to add a Zuul job that builds s2i OpenStack service
images and deploys them through OpenStackVersion on an operator
repository's github-check pipeline.
Do not copy the existing test jobs from the operator repositories blindly. Some of them (for example test-operator and at the moment watcher-operator) are special cases.
For how the content provider job works in this repository, see the
developer guide.
This document covers the consumer side: wiring a live deploy+test
job in an operator repo. Do not copy this repository's own
github-check graph (content-provider → consumer-smoke →
deploy-validation); that wiring is documented under
This repository's github-check pipeline.
On an operator GitHub PR, Zuul must:
- Build operator images with
openstack-k8s-operators-content-provider. - Build that service's containers with
<service>-s2i-content-provider(child ofs2i-openstack-container-content-provider). - Deploy OpenStack with the s2i service images applied to
OpenStackVersionduringedpm_prepare(before the control plane comes up). - Run the operator's existing test-operator (or equivalent) against that
deployment via a test job. The naming convention for such jobs is:
<service>-s2i-test[-<foo>], where the optional<foo>suffix is used to distinguish the various testing jobs for the same component.
Keep the existing kuttl and test-operator jobs unchanged, which can be used to test the newer operators with the old content. The s2i jobs are new siblings, not replacements. Once they are stable they should be turned to voting.
Job names in the operator repo:
| Job | Parents | Purpose |
|---|---|---|
<service>-s2i-content-provider |
s2i-openstack-container-content-provider |
Build this service's s2i images |
<service>-s2i-test |
The operator's existing deploy+test job | Deploy those images and run test-operator tests |
Example: cinder-s2i-content-provider, cinder-s2i-test-ceph.
Operator PR (github-check)
|
+-- openstack-k8s-operators-content-provider
| (operator catalog; owns content_provider_registry_ip)
|
+-- <service>-s2i-content-provider
| (service images; s2i_content_provider_registry_ip:5001)
|
v
<service>-s2i-test-foo
parents the operator's existing deploy+test job
trusts both registries
applies cifmw_set_containers_images during edpm_prepare
runs the parent's test-operator tests
Use one of the two component base jobs defined in this repository as parent for the deploy+test job:
s2i-test-bases2i-test-base-ceph(a variant ofs2i-test-basewhich deploys a minimal ceph and configures a few services with it).
Do not parent s2i-openstack-deploy-validation (defined in this
repo) on operator github-check. That job is special in the way s2i is
the sole content provider. It sets content_provider_registry_ip
to the s2i registry, which steals the operator catalog.
Do not copy this repository's own github-check job graph onto an
operator pipeline either. Here the image jobs are
s2i-openstack-container-content-provider →
s2i-openstack-container-consumer-smoke →
s2i-openstack-deploy-validation. That last job depends on both the
content provider (paused registry and artifacts) and consumer-smoke (skip
CRC/EDPM when pull/inspect/mapping fails). Operator pipelines still use
<service>-s2i-test-<foo> with dual-registry trust as shown below. Smoke is
optional on the operator side; see
Optional fail-fast.
Before writing Zuul YAML, collect these facts from the operator repo and from this repository.
Under containers/<service>/. Example for cinder: cinder-api,
cinder-backup, cinder-scheduler, cinder-volume. The content
provider always builds base as a dependency when you list service
images.
Read containers/image-mappings.yaml.
- Scalar fields (for example
cinderAPIImage) are returned ins2i_content_provider_os_custom_container_imagesand can be passed straight tocifmw_set_containers_images. - Unmapped on purpose:
base— not a service imagetempest,ansible-test— test imagescinder/cinder-volume,manila/manila-share— backend maps, not scalars- nova-compute / nova-conductor / nova-scheduler / nova-novncproxy / placement — s2i does not build them; they stay on operator defaults
- Mapped but omitted by this repo's deploy-validation job:
neutronAPIImage,edpmNeutronMetadataAgentImage, andmariadbImage.s2i-openstack-deploy-validationfilters them withs2i_ci_skip_os_custom_imagesuntil those images can be consumed by the control plane, sopreserve_unlistedkeeps payload defaults. The content provider still returns every mapped key. Operator consumer jobs must inject them: leave the skip list unset or empty. Do not replace the mappings withquay.iomaster-latestpins. When operators are ready, remove the keys from the skip list rather than deleting the mappings.
If a scalar service image is missing from the mapping, add it in this
repo first. Do not invent OpenStackVersion field names; they must match
spec.customContainerImages on
core.openstack.org/v1beta1 OpenStackVersion.
cinderVolumeImages and manilaShareImages are maps keyed by the
CinderVolume / ManilaShare resource name, not the driver name.
HCI Ceph in ci-framework uses CinderVolume volume1 (the Ceph driver
is configured inside that CR). openstack-operator looks up
CinderVolumeImages[<name>] and otherwise falls back to "default".
The "default" key is always reset to the operator
RELATED_IMAGE; setting backends: [default] does not change the
running volume pod.
Find the name of all backends from the parent job's kustomize
(for a simple HCI job: cinderVolumes/volume1).
This is the only phase needed to prove the job. Do it first.
github-check already runs openstack-k8s-operators-content-provider.
CRC trusts that registry via content_provider_registry_ip. The s2i
provider publishes to a second plain registry.
Do not set:
content_provider_registry_ip: "{{ s2i_content_provider_registry_ip }}"That overwrites the operator catalog host. Append s2i instead:
cifmw_crc_additional_insecure_registries:
- "{{ s2i_content_provider_registry_ip }}:5001"
cifmw_crc_additional_allowed_registries:
- "{{ s2i_content_provider_registry_ip }}:5001"ci-framework edpm_prepare calls cifmw.general.set_containers when
cifmw_set_containers_images is non-empty. That is early enough.
A pre_tests oc patch is too late.
The two parents jobs take care of this, so do not overload
cifmw_set_containers_images.
cifmw_set_containers_preserve_unlisted: true
cifmw_set_containers_images: >-
{{
s2i_content_provider_os_custom_container_images | dict2items |
json_query('[].{name: key, full_registry: value}')
}}preserve_unlisted: true keeps images not in the s2i map from the
current OpenStackVersion CR.
s2i-speculative-deploy-test-base (this repository only) optionally
filters that map through s2i_ci_skip_os_custom_images, which is empty
by default. Only s2i-openstack-deploy-validation sets a skip list
today (neutronAPIImage, edpmNeutronMetadataAgentImage,
mariadbImage). Do not copy that skip list into
<service>-s2i-test-<foo>. Operator jobs should pass the full
s2i_content_provider_os_custom_container_images map as shown above.
Only for jobs testing cinder and manila, append the discovered cinder and manila backends as a list to respectively:
s2i_cinder_volume_backendss2i_manila_share_backends
Place both jobs in the operator's zuul.d/jobs.yaml (or .zuul.yaml if
that is how the repo is laid out). Do not add the generic
s2i-openstack-container-content-provider to the project pipeline;
inherit it under the operator's own name.
- job:
name: <service>-s2i-content-provider
parent: s2i-openstack-container-content-provider
description: |
Build s2i <service> images for <service>-s2i-test-<foo>.
required-projects:
- name: openstack-k8s-operators/s2i-openstack-containers
override-checkout: main
vars:
s2i_ci_images:
- <service>/<image-a>
- <service>/<image-b>
- job:
name: <service>-s2i-test-<foo>
parent: s2i-test-base[-ceph]
description: |
Validate speculatively-built s2i <service> images against a live
OpenStack deployment. s2i-built images from the content provider
are applied to OpenStackVersion during edpm_prepare via
ci-framework set_containers before the control plane is deployed.
vars:
cifmw_test_operator_tempest_include_list: |
...Do not copy s2i_ci_skip_os_custom_images from
s2i-openstack-deploy-validation into operator consumer jobs.
Use an explicit s2i_ci_images list on github-check. auto is for
OpenDev patches, where the triggering project is openstack/<service>.
On an operator PR, auto-detect looks at operator sources and finds no
sources.txt match.
In zuul.d/projects.yaml (or the project stanza in .zuul.yaml):
- project:
name: openstack-k8s-operators/<service>-operator
github-check:
jobs:
- openstack-k8s-operators-content-provider:
vars:
cifmw_install_yamls_sdk_version: v1.41.1
# existing kuttl / test-operator unchanged
- <service>-s2i-content-provider:
voting: false
- <service>-s2i-test-<foo>:
voting: false
dependencies:
- openstack-k8s-operators-content-provider
- <service>-s2i-content-providerKeep both content providers as direct dependencies for the test job. It is what keeps each paused registry up until CRC finishes. Do not replace those lines with a dependency on smoke alone.
This repository gates s2i-openstack-deploy-validation on
s2i-openstack-container-consumer-smoke. Operators can do the same
before <service>-s2i-test-<foo>: smoke pulls and inspects the published
images on a cheap CentOS node so a broken registry or mapping does not
start CRC.
Depend on <service>-s2i-content-provider (the job name in this
pipeline), not s2i-openstack-container-content-provider. That parent
job is not scheduled on the operator pipeline. Keep both content
providers as direct dependencies for the test job so each paused registry
stays up.
- s2i-openstack-container-consumer-smoke:
voting: false
dependencies:
- <service>-s2i-content-provider
- <service>-s2i-test-<foo>:
voting: false
dependencies:
- openstack-k8s-operators-content-provider
- <service>-s2i-content-provider
- s2i-openstack-container-consumer-smokeThis is optional. Phase 1 is complete without it.
watcher-operator also:
- Switched github-check from the meta content provider to
openstack-k8s-operators-content-provider(operator images only; service images come from s2i). - Folded s2i jobs into the existing
opendev-watcher-edpm-pipelinetemplate because RDO config already applies that template toopenstack/watcher,python-watcherclient, andwatcher-tempest-plugin. - Limited OpenDev s2i jobs with
files: [^watcher/]so client and tempest-plugin changes do not rebuild containers.
Most operators already use the non-meta operator content provider and have no OpenDev EDPM template. Skip those extras unless the same facts are true for the operator you are onboarding.
Do this only after github-check has applied s2i images and the test job has run.
Two wiring options:
- Existing
opendev-<service>-edpm-pipelinein the operator repo, already applied by the config repo (watcher): add the s2i provider and consumer to that template in place. Uses2i_ci_images: auto,files:on the service source tree, andoverride-checkout: main. - No such template (cinder and most others): add a project stanza
in
openstack-k8s-operators/configzuul.d/s2i-openstack-speculative-builds.yamlusing thes2i-speculative-buildtemplate, plus the consumer job with dependencies on both content providers.
Do not invent a new opendev-<service>-edpm-pipeline inside the
operator just to copy watcher. That template exists because RDO already
pointed Gerrit watcher projects at it.
End-to-end OpenDev proof needs a DNM patch on
opendev.org/openstack/<service> with Depends-On: pointing at the
operator PR.
Projects that only need build validation (no deployment) can use the template alone:
- project:
name: opendev.org/openstack/<service>
templates:
- s2i-speculative-buildThe s2i-speculative-build template still schedules the generic
s2i-openstack-container-content-provider with s2i_ci_images: auto.
Depend on that job, not <service>-s2i-content-provider (that child
exists only on the operator github-check pipeline).
A deploy+test OpenDev stanza looks like:
- project:
name: opendev.org/openstack/<service>
templates:
- s2i-speculative-build
check:
jobs:
- openstack-k8s-operators-content-provider:
vars:
cifmw_install_yamls_sdk_version: v1.41.1
- <service>-s2i-test-<foo>:
voting: false
dependencies:
- openstack-k8s-operators-content-provider
- s2i-openstack-container-content-providerFrom the consumer job logs / must-gather, OpenStackVersion
spec.customContainerImages must show s2i registry URLs, for example:
cinderAPIImage: <s2i-ip>:5001/openstack/openstack-cinder-api:<tag>
cinderBackupImage: <s2i-ip>:5001/openstack/openstack-cinder-backup:<tag>
cinderSchedulerImage: <s2i-ip>:5001/openstack/openstack-cinder-scheduler:<tag>
cinderVolumeImages:
volume1: <s2i-ip>:5001/openstack/openstack-cinder-volume:<tag>Pods for those services must pull from the s2i registry, not only quay.io operator defaults. Tempest failures after a correct OpenStackVersion are a test-filter problem, not an injection problem.
- Classified the operator (test image vs custom EDPM vs typical)
- Confirmed s2i image targets and
image-mappings.yamlscalars - For cinder/manila: identified backend map key (HCI:
volume1) - Jobs named
<service>-s2i-content-providerand<service>-s2i-test-<foo> - Content provider child parents
s2i-openstack-container-content-provider(do not add the generic job to the operator pipeline) - Consumer job parents one of the two base jobs
- Do not copy this repo's
s2i-openstack-deploy-validationdependency list; keep both content providers as direct dependencies for the test job. Optional: adds2i-openstack-container-consumer-smokeas an extra test job dependency (depend on<service>-s2i-content-provider, not the generic parent job) - Do not copy
s2i_ci_skip_os_custom_imagesfroms2i-openstack-deploy-validation - Dual registry: additional insecure and allowed; operator CP
keeps
content_provider_registry_ip -
cifmw_set_containers_preserve_unlisted: true - No Zuul vars starting with
_ - Existing kuttl/test-operator jobs unchanged
- New jobs
voting: falseuntil they are stable - Explicit
s2i_ci_imageslist on github-check - OpenStackVersion in a live run shows s2i URLs (including backend maps if applicable)
| Symptom | Likely cause |
|---|---|
Zuul: Invalid Ansible variable name '_...' |
Job vars must not start with _ |
| Operator catalog / CRC cannot pull operator images | content_provider_registry_ip was pointed at s2i |
| CRC cannot pull s2i service images | Missing cifmw_crc_additional_* registries |
| API/scheduler s2i, volume pod still quay | Missing cinderVolumeImages.<CinderVolume name> |
Volume map set on default but pod unchanged |
Operator always overwrites the default key |
s2i_ci_images: auto on an operator PR builds nothing useful |
Auto-detect matches OpenDev sources.txt projects, not operator git |
| Images appear only after test job starts | Injection used pre_tests instead of edpm_prepare / set_containers |
| CRC/EDPM skipped after a short consumer-smoke failure | Expected if smoke is a test job dependency: pull, inspect, or deployment-key resolution failed. Fix the s2i provider return, then test-operator will run. |
Smoke job: Job s2i-openstack-container-content-provider not defined |
Smoke depends on a job name that is not in this pipeline. On an operator repo depend on <service>-s2i-content-provider. |
| Registry gone while the test job is still pulling | Test job lost its direct dependency on the s2i content provider (depended only on smoke). Keep the provider listed on the test job. |
| Neutron/MariaDB/Glance image stays on payload defaults in an operator job | Copied s2i_ci_skip_os_custom_images from s2i-openstack-deploy-validation; that skip list is only for this repo's gate |