Merge "Added tempest images"

This commit is contained in:
Zuul 2022-04-18 15:07:37 +00:00 committed by Gerrit Code Review
commit d4cf5d8687
9 changed files with 478 additions and 0 deletions

26
images/master.yml Normal file
View File

@ -0,0 +1,26 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
registry: us-docker.pkg.dev/vexxhost-infra/openstack
projects:
tempest:
branch: master
revision: 44dac69eb77d78a0de8e68e63617099249345578
tag: 30.1.0-0
pip_packages:
- keystone-tempest-plugin
- cinder-tempest-plugin
- neutron-tempest-plugin
- heat-tempest-plugin

View File

@ -0,0 +1,3 @@
---
features:
- Added tempest images built from the master branch.

99
zuul.d/images-master.yaml Normal file
View File

@ -0,0 +1,99 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- job:
name: ansible-collection-atmosphere-build-images-master
parent: ansible-collection-atmosphere-build-images
abstract: true
dependencies: &image_dependencies
- name: ansible-collection-atmosphere-buildset-registry
soft: false
- name: ansible-collection-atmosphere-merge-wheels-master
soft: true
requires: &image_requires
- ansible-collection-atmosphere-wheels-master
files: &image_files
- images/master.yml
vars: &image_vars
openstack_release: master
- job:
name: ansible-collection-atmosphere-build-images-master-amd64
parent: ansible-collection-atmosphere-build-images-master
nodeset: ubuntu-focal
- job:
name: ansible-collection-atmosphere-build-images-master-aarch64
parent: ansible-collection-atmosphere-build-images-master
nodeset: ubuntu-focal-arm64
- job:
name: ansible-collection-atmosphere-build-images-manifest-master
parent: ansible-collection-atmosphere-build-images-manifest
dependencies:
- name: ansible-collection-atmosphere-buildset-registry
soft: false
- name: ansible-collection-atmosphere-build-images-master-amd64
soft: false
- name: ansible-collection-atmosphere-build-images-master-aarch64
soft: false
files: *image_files
vars: &manifest_vars
openstack_release: master
- job:
name: ansible-collection-atmosphere-upload-images-master
parent: ansible-collection-atmosphere-upload-images
abstract: true
dependencies: *image_dependencies
requires: *image_requires
files: *image_files
vars: *image_vars
- job:
name: ansible-collection-atmosphere-upload-images-master-amd64
parent: ansible-collection-atmosphere-upload-images-master
nodeset: ubuntu-focal
- job:
name: ansible-collection-atmosphere-upload-images-master-aarch64
parent: ansible-collection-atmosphere-upload-images-master
nodeset: ubuntu-focal-arm64
- job:
name: ansible-collection-atmosphere-upload-images-manifest-master
parent: ansible-collection-atmosphere-upload-images-manifest
dependencies:
- name: ansible-collection-atmosphere-buildset-registry
soft: false
- name: ansible-collection-atmosphere-upload-images-master-amd64
soft: false
- name: ansible-collection-atmosphere-upload-images-master-aarch64
soft: false
files: *image_files
vars: *manifest_vars
- project:
check:
jobs:
- ansible-collection-atmosphere-build-images-master-amd64
- ansible-collection-atmosphere-build-images-master-aarch64
- ansible-collection-atmosphere-build-images-manifest-master
gate:
jobs:
- ansible-collection-atmosphere-upload-images-master-amd64
- ansible-collection-atmosphere-upload-images-master-aarch64
- ansible-collection-atmosphere-upload-images-manifest-master

56
zuul.d/images.yaml Normal file
View File

@ -0,0 +1,56 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- job:
name: ansible-collection-atmosphere-buildset-registry
parent: opendev-buildset-registry
- job:
name: ansible-collection-atmosphere-build-images
parent: opendev-build-docker-image
abstract: true
required-projects:
- openstack/loci
pre-run:
- zuul.d/playbooks/ansible-collection-atmosphere-build-images/pre-run.yml
run:
- zuul.d/playbooks/ansible-collection-atmosphere-build-images/run.yml
- job:
name: ansible-collection-atmosphere-upload-images
parent: ansible-collection-atmosphere-build-images
abstract: true
secrets:
name: docker_credentials
secret: gar-credentials
pass-to-parent: true
- job:
name: ansible-collection-atmosphere-build-images-manifest
pre-run:
- zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/pre-run.yml
run:
- zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/run.yml
- job:
name: ansible-collection-atmosphere-upload-images-manifest
parent: ansible-collection-atmosphere-build-images-manifest
- project:
check:
jobs:
- ansible-collection-atmosphere-buildset-registry
gate:
jobs:
- ansible-collection-atmosphere-buildset-registry

