Added tempest images
Sem-Ver: feature
Change-Id: I9fea644a8fc021cb21bd7ff14af2d581e1d193ee
diff --git a/images/master.yml b/images/master.yml
new file mode 100644
index 0000000..1801720
--- /dev/null
+++ b/images/master.yml
@@ -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
\ No newline at end of file
diff --git a/releasenotes/notes/add-tempest-images-07a34f3e521ffee5.yaml b/releasenotes/notes/add-tempest-images-07a34f3e521ffee5.yaml
new file mode 100644
index 0000000..7cd427e
--- /dev/null
+++ b/releasenotes/notes/add-tempest-images-07a34f3e521ffee5.yaml
@@ -0,0 +1,3 @@
+---
+features:
+ - Added tempest images built from the master branch.
diff --git a/zuul.d/images-master.yaml b/zuul.d/images-master.yaml
new file mode 100644
index 0000000..3e9346d
--- /dev/null
+++ b/zuul.d/images-master.yaml
@@ -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
\ No newline at end of file
diff --git a/zuul.d/images.yaml b/zuul.d/images.yaml
new file mode 100644
index 0000000..c487221
--- /dev/null
+++ b/zuul.d/images.yaml
@@ -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
diff --git a/zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/pre-run.yml b/zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/pre-run.yml
new file mode 100644
index 0000000..f390d11
--- /dev/null
+++ b/zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/pre-run.yml
@@ -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
\ No newline at end of file
diff --git a/zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/run.yml b/zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/run.yml
new file mode 100644
index 0000000..2ded2c2
--- /dev/null
+++ b/zuul.d/playbooks/ansible-collection-atmosphere-build-images-manifest/run.yml
@@ -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 }}"
diff --git a/zuul.d/playbooks/ansible-collection-atmosphere-build-images/pre-run.yml b/zuul.d/playbooks/ansible-collection-atmosphere-build-images/pre-run.yml
new file mode 100644
index 0000000..1032b4c
--- /dev/null
+++ b/zuul.d/playbooks/ansible-collection-atmosphere-build-images/pre-run.yml
@@ -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
diff --git a/zuul.d/playbooks/ansible-collection-atmosphere-build-images/run.yml b/zuul.d/playbooks/ansible-collection-atmosphere-build-images/run.yml
new file mode 100644
index 0000000..7f879cf
--- /dev/null
+++ b/zuul.d/playbooks/ansible-collection-atmosphere-build-images/run.yml
@@ -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 }}"
diff --git a/zuul.d/secrets.yaml b/zuul.d/secrets.yaml
new file mode 100644
index 0000000..348b2ab
--- /dev/null
+++ b/zuul.d/secrets.yaml
@@ -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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
\ No newline at end of file