View File

@ -0,0 +1,18 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- hosts: all
roles:
- ensure-podman
- use-buildset-registry

View File

@ -0,0 +1,40 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- hosts: all
tasks:
- name: Include manifest file with all the image information
ansible.builtin.include_vars:
file: "../../../images/{{ openstack_release }}.yml"
name: image_manifest
- name: Create manifest for every project built
command:
podman manifest create {{ item | basename }}:{{ image_manifest['projects'][item.rsplit('/')[-1]]['tag'] }}
loop: "{{ zuul.artifacts | selectattr('metadata.repository', 'defined') | map(attribute='metadata.repository') | sort | unique }}"
- name: Add image to their manifest
command:
podman manifest add
--arch {{ (item.metadata.arch == "aarch64") | ternary("arm64", "amd64") }}
{{ item.metadata.project }}:{{ image_manifest['projects'][item.metadata.project]['tag'] }}
{{ item.url }}
loop: "{{ zuul.artifacts | selectattr('metadata.type', 'defined') | selectattr('metadata.type', 'equalto', 'image') | list }}"
- name: Push manifests to buildset registry
command:
podman manifest push
{{ item | basename }}:{{ image_manifest['projects'][item.rsplit('/')[-1]]['tag'] }}
{{ item }}:{{ image_manifest['projects'][item.rsplit('/')[-1]]['tag'] }}
loop: "{{ zuul.artifacts | selectattr('metadata.repository', 'defined') | map(attribute='metadata.repository') | sort | unique }}"

View File

@ -0,0 +1,17 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- hosts: all
roles:
- ensure-pip

View File

@ -0,0 +1,130 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- hosts: all
tasks:
- name: Include manifest file with all the image information
ansible.builtin.include_vars:
file: "../../../images/{{ openstack_release }}.yml"
name: image_manifest
- name: Check if the image is already built
ansible.builtin.command:
docker manifest inspect {{ image_manifest.registry }}/{{ item.key }}:{{ item.value.tag }}
register: _docker_manifest_inspect
with_dict: "{{ image_manifest.projects }}"
loop_control:
label: "{{ item.key }}"
# NOTE(mnaser): We want to mark the task as "changed" if we have to do
# any work (i.e if the image is not already built).
failed_when: false
changed_when: _docker_manifest_inspect.rc != 0
- name: Fail the job if all the images are already built
ansible.builtin.fail:
msg: All the images are already built, did you forget to bump the tag?
when: _docker_manifest_inspect is not changed
- name: Generate a fact with the list of projects to be built
ansible.builtin.set_fact:
images_to_build: "{{ _docker_manifest_inspect.results | select('changed') | list | map(attribute='item.key') | list }}"
- name: Clone projects that need to be built
ansible.builtin.git:
repo: "https://opendev.org/openstack/{{ item }}"
dest: "/tmp/{{ item }}"
version: "{{ image_manifest['projects'][item]['revision'] }}"
loop: "{{ images_to_build }}"
- name: Generate the PBR version for the projects
ansible.builtin.shell:
/usr/bin/python3 setup.py --version
args:
chdir: "/tmp/{{ item }}"
environment:
PYTHONWARNINGS: "ignore:Unverified HTTPS request"
register: _pbr_version
loop: "{{ images_to_build }}"
- name: Assert that the PBR version exists in the tag
ansible.builtin.assert:
that: item.stdout.strip() in image_manifest['projects'][item.item].tag
loop: "{{ _pbr_version.results }}"
loop_control:
label: "{{ item.item }}"
- name: Set fact for wheels tarball from artifacts
ansible.builtin.set_fact:
wheels_path: "{{ item.url }}"
loop: "{{ (zuul.artifacts | default([])) | selectattr('metadata.type', 'defined') | selectattr('metadata.type', 'equalto', 'wheels') | list }}"
- name: Set the fact for wheels path to default if none is detected
ansible.builtin.set_fact:
wheels_path: "https://tarballs.opendev.org/vexxhost/ansible-collection-atmosphere/ansible-collection-atmosphere-wheels-{{ openstack_release }}-master.tar.gz"
when: wheels_path is not defined
- name: Build the images
ansible.builtin.include_role:
name: build-docker-image
register: _build_docker_image
loop: "{{ images_to_build }}"
vars:
zuul_work_dir: "{{ zuul.projects['opendev.org/openstack/loci'].src_dir }}"
docker_registry: "{{ image_manifest.registry }}"
docker_images:
- context: .
repository: "{{ item }}"
tags:
- "{{ image_manifest['projects'][item]['tag'] }}-{{ ansible_architecture }}"
build_args:
# TODO(mnaser): build base image
- FROM="ubuntu:focal"
- PROJECT="{{ item }}"
- PROJECT_REF="{{ image_manifest['projects'][item]['revision'] }}"
- PROJECT_RELEASE="{{ openstack_release }}"
- WHEELS="{{ wheels_path }}"
- PROFILES="{{ image_manifest['projects'][item].get('profies', []) | join(' ') }}"
- PIP_PACKAGES="{{ image_manifest['projects'][item].get('pip_packages', []) | join(' ') }}"
- DIST_PACKAGES="{{ image_manifest['projects'][item].get('dist_packages', []) | join(' ') }}"
- name: Upload the images
ansible.builtin.include_role:
name: upload-docker-image
register: _build_docker_image
when: zuul.job is search("upload")
loop: "{{ images_to_build }}"
vars:
zuul_work_dir: "{{ zuul.projects['opendev.org/openstack/loci'].src_dir }}"
docker_registry: "{{ image_manifest.registry }}"
docker_images:
- context: .
repository: "{{ item }}"
tags:
- "{{ image_manifest['projects'][item]['tag'] }}-{{ ansible_architecture }}"
- name: Return artifacts to Zuul
zuul_return:
data:
zuul:
artifacts:
- name: "{{ item }} ({{ ansible_architecture }})"
url: "docker://{{ _docker_registry }}/{{ item }}:{{ image_manifest['projects'][item]['tag'] }}-{{ ansible_architecture }}"
metadata:
type: image
repository: "docker://{{ _docker_registry }}/{{ item }}"
project: "{{ item }}"
arch: "{{ ansible_architecture }}"
vars:
_docker_registry: "{{ (docker_registry is defined) | ternary(docker_registry, 'zuul-jobs.buildset-registry:5000') }}"
loop: "{{ _build_docker_image.results | map(attribute='item') | list }}"

89
zuul.d/secrets.yaml Normal file
View File

@ -0,0 +1,89 @@
# Copyright (c) 2022 VEXXHOST, Inc.
#
# 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.
- secret:
name: gar-credentials
data:
username: _json_key_base64
password: !encrypted/pkcs1-oaep
- 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
- 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
- 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
- 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
- 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
- rw5LfGaIX+R9mZxU73+DdzHI5GT4ztLtVbovbE0iUcVUJgMjcY8jVEWm7DpFD6lwA6bsX
lw/deoVtFysfSN1XhfFVExU/apQ0eJgX38d6s1peKiJD7BPnpdIvJNfzHeaR3lUbhHXQo
Vl8VAIaIo1wsxHJRpXddZmqQRki23UBT2Yy2y8avEYPUJEYjyeyGaGvLu4V8kVTR7PoZJ
1uvR1kA2HrLKQp+kPf5Y0WT96LmsC6A+mtroy8aklCVnECxHC5J9Kvnhqgl6D4hFc5pkY
3INaYydCfTVhcaDg21UH27yLCL3jsp0t9RZ7jKlgSPWao6kzb04hnfcs8B8V280miBmIz
F6Em6wO+6rWZn9G/lq5f/8pA9a5wmRhQxoz9CT/u7ZyyzqytYC49Lyiz96B3vuUn9R4Ll
Hf5wkeSp07fsjDUrnP9I0pvXuQ9PxCoBVtW9ZzsjWzV2KZN+41ZriQLwnOB1tgsZFOs40
4vfLaq7WAyHC4OsTJbJp9CtpKUVHU4iE1rErzG4C9U6MdRG3RKGwdR/es9ur702J2U/c8
uHVVdG92WUQqDeRTmc6AtUfQaAZaGctJsl3NNbS1H556jUv04UDzAyXwti+0UnH+HCPuU
yBGNoDpI4H9d67wg2/hdcLUeXxiTOqcBKNAJLlzg2K81gMRL2FDc+xOgSIjF50=
- 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