From 403c0428046dadfb7dc44c958c943fa0d7666c98 Mon Sep 17 00:00:00 2001 From: Mohammed Naser Date: Tue, 16 Jan 2024 14:36:28 -0500 Subject: [PATCH] feat: upgrade to bobcat (#887) --- .github/renovate.json | 6 +- .pre-commit-config.yaml | 2 +- Earthfile | 1 - docs/developer/images.md | 15 + docs/developer/repos.md | 70 - images/Earthfile | 34 +- images/barbican/Earthfile | 24 +- images/base/Earthfile | 1 + images/cinder/Earthfile | 29 +- images/designate/Earthfile | 25 +- images/glance/Earthfile | 38 +- ...opriate-resize-amount-before-resizin.patch | 146 ++ images/heat/Earthfile | 25 +- images/horizon/Earthfile | 43 +- ...nore-errors-when-flavors-are-deleted.patch | 24 +- ...t-URL-when-browsing-Swift-containers.patch | 40 + ...000-fix-disable-resizing-for-admins.patch} | 24 +- ...-going-through-heat-for-worker-list.patch} | 0 images/ironic/Earthfile | 27 +- images/keystone/Earthfile | 29 +- ...on-credentials-take-account-of-impli.patch | 47 + images/libvirtd/Earthfile | 1 - images/magnum/Earthfile | 27 +- ...tainerd-cni-plugin-path-in-coreos-35.patch | 35 - .../patches/0002-support-k8s-1-24.patch | 75 - ...rovide-real-resolvconf-to-containers.patch | 48 - ...dapt-cinder-csi-to-upstream-manifest.patch | 860 ------- images/magnum/patches/0005-secure-rbac.patch | 1969 ----------------- ...lect-breaking-change-in-helm-v3-5-2.patch} | 0 images/manila/Earthfile | 25 +- ...stop-using-batch_op-for-rename_table.patch | 11 +- images/neutron/Earthfile | 27 +- ...-netns-deletion-of-broken-namespaces.patch | 33 +- images/nova/Earthfile | 25 +- images/octavia/Earthfile | 27 +- .../2023.1/upper-constraints.txt | 1 - .../2023.2/upper-constraints.txt | 1 - images/openstack-service/Earthfile | 82 +- .../master/upper-constraints.txt | 1 - .../zed/upper-constraints.txt | 1 - images/placement/Earthfile | 22 +- images/senlin/Earthfile | 22 +- images/tempest/Earthfile | 27 +- roles/defaults/vars/main.yml | 136 +- 44 files changed, 697 insertions(+), 3409 deletions(-) create mode 100644 docs/developer/images.md delete mode 100644 docs/developer/repos.md create mode 100644 images/glance/patches/glance_store/0000-rbd-compute-appropriate-resize-amount-before-resizin.patch rename images/horizon/patches/{ => horizon}/0000-fix-ignore-errors-when-flavors-are-deleted.patch (88%) create mode 100644 images/horizon/patches/horizon/0001-Fixing-Incorrect-URL-when-browsing-Swift-containers.patch rename images/horizon/patches/{0001-fix-disable-resizing-for-admins.patch => magnum-ui/0000-fix-disable-resizing-for-admins.patch} (89%) rename images/horizon/patches/{0002-capi-avoid-going-through-heat-for-worker-list.patch => magnum-ui/0001-capi-avoid-going-through-heat-for-worker-list.patch} (100%) create mode 100644 images/keystone/patches/keystone/0000-Ensure-application-credentials-take-account-of-impli.patch delete mode 100644 images/magnum/patches/0000-containerd-cni-plugin-path-in-coreos-35.patch delete mode 100644 images/magnum/patches/0002-support-k8s-1-24.patch delete mode 100644 images/magnum/patches/0003-fix-kubelet-for-fedora-coreos-36-to-provide-real-resolvconf-to-containers.patch delete mode 100644 images/magnum/patches/0004-adapt-cinder-csi-to-upstream-manifest.patch delete mode 100644 images/magnum/patches/0005-secure-rbac.patch rename images/magnum/patches/{0001-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch => magnum/0000-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch} (100%) rename images/manila/patches/{ => manila}/0000-fix-stop-using-batch_op-for-rename_table.patch (80%) rename images/neutron/patches/{ => neutron}/0000-fix-netns-deletion-of-broken-namespaces.patch (86%) diff --git a/.github/renovate.json b/.github/renovate.json index 8e4fae421..c9fc620ac 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -21,9 +21,9 @@ "packageNameTemplate": "https://github.com/openstack/{{{depName}}}", "currentValueTemplate": "stable/{{{version}}}", "matchStrings": [ - "ARG PROJECT=(?.*)", - "ARG RELEASE=(?.*)", - "ARG REF=(?.*)" + "ARG --global RELEASE=(?.*)", + "ARG --global PROJECT=(?.*)", + "ARG --global PROJECT_REF=(?.*)" ] }, { diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bb25beba0..17c6b27f7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: hooks: - id: end-of-file-fixer - id: trailing-whitespace - exclude: ^images/.*/patches/.*\.patch$ + exclude: ^images/.*/patches/.*/.*\.patch$ - repo: https://github.com/compilerla/conventional-pre-commit rev: v2.0.0 diff --git a/Earthfile b/Earthfile index 888110c3d..4ae563e85 100644 --- a/Earthfile +++ b/Earthfile @@ -27,7 +27,6 @@ libvirt-tls-sidecar.platform-image: --platform=linux/amd64 \ (+libvirt-tls-sidecar.build/main --GOARCH=$TARGETARCH --VARIANT=$TARGETVARIANT) /usr/bin/libvirt-tls-sidecar ENTRYPOINT ["/usr/bin/libvirt-tls-sidecar"] - LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere SAVE IMAGE --push ghcr.io/vexxhost/atmosphere/libvirt-tls-sidecar:latest libvirt-tls-sidecar.image: diff --git a/docs/developer/images.md b/docs/developer/images.md new file mode 100644 index 000000000..4a7acfbed --- /dev/null +++ b/docs/developer/images.md @@ -0,0 +1,15 @@ +# Images + +The images are built using Earthly and the contents of these files are all +located in the `images/` directory. + +## Adding Gerrit packages + +If you need to cherry-pick a specific Gerrit patch, you can use the following +command to download and extract the patch: + +```bash +earthly ./images+fetch-gerrit-patch \ + --IMAGE keystone \ + --CHANGE 893737 +``` diff --git a/docs/developer/repos.md b/docs/developer/repos.md deleted file mode 100644 index 512b9db36..000000000 --- a/docs/developer/repos.md +++ /dev/null @@ -1,70 +0,0 @@ -# Repositories - -Atmosphere uses a few different Git repositories to host the code for the -project. This document explains how to work with the different repositories, -their purpose, and how to maintain them. - -## Creating a new fork - -In order to create a new fork of a repository, we'll need to create a fork -under the `vexxhost` organization. In this example, we'll assume that you're -creating a fork of the `openstack/horizon` project. - -In order to fork the project, you'll start with the following command which -assumes that you have the `gh` command line tool installed: - -```bash -./hack/repos/fork openstack/horizon -``` - -> **Note** -> -> If this is an OpenStack project, once you're done, you'll also need to update -> the `FORKED_PROJECTS` variable in the -> `internal/pkg/image_repositories/build_workflow.go` file to include the newly -> forked project. - -## Applying patches - -The only time that it is necessary to apply patches to the forked repositories -is when there is a fix that has not yet been merged upstream. In order to -apply a patch, you can use the following command which includes the project -name and either a Gerrit URL or a GitHub pull request URL: - -```bash -./hack/repos/patch horizon https://review.opendev.org/c/openstack/horizon/+/874351/ -``` - -This command will take care of automatically cloning the project, downloading -the patch, and applying it to the repository. Once the patch has been applied, -it will push it in a new branch to the forked repository and create a pull -request. - -> **Note** -> -> If the process fails because of a merge conflict, you'll need to resolve the -> conflict and then run the command again. - -## Cherry-picking patches - -If you need to cherry-pick a patch from one branch of a forked repository to -another, you can use the following command: - -```bash -./hack/repos/cherry-pick magnum fbfd3ce9a3 stable/zed -``` - -In the example above, this will cherry-pick the commit `fbfd3ce9a3` from the -`master` branch of the `magnum` repository and create a pull request to apply -it to the `stable/zed` branch. - -## OpenStack - -Atmosphere has a few forks of the OpenStack repositories. These are used to -apply patches to the upstream code that contain fixes which have not yet been -merged upstream. The list of forked repositories is as follows: - -* [openstack/horizon](https://github.com/vexxhost/horizon) -* [openstack/keystone](https://github.com/vexxhost/keystone) -* [openstack/magnum](https://github.com/vexxhost/magnum) -* [openstack/magnum-ui](https://github.com/vexxhost/magnum-ui) diff --git a/images/Earthfile b/images/Earthfile index f5ff111b8..21cd0d819 100644 --- a/images/Earthfile +++ b/images/Earthfile @@ -29,17 +29,23 @@ CREATE_PROJECT_USER: mkdir -p /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT} && \ chown -Rv ${PROJECT}:${PROJECT} /etc/${PROJECT} /var/log/${PROJECT} /var/lib/${PROJECT} /var/cache/${PROJECT} -APPLY_PATCHES: - COMMAND - COPY --if-exists patches /patches - IF [ -d /patches ] - RUN \ - apt-get update && \ - apt-get install -y patch && \ - for patch in /patches/*.patch; do \ - patch -d /var/lib/openstack/lib/python3.10/site-packages/ -p1 < $patch; \ - done && \ - apt-get purge -y --auto-remove patch && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - END +fetch-gerrit-patch: + FROM ./base+image + DO +APT_INSTALL --PACKAGES "ca-certificates curl git jq" + ARG --required IMAGE + ARG PROJECT=${IMAGE} + ARG --required CHANGE + ARG PROJECT_REF=master + DO ./openstack-service+GIT_CHECKOUT \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + ARG REF=$(curl "https://review.opendev.org/changes/?q=${CHANGE}&o=CURRENT_REVISION" | tail -1 | jq -r '.[0].revisions[].ref') + COPY ${IMAGE}/patches/${PROJECT} /patches + RUN \ + git fetch https://review.opendev.org/openstack/${PROJECT} ${REF} && \ + git format-patch -1 --output-directory /gerrit FETCH_HEAD + ARG PATCH_ID=$(ls -1 /patches | wc -l | xargs printf "%04d") + RUN \ + cp /gerrit/0001-* \ + /patches/${PATCH_ID}-$(basename /gerrit/*.patch | sed 's/0001-//') + SAVE ARTIFACT /patches AS LOCAL ${IMAGE}/patches/${PROJECT} diff --git a/images/barbican/Earthfile b/images/barbican/Earthfile index af81b118f..0c843ffe2 100644 --- a/images/barbican/Earthfile +++ b/images/barbican/Earthfile @@ -1,15 +1,19 @@ VERSION 0.7 +ARG --global PROJECT=barbican +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=a00fcade4138ffc52cd9c84b5999297966f019b5 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="pykmip" + image: - ARG PROJECT=barbican - ARG RELEASE=zed - ARG REF=7d6749fcb1ad16a3350de82cd8e523d5b55306f8 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "pykmip" - DO ../+APPLY_PATCHES + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/base/Earthfile b/images/base/Earthfile index c075abc26..89449e018 100644 --- a/images/base/Earthfile +++ b/images/base/Earthfile @@ -2,3 +2,4 @@ VERSION 0.7 image: FROM ubuntu:jammy + LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere diff --git a/images/cinder/Earthfile b/images/cinder/Earthfile index c02de0ccf..402127fcd 100644 --- a/images/cinder/Earthfile +++ b/images/cinder/Earthfile @@ -1,19 +1,22 @@ VERSION 0.7 +ARG --global PROJECT=cinder +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=7d158234b72f04e780e307b0375cedf30dd8fb90 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="purestorage" + image: - ARG PROJECT=cinder - ARG RELEASE=zed - ARG REF=011e6549259c0433ceb594d8083f6c838d964311 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "purestorage" - DO \ - ../+APT_INSTALL \ - --PACKAGES "ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux" - DO ../+APPLY_PATCHES + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack COPY ../kubernetes+image/kubectl /usr/local/bin/kubectl + DO ../+APT_INSTALL \ + --PACKAGES "ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux" SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/designate/Earthfile b/images/designate/Earthfile index f3014be22..d88dc10da 100644 --- a/images/designate/Earthfile +++ b/images/designate/Earthfile @@ -1,17 +1,20 @@ VERSION 0.7 +ARG --global PROJECT=designate +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=2c817b3d7f01de44023f195c6e8de8853683a54a + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + image: - ARG PROJECT=designate - ARG RELEASE=zed - ARG REF=d247267823034c5e656f74e91b50475aa54d3fa6 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "bind9utils" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/glance/Earthfile b/images/glance/Earthfile index 8e203c9bb..c40c4033a 100644 --- a/images/glance/Earthfile +++ b/images/glance/Earthfile @@ -1,19 +1,31 @@ VERSION 0.7 +ARG --global PROJECT=glance +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=9a4a3067b5c7c7f8ee9363bd939a3d86b260d660 + +build.plugin: + ARG PLUGIN + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+GIT_CHECKOUT \ + --PROJECT=${PLUGIN} \ + --PROJECT_REF=stable/${RELEASE} + SAVE ARTIFACT /src + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + COPY (+build.plugin/src --PLUGIN=glance_store) /glance_store + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="/glance_store[cinder]" + image: - ARG PROJECT=glance - ARG RELEASE=zed - ARG REF=06a18202ab52c64803f044b8f848ed1c160905d2 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "glance_store[cinder]" - DO \ - ../+APT_INSTALL \ - --PACKAGES "ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux" - DO ../+APPLY_PATCHES + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack COPY ../kubernetes+image/kubectl /usr/local/bin/kubectl + DO ../+APT_INSTALL \ + --PACKAGES "ceph-common lsscsi nvme-cli python3-rados python3-rbd qemu-utils sysfsutils udev util-linux" SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/glance/patches/glance_store/0000-rbd-compute-appropriate-resize-amount-before-resizin.patch b/images/glance/patches/glance_store/0000-rbd-compute-appropriate-resize-amount-before-resizin.patch new file mode 100644 index 000000000..d57f318a0 --- /dev/null +++ b/images/glance/patches/glance_store/0000-rbd-compute-appropriate-resize-amount-before-resizin.patch @@ -0,0 +1,146 @@ +From fa43561078bbee531ccc8acf2e185b3fc6d98b2a Mon Sep 17 00:00:00 2001 +From: Andrew Bogott +Date: Thu, 8 Jun 2023 07:54:16 -0500 +Subject: [PATCH] rbd: compute appropriate resize amount before resizing image + +Resolves a bug introduced in + +https://opendev.org/openstack/glance_store/commit/c43f19e8456b9e20f03709773fb2ffdb94807a0a + +This issue is only in evidence when glance is behind a proxy where the +client buffer size can be lower (for haproxy: bufsize = 16384) which +can cause unaligned reads + +(https://github.com/openstack/glance/blob/master/glance/common/wsgi.py#L1028). + +The response length can be bigger than the store_chunk_size for the +first time, so at the end the RBD write will fail because it wants +to write more data than the actual RBD image size after the first +resize. + +Thanks to Robert Varjasi for investigating this issue! + +Fixes-Bug: 1916482 +Change-Id: Ie03693c2cb8b096978fb156231c3b1cab695470f +--- + glance_store/_drivers/rbd.py | 6 ++-- + glance_store/tests/unit/test_rbd_store.py | 38 ++++++++++++++--------- + 2 files changed, 26 insertions(+), 18 deletions(-) + +diff --git a/glance_store/_drivers/rbd.py b/glance_store/_drivers/rbd.py +index ba2defa..e53baef 100644 +--- a/glance_store/_drivers/rbd.py ++++ b/glance_store/_drivers/rbd.py +@@ -535,12 +535,12 @@ class Store(driver.Store): + """Handle the rbd resize when needed.""" + if image_size != 0 or self.size >= bytes_written + chunk_length: + return self.size +- new_size = self.size + self.resize_amount +- LOG.debug("resizing image to %s KiB" % (new_size / units.Ki)) +- image.resize(new_size) + # Note(jokke): We double how much we grow the image each time + # up to 8gigs to avoid resizing for each write on bigger images + self.resize_amount = min(self.resize_amount * 2, 8 * units.Gi) ++ new_size = self.size + self.resize_amount ++ LOG.debug("resizing image to %s KiB" % (new_size / units.Ki)) ++ image.resize(new_size) + return new_size + + @driver.back_compat_add +diff --git a/glance_store/tests/unit/test_rbd_store.py b/glance_store/tests/unit/test_rbd_store.py +index 4f24c26..fb6522a 100644 +--- a/glance_store/tests/unit/test_rbd_store.py ++++ b/glance_store/tests/unit/test_rbd_store.py +@@ -213,10 +213,10 @@ class TestReSize(base.StoreBaseTest, + data_len_temp = data_len + resize_amount = self.store.WRITE_CHUNKSIZE + while data_len_temp > 0: ++ resize_amount *= 2 + expected_calls.append(resize_amount + (data_len - + data_len_temp)) + data_len_temp -= resize_amount +- resize_amount *= 2 + expected += 1 + self.assertEqual(expected, resize.call_count) + resize.assert_has_calls([mock.call(call) for call in +@@ -244,7 +244,7 @@ class TestReSize(base.StoreBaseTest, + # Current size is smaller than we need + self.store.size = 8 + ret = self.store._resize_on_write(image, 0, 16, 16) +- self.assertEqual(8 + self.store.WRITE_CHUNKSIZE, ret) ++ self.assertEqual(8 + self.store.WRITE_CHUNKSIZE * 2, ret) + self.assertEqual(self.store.WRITE_CHUNKSIZE * 2, + self.store.resize_amount) + image.resize.assert_called_once_with(ret) +@@ -253,47 +253,55 @@ class TestReSize(base.StoreBaseTest, + image.resize.reset_mock() + self.store.size = ret + ret = self.store._resize_on_write(image, 0, 64, 16) +- self.assertEqual(8 + self.store.WRITE_CHUNKSIZE, ret) ++ self.assertEqual(8 + self.store.WRITE_CHUNKSIZE * 2, ret) + image.resize.assert_not_called() + + # Read past the limit triggers another resize + ret = self.store._resize_on_write(image, 0, ret + 1, 16) +- self.assertEqual(8 + self.store.WRITE_CHUNKSIZE * 3, ret) ++ self.assertEqual(8 + self.store.WRITE_CHUNKSIZE * 6, ret) + image.resize.assert_called_once_with(ret) + self.assertEqual(self.store.WRITE_CHUNKSIZE * 4, + self.store.resize_amount) + + # Check that we do not resize past the 8G ceiling. + +- # Start with resize_amount at 4G, 1G read so far ++ # Start with resize_amount at 2G, 1G read so far + image.resize.reset_mock() +- self.store.resize_amount = 4 * units.Gi ++ self.store.resize_amount = 2 * units.Gi + self.store.size = 1 * units.Gi + +- # First resize happens and we get the 4G, +- # resize_amount goes to limit of 8G ++ # First resize happens and we get to 5G, ++ # resize_amount goes to limit of 4G + ret = self.store._resize_on_write(image, 0, 4097 * units.Mi, 16) +- self.assertEqual(5 * units.Gi, ret) +- self.assertEqual(8 * units.Gi, self.store.resize_amount) ++ self.assertEqual(4 * units.Gi, self.store.resize_amount) ++ self.assertEqual((1 + 4) * units.Gi, ret) + self.store.size = ret + +- # Second resize happens and we get to 13G, ++ # Second resize happens and we stay at 13, no resize + # resize amount stays at limit of 8G + ret = self.store._resize_on_write(image, 0, 6144 * units.Mi, 16) +- self.assertEqual((5 + 8) * units.Gi, ret) + self.assertEqual(8 * units.Gi, self.store.resize_amount) ++ self.assertEqual((1 + 4 + 8) * units.Gi, ret) + self.store.size = ret + +- # Third resize happens and we get to 21G, ++ # Third resize happens and we get to 21, + # resize amount stays at limit of 8G + ret = self.store._resize_on_write(image, 0, 14336 * units.Mi, 16) +- self.assertEqual((5 + 8 + 8) * units.Gi, ret) + self.assertEqual(8 * units.Gi, self.store.resize_amount) ++ self.assertEqual((1 + 4 + 8 + 8) * units.Gi, ret) ++ self.store.size = ret ++ ++ # Fourth resize happens and we get to 29, ++ # resize amount stays at limit of 8G ++ ret = self.store._resize_on_write(image, 0, 22528 * units.Mi, 16) ++ self.assertEqual(8 * units.Gi, self.store.resize_amount) ++ self.assertEqual((1 + 4 + 8 + 8 + 8) * units.Gi, ret) + + image.resize.assert_has_calls([ + mock.call(5 * units.Gi), + mock.call(13 * units.Gi), +- mock.call(21 * units.Gi)]) ++ mock.call(21 * units.Gi), ++ mock.call(29 * units.Gi)]) + + + class TestStore(base.StoreBaseTest, +-- +2.34.1 + diff --git a/images/heat/Earthfile b/images/heat/Earthfile index 87ee43bb1..c55fc4265 100644 --- a/images/heat/Earthfile +++ b/images/heat/Earthfile @@ -1,17 +1,20 @@ VERSION 0.7 +ARG --global PROJECT=heat +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=d1363cc17646893054f9e8daf40de67699078e7c + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + image: - ARG PROJECT=heat - ARG RELEASE=zed - ARG REF=a2b70a93658ecd2774f22c63a394c5629aefdbe7 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "curl jq" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/horizon/Earthfile b/images/horizon/Earthfile index 6ff9199cd..fe9ac5fc3 100644 --- a/images/horizon/Earthfile +++ b/images/horizon/Earthfile @@ -1,18 +1,37 @@ VERSION 0.7 +ARG --global PROJECT=horizon +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=3c6029cd94846235e25058b71522c13556f41f58 + +build.plugin: + ARG PLUGIN + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+GIT_CHECKOUT \ + --PROJECT=${PLUGIN} \ + --PROJECT_REF=stable/${RELEASE} + SAVE ARTIFACT /src + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + COPY (+build.plugin/src --PLUGIN=designate-dashboard) /designate-dashboard + COPY (+build.plugin/src --PLUGIN=heat-dashboard) /heat-dashboard + COPY (+build.plugin/src --PLUGIN=ironic-ui) /ironic-ui + COPY (+build.plugin/src --PLUGIN=magnum-ui) /magnum-ui + COPY (+build.plugin/src --PLUGIN=manila-ui) /manila-ui + COPY (+build.plugin/src --PLUGIN=neutron-vpnaas-dashboard) /neutron-vpnaas-dashboard + COPY (+build.plugin/src --PLUGIN=octavia-dashboard) /octavia-dashboard + COPY (+build.plugin/src --PLUGIN=senlin-dashboard) /senlin-dashboard + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES "/designate-dashboard /heat-dashboard /ironic-ui /magnum-ui /neutron-vpnaas-dashboard /octavia-dashboard /senlin-dashboard /manila-ui" + image: - ARG PROJECT=horizon - ARG RELEASE=2023.2 - ARG REF=3c6029cd94846235e25058b71522c13556f41f58 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "git+https://github.com/openstack/designate-dashboard.git@stable/${RELEASE} git+https://github.com/openstack/heat-dashboard.git@stable/${RELEASE} git+https://github.com/openstack/ironic-ui.git@stable/${RELEASE} git+https://github.com/openstack/magnum-ui.git@stable/${RELEASE} git+https://github.com/openstack/neutron-vpnaas-dashboard.git@stable/${RELEASE} git+https://github.com/openstack/octavia-dashboard.git@stable/${RELEASE} git+https://github.com/openstack/senlin-dashboard.git@stable/${RELEASE} git+https://github.com/openstack/manila-ui.git@stable/${RELEASE}" - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "apache2 gettext libapache2-mod-wsgi-py3" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/horizon/patches/0000-fix-ignore-errors-when-flavors-are-deleted.patch b/images/horizon/patches/horizon/0000-fix-ignore-errors-when-flavors-are-deleted.patch similarity index 88% rename from images/horizon/patches/0000-fix-ignore-errors-when-flavors-are-deleted.patch rename to images/horizon/patches/horizon/0000-fix-ignore-errors-when-flavors-are-deleted.patch index 50d68c9b4..211d0552a 100644 --- a/images/horizon/patches/0000-fix-ignore-errors-when-flavors-are-deleted.patch +++ b/images/horizon/patches/horizon/0000-fix-ignore-errors-when-flavors-are-deleted.patch @@ -1,4 +1,4 @@ -From c62527488bfeab588c4abbc8426688e4feef87a4 Mon Sep 17 00:00:00 2001 +From aa21f4baa38fc70549b1c7341361519de6362d9b Mon Sep 17 00:00:00 2001 From: okozachenko Date: Thu, 2 Nov 2023 01:27:20 +1100 Subject: [PATCH] fix: ignore errors when flavors are deleted @@ -13,7 +13,6 @@ and refactors the code to use the same code-base. Closes-Bug: #2042362 Change-Id: I37cc02102285b1e83ec1343b710a57fb5ac4ba15 -(cherry picked from commit 40759aa9cdb9b2162b3f50df751c500db94943b3) --- .../dashboards/admin/instances/tests.py | 4 ---- .../dashboards/admin/instances/views.py | 17 +++++------------ @@ -22,10 +21,10 @@ Change-Id: I37cc02102285b1e83ec1343b710a57fb5ac4ba15 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/openstack_dashboard/dashboards/admin/instances/tests.py b/openstack_dashboard/dashboards/admin/instances/tests.py -index 3630cb79ade..c6cf65e5dab 100644 +index 3630cb79a..c6cf65e5d 100644 --- a/openstack_dashboard/dashboards/admin/instances/tests.py +++ b/openstack_dashboard/dashboards/admin/instances/tests.py -@@ -133,10 +133,6 @@ def test_index_flavor_get_exception(self): +@@ -133,10 +133,6 @@ class InstanceViewTest(test.BaseAdminViewTests): res = self.client.get(INDEX_URL) instances = res.context['table'].data self.assertTemplateUsed(res, INDEX_TEMPLATE) @@ -37,10 +36,10 @@ index 3630cb79ade..c6cf65e5dab 100644 self.assertEqual(self.mock_image_list_detailed.call_count, 4) diff --git a/openstack_dashboard/dashboards/admin/instances/views.py b/openstack_dashboard/dashboards/admin/instances/views.py -index c35527fe465..efa28dd763e 100644 +index c35527fe4..efa28dd76 100644 --- a/openstack_dashboard/dashboards/admin/instances/views.py +++ b/openstack_dashboard/dashboards/admin/instances/views.py -@@ -33,6 +33,8 @@ +@@ -33,6 +33,8 @@ from openstack_dashboard.dashboards.admin.instances \ from openstack_dashboard.dashboards.admin.instances \ import tables as project_tables from openstack_dashboard.dashboards.admin.instances import tabs @@ -49,7 +48,7 @@ index c35527fe465..efa28dd763e 100644 from openstack_dashboard.dashboards.project.instances import views from openstack_dashboard.dashboards.project.instances.workflows \ import update_instance -@@ -215,18 +217,9 @@ def get_data(self): +@@ -215,18 +217,9 @@ class AdminIndexView(tables.PagedTableMixin, tables.DataTableView): else: inst.image['name'] = _("-") @@ -72,10 +71,10 @@ index c35527fe465..efa28dd763e 100644 inst.tenant_name = getattr(tenant, "name", None) return instances diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py -index 70d32bc4b3c..c44dedd5b5a 100644 +index 5ab1b4a48..fe2f58c46 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py -@@ -316,6 +316,7 @@ def test_index_flavor_list_exception(self): +@@ -316,6 +316,7 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin): self.mock_is_feature_available.return_value = True self.mock_server_list_paged.return_value = [servers, False, False] self.mock_servers_update_addresses.return_value = None @@ -84,10 +83,10 @@ index 70d32bc4b3c..c44dedd5b5a 100644 self.mock_image_list_detailed.return_value = (self.images.list(), False, False) diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py -index badf540b830..b848f6fffd9 100644 +index badf540b8..b848f6fff 100644 --- a/openstack_dashboard/dashboards/project/instances/views.py +++ b/openstack_dashboard/dashboards/project/instances/views.py -@@ -171,14 +171,9 @@ def get_data(self): +@@ -171,14 +171,9 @@ class IndexView(tables.PagedTableMixin, tables.DataTableView): for instance in instances: self._populate_image_info(instance, image_dict, volume_dict) @@ -105,3 +104,6 @@ index badf540b830..b848f6fffd9 100644 return instances +-- +2.34.1 + diff --git a/images/horizon/patches/horizon/0001-Fixing-Incorrect-URL-when-browsing-Swift-containers.patch b/images/horizon/patches/horizon/0001-Fixing-Incorrect-URL-when-browsing-Swift-containers.patch new file mode 100644 index 000000000..2e5b936ed --- /dev/null +++ b/images/horizon/patches/horizon/0001-Fixing-Incorrect-URL-when-browsing-Swift-containers.patch @@ -0,0 +1,40 @@ +From 4aa347fe196b7b18ff0bf5f4d4f076a6c14cf12e Mon Sep 17 00:00:00 2001 +From: jeremy-boyle +Date: Sat, 24 Jun 2023 16:59:11 +0000 +Subject: [PATCH] Fixing Incorrect URL when browsing Swift containers + +This patch fixes a bug identified in the code that generates the URL for +the Swift container object. The bug caused the forward slashes (/) in the +folder parameter to be encoded as %2F instead of being included as '/' in the +resulting URL. + +To resolve this issue, the code has been updated by adding a replace() method +to replace the %2F sequences with forward slashes. The updated code ensures +that the URL generated for the folder parameter contains the correct forward +slash (/) representation. + +Closes-Bug: #2009724 +Signed-off-by: jeremy-boyle + +Change-Id: I5837e74ddcc71cda6b4686e586dbb8b1386a9cd3 +--- + .../static/dashboard/project/containers/objects.controller.js | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/containers/objects.controller.js b/openstack_dashboard/dashboards/project/static/dashboard/project/containers/objects.controller.js +index 55262a1fa..c14128cbf 100644 +--- a/openstack_dashboard/dashboards/project/static/dashboard/project/containers/objects.controller.js ++++ b/openstack_dashboard/dashboards/project/static/dashboard/project/containers/objects.controller.js +@@ -60,7 +60,8 @@ + ctrl.containerURL = containerRoute + encodeURIComponent($routeParams.container) + + ctrl.model.DELIMETER; + if (angular.isDefined($routeParams.folder)) { +- ctrl.currentURL = ctrl.containerURL + encodeURIComponent($routeParams.folder) + ++ ctrl.currentURL = ctrl.containerURL + ++ encodeURIComponent($routeParams.folder).replace(/%2F/g, '/') + + ctrl.model.DELIMETER; + } else { + ctrl.currentURL = ctrl.containerURL; +-- +2.34.1 + diff --git a/images/horizon/patches/0001-fix-disable-resizing-for-admins.patch b/images/horizon/patches/magnum-ui/0000-fix-disable-resizing-for-admins.patch similarity index 89% rename from images/horizon/patches/0001-fix-disable-resizing-for-admins.patch rename to images/horizon/patches/magnum-ui/0000-fix-disable-resizing-for-admins.patch index aaa505885..a64b453f7 100644 --- a/images/horizon/patches/0001-fix-disable-resizing-for-admins.patch +++ b/images/horizon/patches/magnum-ui/0000-fix-disable-resizing-for-admins.patch @@ -1,4 +1,4 @@ -From d3ac70fb12dc363a0fbed39bcfd3642e36f4515d Mon Sep 17 00:00:00 2001 +From a3671cc242adb85f792d1c8c57ccc7692f1ec251 Mon Sep 17 00:00:00 2001 From: Mohammed Naser Date: Mon, 20 Feb 2023 00:55:14 +0000 Subject: [PATCH] fix: disable resizing for admins @@ -11,14 +11,13 @@ This will hide the resize button for clusters that don't match the project ID of the current user. Change-Id: If09c509abdd21a5a7b9bc374af52a06404fb0ff8 -(cherry picked from commit 345f853567d25f1b163025f0295c742582052748) --- .../clusters/resize/resize.service.js | 9 ++++--- - .../clusters/resize/resize.service.spec.js | 27 ++++++++++++++----- - 2 files changed, 26 insertions(+), 10 deletions(-) + .../clusters/resize/resize.service.spec.js | 25 +++++++++++++++---- + 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js -index ebc6a961..b86833a0 100644 +index ebc6a96..b86833a 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js @@ -32,6 +32,7 @@ @@ -52,10 +51,10 @@ index ebc6a961..b86833a0 100644 function constructModalConfig(workerNodesList) { diff --git a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js -index 842df87d..27fa8064 100644 +index 842df87..645b149 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js -@@ -19,16 +19,17 @@ +@@ -19,9 +19,10 @@ describe('horizon.dashboard.container-infra.clusters.resize.service', function() { @@ -68,14 +67,6 @@ index 842df87d..27fa8064 100644 }; var modal = { open: function(config) { - deferred = $q.defer(); - deferred.resolve(config); - modalConfig = config; -- -+`` - return deferred.promise; - } - }; @@ -50,6 +51,7 @@ 'horizon.dashboard.container-infra.clusters.resize.service'); magnum = $injector.get('horizon.app.core.openstack-service-api.magnum'); @@ -110,3 +101,6 @@ index 842df87d..27fa8064 100644 }); it('should open the modal, hide the loading spinner and check the form model', +-- +2.34.1 + diff --git a/images/horizon/patches/0002-capi-avoid-going-through-heat-for-worker-list.patch b/images/horizon/patches/magnum-ui/0001-capi-avoid-going-through-heat-for-worker-list.patch similarity index 100% rename from images/horizon/patches/0002-capi-avoid-going-through-heat-for-worker-list.patch rename to images/horizon/patches/magnum-ui/0001-capi-avoid-going-through-heat-for-worker-list.patch diff --git a/images/ironic/Earthfile b/images/ironic/Earthfile index 74b2ed9ea..5edcd7c44 100644 --- a/images/ironic/Earthfile +++ b/images/ironic/Earthfile @@ -1,18 +1,21 @@ VERSION 0.7 -image: - ARG PROJECT=ironic - ARG RELEASE=zed - ARG REF=e38735cb95263b0c54f2fd719ff6b714efbddbb3 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ +ARG --global PROJECT=ironic +ARG --global RELEASE=zed +ARG --global PROJECT_REF=e38735cb95263b0c54f2fd719ff6b714efbddbb3 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ --PIP_PACKAGES "python-dracclient sushy" - DO \ - ../+APT_INSTALL \ + +image: + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "ethtool ipmitool iproute2 ipxe lshw qemu-utils tftpd-hpa" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/keystone/Earthfile b/images/keystone/Earthfile index 9478a0371..7aae428be 100644 --- a/images/keystone/Earthfile +++ b/images/keystone/Earthfile @@ -1,19 +1,22 @@ VERSION 0.7 +ARG --global RELEASE=2023.2 +ARG --global PROJECT=keystone +ARG --global PROJECT_REF=653d82b1b4e09b2ff37b56868e57d08c8e3af7dd + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --EXTRAS "[ldap]" \ + --PIP_PACKAGES "keystone-keycloak-backend==0.1.6" + image: - ARG PROJECT=keystone - ARG RELEASE=zed - ARG REF=72a4fc0f3ccf7a5ca9fc40e5364e14f881ec27b2 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "keystone-keycloak-backend==0.1.6" \ - --EXTRAS "[ldap]" - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "apache2 libapache2-mod-wsgi-py3" - DO ../+APPLY_PATCHES ARG MOD_AUTH_OPENIDC_VERSION=2.4.12.1 ARG TARGETARCH RUN \ @@ -27,4 +30,4 @@ image: rm -rfv /var/lib/apt/lists/* libapache2-mod-auth-openidc_${MOD_AUTH_OPENIDC_VERSION}-1.$(lsb_release -sc)_${TARGETARCH}.deb SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/keystone/patches/keystone/0000-Ensure-application-credentials-take-account-of-impli.patch b/images/keystone/patches/keystone/0000-Ensure-application-credentials-take-account-of-impli.patch new file mode 100644 index 000000000..83689fa23 --- /dev/null +++ b/images/keystone/patches/keystone/0000-Ensure-application-credentials-take-account-of-impli.patch @@ -0,0 +1,47 @@ +From 6ee7ea0d63fed272beb3806d722c2dd3585e8212 Mon Sep 17 00:00:00 2001 +From: Andrew Bonney +Date: Tue, 5 Sep 2023 14:56:51 +0100 +Subject: [PATCH] Ensure application credentials take account of implied roles + +Related-Bug: #2030061 +Change-Id: I2aea0b89987b24cf5ddaadeecbd06c32ad81a9bc +--- + keystone/models/token_model.py | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/keystone/models/token_model.py b/keystone/models/token_model.py +index 78146295d..b152d97c2 100644 +--- a/keystone/models/token_model.py ++++ b/keystone/models/token_model.py +@@ -429,7 +429,13 @@ class TokenModel(object): + + def _get_application_credential_roles(self): + roles = [] ++ roles_added = list() + app_cred_roles = self.application_credential['roles'] ++ app_cred_roles = [{'role_id': r['id']} for r in app_cred_roles] ++ effective_app_cred_roles = ( ++ PROVIDERS.assignment_api.add_implied_roles(app_cred_roles) ++ ) ++ + assignment_list = PROVIDERS.assignment_api.list_role_assignments( + user_id=self.user_id, + project_id=self.project_id, +@@ -437,9 +443,12 @@ class TokenModel(object): + effective=True) + user_roles = list(set([x['role_id'] for x in assignment_list])) + +- for role in app_cred_roles: +- if role['id'] in user_roles: ++ for role in effective_app_cred_roles: ++ if role['role_id'] in user_roles and \ ++ role['role_id'] not in roles_added: ++ role = PROVIDERS.role_api.get_role(role['role_id']) + roles.append({'id': role['id'], 'name': role['name']}) ++ roles_added.append(role['id']) + + return roles + +-- +2.34.1 + diff --git a/images/libvirtd/Earthfile b/images/libvirtd/Earthfile index 07c358f22..31792d22b 100644 --- a/images/libvirtd/Earthfile +++ b/images/libvirtd/Earthfile @@ -3,7 +3,6 @@ VERSION 0.7 platform-image: ARG RELEASE=zed FROM ../cloud-archive-base+image --RELEASE=${RELEASE} - LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere COPY keyrings/ceph.gpg /etc/apt/trusted.gpg.d/ IF [ "$(lsb_release -sc)" = "focal" ] RUN echo "deb http://download.ceph.com/debian-quincy/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/ceph.list diff --git a/images/magnum/Earthfile b/images/magnum/Earthfile index f7e189f53..645d99cd7 100644 --- a/images/magnum/Earthfile +++ b/images/magnum/Earthfile @@ -1,18 +1,21 @@ VERSION 0.7 +ARG --global PROJECT=magnum +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=156f6f52d38a670e6fe10725966aeea4ddf65146 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="magnum-cluster-api==0.13.3" + image: - ARG PROJECT=magnum - ARG RELEASE=zed - ARG REF=c671d8baf9d6f4705a1b832ae2d96980e5a58db6 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "magnum-cluster-api==0.13.3" - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "haproxy" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/magnum/patches/0000-containerd-cni-plugin-path-in-coreos-35.patch b/images/magnum/patches/0000-containerd-cni-plugin-path-in-coreos-35.patch deleted file mode 100644 index 8d7c4113f..000000000 --- a/images/magnum/patches/0000-containerd-cni-plugin-path-in-coreos-35.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 7f9f804a766083b65389b4cc2870fbb1a951b29e Mon Sep 17 00:00:00 2001 -From: Mohammed Naser -Date: Thu, 9 Mar 2023 09:45:43 +0100 -Subject: [PATCH] Containerd cni plugin path in CoreOS 35 (#1) - -Task: 45387 -Story: 2010041 - -In Fedora CoreOS 35 default containerd cni bin_dir is set to -/usr/libexec/cni. Since we're installing our own in /opt/cni/bin need to -override in containerd config.toml otherwise pods get stuck in -ContainerCreating state looking for for ex. calico in wrong path. - -Change-Id: I3242b718e32c92942ac471bc7e182a42e803005b -(cherry picked from commit fbfd3ce9a30fed291c96179f409821b7e016d2ba) - -Co-authored-by: Jakub Darmach ---- - .../common/templates/kubernetes/fragments/install-cri.sh | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/install-cri.sh b/magnum/drivers/common/templates/kubernetes/fragments/install-cri.sh -index f60efe47a8..61204fe47a 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/install-cri.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/install-cri.sh -@@ -10,6 +10,9 @@ ssh_cmd="ssh -F /srv/magnum/.ssh/config root@localhost" - if [ "${CONTAINER_RUNTIME}" = "containerd" ] ; then - $ssh_cmd systemctl disable docker.service docker.socket - $ssh_cmd systemctl stop docker.service docker.socket -+ if $ssh_cmd [ -f /etc/containerd/config.toml ] ; then -+ $ssh_cmd sed -i 's/bin_dir.*$/bin_dir\ =\ \""\/opt\/cni\/bin\/"\"/' /etc/containerd/config.toml -+ fi - if [ -z "${CONTAINERD_TARBALL_URL}" ] ; then - CONTAINERD_TARBALL_URL="https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/cri-containerd-cni-${CONTAINERD_VERSION}-linux-amd64.tar.gz" - fi diff --git a/images/magnum/patches/0002-support-k8s-1-24.patch b/images/magnum/patches/0002-support-k8s-1-24.patch deleted file mode 100644 index bc69c96ee..000000000 --- a/images/magnum/patches/0002-support-k8s-1-24.patch +++ /dev/null @@ -1,75 +0,0 @@ -From f25b5c0f89dcc16918d5d8636355831ce0dc4091 Mon Sep 17 00:00:00 2001 -From: Daniel Meyerholt -Date: Sat, 28 May 2022 12:43:45 +0200 -Subject: [PATCH] Support K8s 1.24+ - -Only specify dockershim options when container runtime is not containerd. -Those options were ignored in the past when using containerd but since 1.24 -kubelet refuses to start. - -Task: 45282 -Story: 2010028 - -Signed-off-by: Daniel Meyerholt -Change-Id: Ib44cc30285c8bd4219d4a45dc956696505ddd570 -(cherry picked from commit f7cd2928d6a84e869c87c333b814de76cae9a920) ---- - .../kubernetes/fragments/configure-kubernetes-master.sh | 3 ++- - .../kubernetes/fragments/configure-kubernetes-minion.sh | 3 ++- - .../notes/support-dockershim-removal-cad104d069f1a50b.yaml | 5 +++++ - 3 files changed, 9 insertions(+), 2 deletions(-) - create mode 100644 releasenotes/notes/support-dockershim-removal-cad104d069f1a50b.yaml - -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh -index 42267404a1..61ca0a7a59 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh -@@ -454,7 +454,6 @@ if [ -f /etc/sysconfig/docker ] ; then - sed -i -E 's/^OPTIONS=("|'"'"')/OPTIONS=\1'"${DOCKER_OPTIONS}"' /' /etc/sysconfig/docker - fi - --KUBELET_ARGS="${KUBELET_ARGS} --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin" - KUBELET_ARGS="${KUBELET_ARGS} --register-with-taints=node-role.kubernetes.io/master=:NoSchedule" - KUBELET_ARGS="${KUBELET_ARGS} --node-labels=magnum.openstack.org/role=${NODEGROUP_ROLE}" - KUBELET_ARGS="${KUBELET_ARGS} --node-labels=magnum.openstack.org/nodegroup=${NODEGROUP_NAME}" -@@ -503,6 +502,8 @@ if [ ${CONTAINER_RUNTIME} = "containerd" ] ; then - KUBELET_ARGS="${KUBELET_ARGS} --container-runtime=remote" - KUBELET_ARGS="${KUBELET_ARGS} --runtime-request-timeout=15m" - KUBELET_ARGS="${KUBELET_ARGS} --container-runtime-endpoint=unix:///run/containerd/containerd.sock" -+else -+ KUBELET_ARGS="${KUBELET_ARGS} --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin" - fi - - if [ -z "${KUBE_NODE_IP}" ]; then -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh -index 46055244ac..60fc1918bc 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh -@@ -282,6 +282,8 @@ if [ ${CONTAINER_RUNTIME} = "containerd" ] ; then - KUBELET_ARGS="${KUBELET_ARGS} --container-runtime=remote" - KUBELET_ARGS="${KUBELET_ARGS} --runtime-request-timeout=15m" - KUBELET_ARGS="${KUBELET_ARGS} --container-runtime-endpoint=unix:///run/containerd/containerd.sock" -+else -+ KUBELET_ARGS="${KUBELET_ARGS} --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin" - fi - - auto_healing_enabled=$(echo ${AUTO_HEALING_ENABLED} | tr '[:upper:]' '[:lower:]') -@@ -290,7 +292,6 @@ if [[ "${auto_healing_enabled}" = "true" && "${autohealing_controller}" = "drain - KUBELET_ARGS="${KUBELET_ARGS} --node-labels=draino-enabled=true" - fi - --KUBELET_ARGS="${KUBELET_ARGS} --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin" - - sed -i ' - /^KUBELET_ADDRESS=/ s/=.*/="--address=0.0.0.0"/ -diff --git a/releasenotes/notes/support-dockershim-removal-cad104d069f1a50b.yaml b/releasenotes/notes/support-dockershim-removal-cad104d069f1a50b.yaml -new file mode 100644 -index 0000000000..f228db6321 ---- /dev/null -+++ b/releasenotes/notes/support-dockershim-removal-cad104d069f1a50b.yaml -@@ -0,0 +1,5 @@ -+--- -+fixes: -+ - | -+ Support K8s 1.24 which removed support of dockershim. Needs containerd as -+ container runtime. diff --git a/images/magnum/patches/0003-fix-kubelet-for-fedora-coreos-36-to-provide-real-resolvconf-to-containers.patch b/images/magnum/patches/0003-fix-kubelet-for-fedora-coreos-36-to-provide-real-resolvconf-to-containers.patch deleted file mode 100644 index a79d935ed..000000000 --- a/images/magnum/patches/0003-fix-kubelet-for-fedora-coreos-36-to-provide-real-resolvconf-to-containers.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 34564ae02c1e7bef3b69967c7497f201058c82a5 Mon Sep 17 00:00:00 2001 -From: Dale Smith -Date: Thu, 22 Dec 2022 16:06:07 +1300 -Subject: [PATCH] Fix kubelet for Fedora CoreOS 36 to provide real resolvconf - to containers. - -In Fedora CoreOS 36 CoreDNS cannot start correctly due to a loopback issue -where /etc/resolv.conf is mounted and points to localhost. - -Tested on Fedora CoreOS 35,36,37, with Docker and containerd. - -https://coredns.io/plugins/loop/#troubleshooting-loops-in-kubernetes-clusters -https://fedoraproject.org/wiki/Changes/systemd-resolved#Detailed_Description - -Story: 2010519 -Depends-On: I3242b718e32c92942ac471bc7e182a42e803005b - -Change-Id: I8106324ce71d6c22fa99e1a84b5a09743315811a -(cherry picked from commit 5061dc5bb5c9aaba8fcfb3cb06404ada084a1908) ---- - .../kubernetes/fragments/configure-kubernetes-master.sh | 1 + - .../kubernetes/fragments/configure-kubernetes-minion.sh | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh -index 61ca0a7a59..24d7e48f4f 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-master.sh -@@ -435,6 +435,7 @@ $ssh_cmd mkdir -p /etc/kubernetes/manifests - KUBELET_ARGS="--register-node=true --pod-manifest-path=/etc/kubernetes/manifests --hostname-override=${INSTANCE_NAME}" - KUBELET_ARGS="${KUBELET_ARGS} --pod-infra-container-image=${CONTAINER_INFRA_PREFIX:-gcr.io/google_containers/}pause:3.1" - KUBELET_ARGS="${KUBELET_ARGS} --cluster_dns=${DNS_SERVICE_IP} --cluster_domain=${DNS_CLUSTER_DOMAIN}" -+KUBELET_ARGS="${KUBELET_ARGS} --resolv-conf=/run/systemd/resolve/resolv.conf" - KUBELET_ARGS="${KUBELET_ARGS} --volume-plugin-dir=/var/lib/kubelet/volumeplugins" - KUBELET_ARGS="${KUBELET_ARGS} ${KUBELET_OPTIONS}" - -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh -index 60fc1918bc..6508ac3ef0 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/configure-kubernetes-minion.sh -@@ -250,6 +250,7 @@ mkdir -p /etc/kubernetes/manifests - KUBELET_ARGS="--pod-manifest-path=/etc/kubernetes/manifests --kubeconfig ${KUBELET_KUBECONFIG} --hostname-override=${INSTANCE_NAME}" - KUBELET_ARGS="${KUBELET_ARGS} --address=${KUBE_NODE_IP} --port=10250 --read-only-port=0 --anonymous-auth=false --authorization-mode=Webhook --authentication-token-webhook=true" - KUBELET_ARGS="${KUBELET_ARGS} --cluster_dns=${DNS_SERVICE_IP} --cluster_domain=${DNS_CLUSTER_DOMAIN}" -+KUBELET_ARGS="${KUBELET_ARGS} --resolv-conf=/run/systemd/resolve/resolv.conf" - KUBELET_ARGS="${KUBELET_ARGS} --volume-plugin-dir=/var/lib/kubelet/volumeplugins" - KUBELET_ARGS="${KUBELET_ARGS} --node-labels=magnum.openstack.org/role=${NODEGROUP_ROLE}" - KUBELET_ARGS="${KUBELET_ARGS} --node-labels=magnum.openstack.org/nodegroup=${NODEGROUP_NAME}" diff --git a/images/magnum/patches/0004-adapt-cinder-csi-to-upstream-manifest.patch b/images/magnum/patches/0004-adapt-cinder-csi-to-upstream-manifest.patch deleted file mode 100644 index 7d302cf91..000000000 --- a/images/magnum/patches/0004-adapt-cinder-csi-to-upstream-manifest.patch +++ /dev/null @@ -1,860 +0,0 @@ -From b13335fc56d4938346619229bb2c23c128a1d58a Mon Sep 17 00:00:00 2001 -From: Michal Nasiadka -Date: Fri, 11 Mar 2022 13:33:15 +0100 -Subject: [PATCH] Adapt Cinder CSI to upstream manifest - -- Bump also components to upstream manifest versions. -- Add small tool to sync Cinder CSI manifests automatically - -Change-Id: Icd19b41d03b7aa200965a3357a8ddf8b4b40794a -(cherry picked from commit ac5702c40653942634e259788434037e1e8c980a) ---- - doc/source/user/index.rst | 11 + - .../kubernetes/fragments/enable-cinder-csi.sh | 237 +++++++++--------- - .../fragments/write-heat-params-master.sh | 1 + - .../drivers/heat/k8s_fedora_template_def.py | 1 + - .../templates/kubecluster.yaml | 19 +- - .../templates/kubemaster.yaml | 6 + - .../unit/drivers/test_template_definition.py | 6 + - tools/sync/cinder-csi | 162 ++++++++++++ - 8 files changed, 322 insertions(+), 121 deletions(-) - create mode 100755 tools/sync/cinder-csi - -diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst -index 20c56400f8..9d8d747204 100644 ---- a/doc/source/user/index.rst -+++ b/doc/source/user/index.rst -@@ -1400,30 +1400,35 @@ _`cinder_csi_plugin_tag` - `_. - Train default: v1.16.0 - Ussuri default: v1.18.0 -+ Yoga default: v1.23.0 - - _`csi_attacher_tag` - This label allows users to override the default container tag for CSI attacher. - For additional tags, `refer to CSI attacher page - `_. - Ussuri-default: v2.0.0 -+ Yoga-default: v3.3.0 - - _`csi_provisioner_tag` - This label allows users to override the default container tag for CSI provisioner. - For additional tags, `refer to CSI provisioner page - `_. - Ussuri-default: v1.4.0 -+ Yoga-default: v3.0.0 - - _`csi_snapshotter_tag` - This label allows users to override the default container tag for CSI snapshotter. - For additional tags, `refer to CSI snapshotter page - `_. - Ussuri-default: v1.2.2 -+ Yoga-default: v4.2.1 - - _`csi_resizer_tag` - This label allows users to override the default container tag for CSI resizer. - For additional tags, `refer to CSI resizer page - `_. - Ussuri-default: v0.3.0 -+ Yoga-default: v1.3.0 - - _`csi_node_driver_registrar_tag` - This label allows users to override the default container tag for CSI node -@@ -1431,6 +1436,12 @@ _`csi_node_driver_registrar_tag` - page - `_. - Ussuri-default: v1.1.0 -+ Yoga-default: v2.4.0 -+ -+-`csi_liveness_probe_tag` -+ This label allows users to override the default container tag for CSI -+ liveness probe. -+ Yoga-default: v2.5.0 - - _`keystone_auth_enabled` - If this label is set to True, Kubernetes will support use Keystone for -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/enable-cinder-csi.sh b/magnum/drivers/common/templates/kubernetes/fragments/enable-cinder-csi.sh -index b85258a5f3..524b5e98ed 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/enable-cinder-csi.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/enable-cinder-csi.sh -@@ -12,15 +12,15 @@ if [ "${volume_driver}" = "cinder" ] && [ "${cinder_csi_enabled}" = "true" ]; th - echo "Writing File: $CINDER_CSI_DEPLOY" - mkdir -p $(dirname ${CINDER_CSI_DEPLOY}) - cat << EOF > ${CINDER_CSI_DEPLOY} ----- - # This YAML file contains RBAC API objects, - # which are necessary to run csi controller plugin ----- -+ - apiVersion: v1 - kind: ServiceAccount - metadata: - name: csi-cinder-controller-sa - namespace: kube-system -+ - --- - # external attacher - kind: ClusterRole -@@ -30,16 +30,20 @@ metadata: - rules: - - apiGroups: [""] - resources: ["persistentvolumes"] -- verbs: ["get", "list", "watch", "update", "patch"] -- - apiGroups: [""] -- resources: ["nodes"] -+ verbs: ["get", "list", "watch", "patch"] -+ - apiGroups: ["storage.k8s.io"] -+ resources: ["csinodes"] - verbs: ["get", "list", "watch"] - - apiGroups: ["storage.k8s.io"] - resources: ["volumeattachments"] -- verbs: ["get", "list", "watch", "update", "patch"] -+ verbs: ["get", "list", "watch", "patch"] - - apiGroups: ["storage.k8s.io"] -- resources: ["csinodes"] -- verbs: ["get", "list", "watch"] -+ resources: ["volumeattachments/status"] -+ verbs: ["patch"] -+ - apiGroups: ["coordination.k8s.io"] -+ resources: ["leases"] -+ verbs: ["get", "watch", "list", "delete", "update", "create"] -+ - --- - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 -@@ -53,6 +57,7 @@ roleRef: - kind: ClusterRole - name: csi-attacher-role - apiGroup: rbac.authorization.k8s.io -+ - --- - # external Provisioner - kind: ClusterRole -@@ -84,6 +89,12 @@ rules: - - apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotcontents"] - verbs: ["get", "list"] -+ - apiGroups: ["storage.k8s.io"] -+ resources: ["volumeattachments"] -+ verbs: ["get", "list", "watch"] -+ - apiGroups: ["coordination.k8s.io"] -+ resources: ["leases"] -+ verbs: ["get", "watch", "list", "delete", "update", "create"] - --- - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 -@@ -97,6 +108,7 @@ roleRef: - kind: ClusterRole - name: csi-provisioner-role - apiGroup: rbac.authorization.k8s.io -+ - --- - # external snapshotter - kind: ClusterRole -@@ -104,36 +116,28 @@ apiVersion: rbac.authorization.k8s.io/v1 - metadata: - name: csi-snapshotter-role - rules: -- - apiGroups: [""] -- resources: ["persistentvolumes"] -- verbs: ["get", "list", "watch"] -- - apiGroups: [""] -- resources: ["persistentvolumeclaims"] -- verbs: ["get", "list", "watch"] -- - apiGroups: ["storage.k8s.io"] -- resources: ["storageclasses"] -- verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] -- - apiGroups: [""] -- resources: ["secrets"] -- verbs: ["get", "list"] -+ # Secret permission is optional. -+ # Enable it if your driver needs secret. -+ # For example, `csi.storage.k8s.io/snapshotter-secret-name` is set in VolumeSnapshotClass. -+ # See https://kubernetes-csi.github.io/docs/secrets-and-credentials.html for more details. -+ # - apiGroups: [""] -+ # resources: ["secrets"] -+ # verbs: ["get", "list"] - - apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotcontents"] -- verbs: ["create", "get", "list", "watch", "update", "delete"] -+ verbs: ["create", "get", "list", "watch", "update", "delete", "patch"] - - apiGroups: ["snapshot.storage.k8s.io"] -- resources: ["volumesnapshots"] -- verbs: ["get", "list", "watch", "update"] -- - apiGroups: ["snapshot.storage.k8s.io"] -- resources: ["volumesnapshots/status"] -- verbs: ["update"] -- - apiGroups: ["apiextensions.k8s.io"] -- resources: ["customresourcedefinitions"] -- verbs: ["create", "list", "watch", "delete"] -+ resources: ["volumesnapshotcontents/status"] -+ verbs: ["update", "patch"] -+ - apiGroups: ["coordination.k8s.io"] -+ resources: ["leases"] -+ verbs: ["get", "watch", "list", "delete", "update", "create"] - --- - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 -@@ -148,6 +152,7 @@ roleRef: - name: csi-snapshotter-role - apiGroup: rbac.authorization.k8s.io - --- -+ - # External Resizer - kind: ClusterRole - apiVersion: rbac.authorization.k8s.io/v1 -@@ -161,19 +166,22 @@ rules: - # verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["persistentvolumes"] -- verbs: ["get", "list", "watch", "update", "patch"] -+ verbs: ["get", "list", "watch", "patch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] -- resources: ["persistentvolumeclaims/status"] -- verbs: ["update", "patch"] -- - apiGroups: ["storage.k8s.io"] -- resources: ["storageclasses"] -+ resources: ["pods"] - verbs: ["get", "list", "watch"] -+ - apiGroups: [""] -+ resources: ["persistentvolumeclaims/status"] -+ verbs: ["patch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] -+ - apiGroups: ["coordination.k8s.io"] -+ resources: ["leases"] -+ verbs: ["get", "watch", "list", "delete", "update", "create"] - --- - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 -@@ -187,56 +195,24 @@ roleRef: - kind: ClusterRole - name: csi-resizer-role - apiGroup: rbac.authorization.k8s.io ----- --kind: Role --apiVersion: rbac.authorization.k8s.io/v1 --metadata: -- namespace: kube-system -- name: external-resizer-cfg --rules: --- apiGroups: ["coordination.k8s.io"] -- resources: ["leases"] -- verbs: ["get", "watch", "list", "delete", "update", "create"] ----- --kind: RoleBinding --apiVersion: rbac.authorization.k8s.io/v1 --metadata: -- name: csi-resizer-role-cfg -- namespace: kube-system --subjects: -- - kind: ServiceAccount -- name: csi-cinder-controller-sa -- namespace: kube-system --roleRef: -- kind: Role -- name: external-resizer-cfg -- apiGroup: rbac.authorization.k8s.io -+ - --- - # This YAML file contains CSI Controller Plugin Sidecars - # external-attacher, external-provisioner, external-snapshotter ----- --kind: Service --apiVersion: v1 --metadata: -- name: csi-cinder-controller-service -- namespace: kube-system -- labels: -- app: csi-cinder-controllerplugin --spec: -- selector: -- app: csi-cinder-controllerplugin -- ports: -- - name: dummy -- port: 12345 ----- --kind: StatefulSet -+# external-resize, liveness-probe -+ -+kind: Deployment - apiVersion: apps/v1 - metadata: - name: csi-cinder-controllerplugin - namespace: kube-system - spec: -- serviceName: "csi-cinder-controller-service" - replicas: 1 -+ strategy: -+ type: RollingUpdate -+ rollingUpdate: -+ maxUnavailable: 0 -+ maxSurge: 1 - selector: - matchLabels: - app: csi-cinder-controllerplugin -@@ -246,6 +222,7 @@ spec: - app: csi-cinder-controllerplugin - spec: - serviceAccount: csi-cinder-controller-sa -+ hostNetwork: true - tolerations: - # Make sure the pod can be scheduled on master kubelet. - - effect: NoSchedule -@@ -257,11 +234,11 @@ spec: - node-role.kubernetes.io/master: "" - containers: - - name: csi-attacher -- image: ${CONTAINER_INFRA_PREFIX:-quay.io/k8scsi/}csi-attacher:${CSI_ATTACHER_TAG} -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}csi-attacher:${CSI_ATTACHER_TAG} - args: -- - "--v=5" - - "--csi-address=\$(ADDRESS)" - - "--timeout=3m" -+ - "--leader-election=true" - resources: - requests: - cpu: 20m -@@ -273,10 +250,14 @@ spec: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-provisioner -- image: ${CONTAINER_INFRA_PREFIX:-quay.io/k8scsi/}csi-provisioner:${CSI_PROVISIONER_TAG} -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}csi-provisioner:${CSI_PROVISIONER_TAG} - args: - - "--csi-address=\$(ADDRESS)" - - "--timeout=3m" -+ - "--default-fstype=ext4" -+ - "--feature-gates=Topology=true" -+ - "--extra-create-metadata" -+ - "--leader-election=true" - resources: - requests: - cpu: 20m -@@ -288,9 +269,12 @@ spec: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-snapshotter -- image: ${CONTAINER_INFRA_PREFIX:-quay.io/k8scsi/}csi-snapshotter:${CSI_SNAPSHOTTER_TAG} -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}csi-snapshotter:${CSI_SNAPSHOTTER_TAG} - args: - - "--csi-address=\$(ADDRESS)" -+ - "--timeout=3m" -+ - "--extra-create-metadata" -+ - "--leader-election=true" - resources: - requests: - cpu: 20m -@@ -302,10 +286,12 @@ spec: - - mountPath: /var/lib/csi/sockets/pluginproxy/ - name: socket-dir - - name: csi-resizer -- image: ${CONTAINER_INFRA_PREFIX:-quay.io/k8scsi/}csi-resizer:${CSI_RESIZER_TAG} -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}csi-resizer:${CSI_RESIZER_TAG} - args: -- - "--v=5" - - "--csi-address=\$(ADDRESS)" -+ - "--timeout=3m" -+ - "--handle-volume-inuse-error=false" -+ - "--leader-election=true" - resources: - requests: - cpu: 20m -@@ -316,22 +302,27 @@ spec: - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ -+ - name: liveness-probe -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}livenessprobe:${CSI_LIVENESS_PROBE_TAG} -+ args: -+ - "--csi-address=\$(ADDRESS)" -+ resources: -+ requests: -+ cpu: 20m -+ env: -+ - name: ADDRESS -+ value: /var/lib/csi/sockets/pluginproxy/csi.sock -+ volumeMounts: -+ - mountPath: /var/lib/csi/sockets/pluginproxy/ -+ name: socket-dir - - name: cinder-csi-plugin - image: ${CONTAINER_INFRA_PREFIX:-docker.io/k8scloudprovider/}cinder-csi-plugin:${CINDER_CSI_PLUGIN_TAG} -- args : -+ args: - - /bin/cinder-csi-plugin -- - "--nodeid=\$(NODE_ID)" - - "--endpoint=\$(CSI_ENDPOINT)" - - "--cloud-config=\$(CLOUD_CONFIG)" - - "--cluster=\$(CLUSTER_NAME)" -- resources: -- requests: -- cpu: 20m - env: -- - name: NODE_ID -- valueFrom: -- fieldRef: -- fieldPath: spec.nodeName - - name: CSI_ENDPOINT - value: unix://csi/csi.sock - - name: CLOUD_CONFIG -@@ -339,6 +330,19 @@ spec: - - name: CLUSTER_NAME - value: kubernetes - imagePullPolicy: "IfNotPresent" -+ ports: -+ - containerPort: 9808 -+ name: healthz -+ protocol: TCP -+ # The probe -+ livenessProbe: -+ failureThreshold: 5 -+ httpGet: -+ path: /healthz -+ port: healthz -+ initialDelaySeconds: 10 -+ timeoutSeconds: 10 -+ periodSeconds: 60 - volumeMounts: - - name: socket-dir - mountPath: /csi -@@ -360,7 +364,7 @@ spec: - type: File - --- - # This YAML defines all API objects to create RBAC roles for csi node plugin. ----- -+ - apiVersion: v1 - kind: ServiceAccount - metadata: -@@ -375,6 +379,7 @@ rules: - - apiGroups: [""] - resources: ["events"] - verbs: ["get", "list", "watch", "create", "update", "patch"] -+ - --- - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 -@@ -391,7 +396,7 @@ roleRef: - --- - # This YAML file contains driver-registrar & csi driver nodeplugin API objects, - # which are necessary to run csi nodeplugin for cinder. ----- -+ - kind: DaemonSet - apiVersion: apps/v1 - metadata: -@@ -412,17 +417,10 @@ spec: - hostNetwork: true - containers: - - name: node-driver-registrar -- image: ${CONTAINER_INFRA_PREFIX:-quay.io/k8scsi/}csi-node-driver-registrar:${CSI_NODE_DRIVER_REGISTRAR_TAG} -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}csi-node-driver-registrar:${CSI_NODE_DRIVER_REGISTRAR_TAG} - args: - - "--csi-address=\$(ADDRESS)" - - "--kubelet-registration-path=\$(DRIVER_REG_SOCK_PATH)" -- resources: -- requests: -- cpu: 25m -- lifecycle: -- preStop: -- exec: -- command: ["/bin/sh", "-c", "rm -rf /registration/cinder.csi.openstack.org /registration/cinder.csi.openstack.org-reg.sock"] - env: - - name: ADDRESS - value: /csi/csi.sock -@@ -438,6 +436,16 @@ spec: - mountPath: /csi - - name: registration-dir - mountPath: /registration -+ - name: liveness-probe -+ image: ${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}livenessprobe:${CSI_LIVENESS_PROBE_TAG} -+ args: -+ - --csi-address=/csi/csi.sock -+ resources: -+ requests: -+ cpu: 20m -+ volumeMounts: -+ - name: socket-dir -+ mountPath: /csi - - name: cinder-csi-plugin - securityContext: - privileged: true -@@ -445,33 +453,35 @@ spec: - add: ["SYS_ADMIN"] - allowPrivilegeEscalation: true - image: ${CONTAINER_INFRA_PREFIX:-docker.io/k8scloudprovider/}cinder-csi-plugin:${CINDER_CSI_PLUGIN_TAG} -- args : -+ args: - - /bin/cinder-csi-plugin -- - "--nodeid=\$(NODE_ID)" - - "--endpoint=\$(CSI_ENDPOINT)" - - "--cloud-config=\$(CLOUD_CONFIG)" -- resources: -- requests: -- cpu: 25m - env: -- - name: NODE_ID -- valueFrom: -- fieldRef: -- fieldPath: spec.nodeName - - name: CSI_ENDPOINT - value: unix://csi/csi.sock - - name: CLOUD_CONFIG - value: /etc/config/cloud-config - imagePullPolicy: "IfNotPresent" -+ ports: -+ - containerPort: 9808 -+ name: healthz -+ protocol: TCP -+ # The probe -+ livenessProbe: -+ failureThreshold: 5 -+ httpGet: -+ path: /healthz -+ port: healthz -+ initialDelaySeconds: 10 -+ timeoutSeconds: 3 -+ periodSeconds: 10 - volumeMounts: - - name: socket-dir - mountPath: /csi - - name: kubelet-dir - mountPath: /var/lib/kubelet - mountPropagation: "Bidirectional" -- - name: pods-cloud-data -- mountPath: /var/lib/cloud/data -- readOnly: true - - name: pods-probe-dir - mountPath: /dev - mountPropagation: "HostToContainer" -@@ -494,9 +504,6 @@ spec: - hostPath: - path: /var/lib/kubelet - type: Directory -- - name: pods-cloud-data -- hostPath: -- path: /var/lib/cloud/data - - name: pods-probe-dir - hostPath: - path: /dev -diff --git a/magnum/drivers/common/templates/kubernetes/fragments/write-heat-params-master.sh b/magnum/drivers/common/templates/kubernetes/fragments/write-heat-params-master.sh -index a50b184558..0cd02bf95b 100644 ---- a/magnum/drivers/common/templates/kubernetes/fragments/write-heat-params-master.sh -+++ b/magnum/drivers/common/templates/kubernetes/fragments/write-heat-params-master.sh -@@ -143,6 +143,7 @@ CSI_PROVISIONER_TAG="$CSI_PROVISIONER_TAG" - CSI_SNAPSHOTTER_TAG="$CSI_SNAPSHOTTER_TAG" - CSI_RESIZER_TAG="$CSI_RESIZER_TAG" - CSI_NODE_DRIVER_REGISTRAR_TAG="$CSI_NODE_DRIVER_REGISTRAR_TAG" -+CSI_LIVENESS_PROBE_TAG="$CSI_LIVENESS_PROBE_TAG" - DRAINO_TAG="$DRAINO_TAG" - MAGNUM_AUTO_HEALER_TAG="$MAGNUM_AUTO_HEALER_TAG" - AUTOSCALER_TAG="$AUTOSCALER_TAG" -diff --git a/magnum/drivers/heat/k8s_fedora_template_def.py b/magnum/drivers/heat/k8s_fedora_template_def.py -index 659069bc28..a4ec6250ab 100644 ---- a/magnum/drivers/heat/k8s_fedora_template_def.py -+++ b/magnum/drivers/heat/k8s_fedora_template_def.py -@@ -90,6 +90,7 @@ def get_params(self, context, cluster_template, cluster, **kwargs): - 'csi_attacher_tag', 'csi_provisioner_tag', - 'csi_snapshotter_tag', 'csi_resizer_tag', - 'csi_node_driver_registrar_tag', -+ 'csi_liveness_probe_tag', - 'etcd_tag', 'flannel_tag', 'flannel_cni_tag', - 'cloud_provider_tag', - 'prometheus_tag', 'grafana_tag', -diff --git a/magnum/drivers/k8s_fedora_coreos_v1/templates/kubecluster.yaml b/magnum/drivers/k8s_fedora_coreos_v1/templates/kubecluster.yaml -index 35ca781d42..15bfd9af25 100644 ---- a/magnum/drivers/k8s_fedora_coreos_v1/templates/kubecluster.yaml -+++ b/magnum/drivers/k8s_fedora_coreos_v1/templates/kubecluster.yaml -@@ -866,32 +866,38 @@ parameters: - description: tag of cinder csi plugin - tag of the k8scloudprovider/cinder-csi-plugin container - https://hub.docker.com/r/k8scloudprovider/cinder-csi-plugin/tags/ -- default: v1.18.0 -+ default: v1.23.0 - - csi_attacher_tag: - type: string - description: tag of csi attacher -- default: v2.0.0 -+ default: v3.3.0 - - csi_provisioner_tag: - type: string - description: tag of csi provisioner -- default: v1.4.0 -+ default: v3.0.0 - - csi_snapshotter_tag: - type: string - description: tag of csi snapshotter -- default: v1.2.2 -+ default: v4.2.1 - - csi_resizer_tag: - type: string - description: tag of csi resizer -- default: v0.3.0 -+ default: v1.3.0 - - csi_node_driver_registrar_tag: - type: string - description: tag of csi node driver registrar -- default: v1.1.0 -+ default: v2.4.0 -+ -+ csi_liveness_probe_tag: -+ type: string -+ description: tag of cinder csi liveness probe -+ tag of the k8s.gcr.io/sig-storage/liveness-probe container -+ default: v2.5.0 - - node_problem_detector_tag: - type: string -@@ -1384,6 +1390,7 @@ resources: - csi_snapshotter_tag: {get_param: csi_snapshotter_tag} - csi_resizer_tag: {get_param: csi_resizer_tag} - csi_node_driver_registrar_tag: {get_param: csi_node_driver_registrar_tag} -+ csi_liveness_probe_tag: {get_param: csi_liveness_probe_tag} - draino_tag: {get_param: draino_tag} - autoscaler_tag: {get_param: autoscaler_tag} - min_node_count: {get_param: min_node_count} -diff --git a/magnum/drivers/k8s_fedora_coreos_v1/templates/kubemaster.yaml b/magnum/drivers/k8s_fedora_coreos_v1/templates/kubemaster.yaml -index a038f144d0..917f010db8 100644 ---- a/magnum/drivers/k8s_fedora_coreos_v1/templates/kubemaster.yaml -+++ b/magnum/drivers/k8s_fedora_coreos_v1/templates/kubemaster.yaml -@@ -621,6 +621,11 @@ parameters: - type: string - description: tag of csi node driver registrar - -+ csi_liveness_probe_tag: -+ type: string -+ description: > -+ Tag of liveness-probe for cinder csi. -+ - node_problem_detector_tag: - type: string - description: tag of the node problem detector container -@@ -910,6 +915,7 @@ resources: - "$CSI_SNAPSHOTTER_TAG": {get_param: csi_snapshotter_tag} - "$CSI_RESIZER_TAG": {get_param: csi_resizer_tag} - "$CSI_NODE_DRIVER_REGISTRAR_TAG": {get_param: csi_node_driver_registrar_tag} -+ "$CSI_LIVENESS_PROBE_TAG": {get_param: csi_liveness_probe_tag} - "$DRAINO_TAG": {get_param: draino_tag} - "$AUTOSCALER_TAG": {get_param: autoscaler_tag} - "$MIN_NODE_COUNT": {get_param: min_node_count} -diff --git a/magnum/tests/unit/drivers/test_template_definition.py b/magnum/tests/unit/drivers/test_template_definition.py -index b523744597..7b08196bf1 100644 ---- a/magnum/tests/unit/drivers/test_template_definition.py -+++ b/magnum/tests/unit/drivers/test_template_definition.py -@@ -600,6 +600,8 @@ def test_k8s_get_params(self, mock_generate_csr_and_key, - 'csi_resizer_tag') - csi_node_driver_registrar_tag = mock_cluster.labels.get( - 'csi_node_driver_registrar_tag') -+ csi_liveness_probe_tag = mock_cluster.labels.get( -+ 'csi_liveness_probe_tag') - draino_tag = mock_cluster.labels.get('draino_tag') - autoscaler_tag = mock_cluster.labels.get('autoscaler_tag') - min_node_count = mock_cluster.labels.get('min_node_count') -@@ -725,6 +727,7 @@ def test_k8s_get_params(self, mock_generate_csr_and_key, - 'csi_snapshotter_tag': csi_snapshotter_tag, - 'csi_resizer_tag': csi_resizer_tag, - 'csi_node_driver_registrar_tag': csi_node_driver_registrar_tag, -+ 'csi_liveness_probe_tag': csi_liveness_probe_tag, - 'draino_tag': draino_tag, - 'autoscaler_tag': autoscaler_tag, - 'min_node_count': min_node_count, -@@ -1161,6 +1164,8 @@ def test_k8s_get_params_insecure(self, mock_generate_csr_and_key, - 'csi_resizer_tag') - csi_node_driver_registrar_tag = mock_cluster.labels.get( - 'csi_node_driver_registrar_tag') -+ csi_liveness_probe_tag = mock_cluster.labels.get( -+ 'csi_liveness_probe_tag') - draino_tag = mock_cluster.labels.get('draino_tag') - autoscaler_tag = mock_cluster.labels.get('autoscaler_tag') - min_node_count = mock_cluster.labels.get('min_node_count') -@@ -1290,6 +1295,7 @@ def test_k8s_get_params_insecure(self, mock_generate_csr_and_key, - 'csi_snapshotter_tag': csi_snapshotter_tag, - 'csi_resizer_tag': csi_resizer_tag, - 'csi_node_driver_registrar_tag': csi_node_driver_registrar_tag, -+ 'csi_liveness_probe_tag': csi_liveness_probe_tag, - 'draino_tag': draino_tag, - 'autoscaler_tag': autoscaler_tag, - 'min_node_count': min_node_count, -diff --git a/tools/sync/cinder-csi b/tools/sync/cinder-csi -new file mode 100755 -index 0000000000..5789631d52 ---- /dev/null -+++ b/tools/sync/cinder-csi -@@ -0,0 +1,162 @@ -+#!/usr/bin/env python3.9 -+ -+import requests -+ -+manifest_data = [] -+ -+files = requests.get("https://api.github.com/repos/kubernetes/cloud-provider-openstack/contents/manifests/cinder-csi-plugin").json() -+for file in files: -+ if file['name'] == 'csi-secret-cinderplugin.yaml': -+ continue -+ -+ r = requests.get(file['download_url']) -+ manifest_data.append(r.text) -+ -+manifests = "---\n".join(manifest_data) -+ -+# Clean-ups -+manifests = manifests.replace( -+""" -+ # - name: cacert -+ # mountPath: /etc/cacert -+ # readOnly: true -+""", -+""" -+ - name: cacert -+ mountPath: /etc/kubernetes/ca-bundle.crt -+ readOnly: true -+""").replace( -+""" -+ secretName: cloud-config -+ # - name: cacert -+ # hostPath: -+ # path: /etc/cacert -+""", -+""" -+ secretName: cinder-csi-cloud-config -+ - name: cacert -+ hostPath: -+ path: /etc/kubernetes/ca-bundle.crt -+ type: File -+""").replace( -+""" -+ serviceAccount: csi-cinder-controller-sa -+""", -+""" -+ serviceAccount: csi-cinder-controller-sa -+ hostNetwork: true -+ tolerations: -+ # Make sure the pod can be scheduled on master kubelet. -+ - effect: NoSchedule -+ operator: Exists -+ # Mark the pod as a critical add-on for rescheduling. -+ - key: CriticalAddonsOnly -+ operator: Exists -+ nodeSelector: -+ node-role.kubernetes.io/master: "" -+""").replace( -+""" -+ - --csi-address=/csi/csi.sock -+""", -+""" -+ - --csi-address=/csi/csi.sock -+ resources: -+ requests: -+ cpu: 20m -+""").replace( -+""" -+ env: -+ - name: ADDRESS -+ value: /var/lib/csi/sockets/pluginproxy/csi.sock -+""", -+""" -+ resources: -+ requests: -+ cpu: 20m -+ env: -+ - name: ADDRESS -+ value: /var/lib/csi/sockets/pluginproxy/csi.sock -+""").replace( -+ "$(", -+ "\$(" -+).replace( -+ "k8s.gcr.io/sig-storage/", -+ "${CONTAINER_INFRA_PREFIX:-k8s.gcr.io/sig-storage/}" -+).replace( -+ "docker.io/k8scloudprovider/", -+ "${CONTAINER_INFRA_PREFIX:-docker.io/k8scloudprovider/}", -+).replace( -+ "csi-attacher:v3.4.0", -+ "csi-attacher:${CSI_ATTACHER_TAG}", -+).replace( -+ "csi-provisioner:v3.1.0", -+ "csi-provisioner:${CSI_PROVISIONER_TAG}", -+).replace( -+ "csi-snapshotter:v6.0.1", -+ "csi-snapshotter:${CSI_SNAPSHOTTER_TAG}", -+).replace( -+ "csi-resizer:v1.4.0", -+ "csi-resizer:${CSI_RESIZER_TAG}", -+).replace( -+ "livenessprobe:v2.7.0", -+ "livenessprobe:${CSI_LIVENESS_PROBE_TAG}", -+).replace( -+ "cinder-csi-plugin:latest", -+ "cinder-csi-plugin:${CINDER_CSI_PLUGIN_TAG}", -+).replace( -+ "csi-node-driver-registrar:v2.5.1", -+ "csi-node-driver-registrar:${CSI_NODE_DRIVER_REGISTRAR_TAG}", -+).replace( -+ "/etc/config/cloud.conf", -+ "/etc/config/cloud-config" -+) -+ -+template = f"""step="enable-cinder-csi" -+printf "Starting to run ${{step}}\\n" -+ -+. /etc/sysconfig/heat-params -+ -+volume_driver=$(echo "${{VOLUME_DRIVER}}" | tr '[:upper:]' '[:lower:]') -+cinder_csi_enabled=$(echo $CINDER_CSI_ENABLED | tr '[:upper:]' '[:lower:]') -+ -+if [ "${{volume_driver}}" = "cinder" ] && [ "${{cinder_csi_enabled}}" = "true" ]; then -+ # Generate Cinder CSI manifest file -+ CINDER_CSI_DEPLOY=/srv/magnum/kubernetes/manifests/cinder-csi.yaml -+ echo "Writing File: $CINDER_CSI_DEPLOY" -+ mkdir -p $(dirname ${{CINDER_CSI_DEPLOY}}) -+ cat << EOF > ${{CINDER_CSI_DEPLOY}} -+{manifests.strip()} -+EOF -+ -+ echo "Waiting for Kubernetes API..." -+ until [ "ok" = "$(kubectl get --raw='/healthz')" ] -+ do -+ sleep 5 -+ done -+ -+ cat < -Date: Tue, 11 Jul 2023 05:40:01 -0700 -Subject: [PATCH] Secure Rbac (#10) - -* Support enables rbac policies new defaults - -The Magnum service allow enables policies (RBAC) new defaults and scope by -default. The Default value of config options ``[oslo_policy] enforce_scope`` -and ``[oslo_policy] oslo_policy.enforce_new_defaults`` are both to -``False``, but will change to ``True`` in following cycles. - -To enable them then modify the below config options value in -``magnum.conf`` file:: - - [oslo_policy] - enforce_new_defaults=True - enforce_scope=True - -reference tc goal for more detail: -https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html - -Related blueprint secure-rbac - -Change-Id: I249942a355577c4f1ef51b3988f0cc4979959d0b - -* Allow Admin to perform all API requests - -This propose changes is base on same concerns as this bug in neutron -https://bugs.launchpad.net/neutron/+bug/1997089 - -This propose to keep and make sure ADMIN can perform all API requests. - -Change-Id: I9a3003963bf13a591cc363fa04ec8e5719ae9114 - -* Add policies unit tests (Part one) - -Add plicies unit test base function -and tests for federation, quotas and stats. - -Change-Id: I0eb12bf77e0e786652e674c787b2821415bd4506 - -* Add policies unit tests (Part two) - -Add plicies unit test base function -and tests for certificate, and magnum service. - -Change-Id: Ib4047cb5a84647ff2848f06de71181673cc0627a - -* Add policies unit tests (Part three) - -Add plicies unit test base function -and tests for cluster, cluster template, and nodegroup. - -Change-Id: I0555e557725b02f3ec9812f0adf84d283f7389b0 ---- - magnum/api/hooks.py | 8 +- - magnum/common/context.py | 12 +- - magnum/common/policies/base.py | 169 +++++++++++++++++- - magnum/common/policies/certificate.py | 11 +- - magnum/common/policies/cluster.py | 27 ++- - magnum/common/policies/cluster_template.py | 20 ++- - magnum/common/policies/federation.py | 18 +- - magnum/common/policies/nodegroup.py | 15 +- - magnum/common/policies/quota.py | 3 +- - magnum/common/policies/stats.py | 3 +- - magnum/common/policy.py | 12 +- - magnum/tests/fakes.py | 2 +- - magnum/tests/unit/api/base.py | 16 ++ - .../tests/unit/api/controllers/test_root.py | 4 +- - .../api/controllers/v1/test_certificate.py | 23 ++- - .../unit/api/controllers/v1/test_cluster.py | 34 ++-- - .../controllers/v1/test_cluster_actions.py | 48 +++-- - .../unit/api/controllers/v1/test_nodegroup.py | 12 +- - .../unit/api/controllers/v1/test_quota.py | 2 +- - .../unit/api/controllers/v1/test_stats.py | 15 +- - magnum/tests/unit/api/test_hooks.py | 10 +- - magnum/tests/unit/common/policies/__init__.py | 0 - magnum/tests/unit/common/policies/base.py | 37 ++++ - .../policies/test_certificate_policy.py | 72 ++++++++ - .../common/policies/test_cluster_policy.py | 65 +++++++ - .../policies/test_cluster_template_policy.py | 74 ++++++++ - .../common/policies/test_federation_policy.py | 67 +++++++ - .../policies/test_magnum_service_policy.py | 26 +++ - .../common/policies/test_nodegroup_policy.py | 74 ++++++++ - .../unit/common/policies/test_quota_policy.py | 74 ++++++++ - .../unit/common/policies/test_stats_policy.py | 33 ++++ - magnum/tests/unit/common/test_context.py | 43 ++--- - ...dmin_perform_acitons-cc988655bb72b3f3.yaml | 9 + - ...ope-and-new-defaults-7e6e503f74283071.yaml | 13 ++ - 36 files changed, 943 insertions(+), 124 deletions(-) - create mode 100644 magnum/tests/unit/common/policies/__init__.py - create mode 100644 magnum/tests/unit/common/policies/base.py - create mode 100644 magnum/tests/unit/common/policies/test_certificate_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_cluster_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_cluster_template_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_federation_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_magnum_service_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_nodegroup_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_quota_policy.py - create mode 100644 magnum/tests/unit/common/policies/test_stats_policy.py - create mode 100644 releasenotes/notes/allow_admin_perform_acitons-cc988655bb72b3f3.yaml - create mode 100644 releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml - -diff --git a/magnum/api/hooks.py b/magnum/api/hooks.py -index e0d36a9a88..f5a9049795 100644 ---- a/magnum/api/hooks.py -+++ b/magnum/api/hooks.py -@@ -52,8 +52,8 @@ def before(self, state): - user_id = headers.get('X-User-Id') - project = headers.get('X-Project-Name') - project_id = headers.get('X-Project-Id') -- domain_id = headers.get('X-User-Domain-Id') -- domain_name = headers.get('X-User-Domain-Name') -+ user_domain_id = headers.get('X-User-Domain-Id') -+ user_domain_name = headers.get('X-User-Domain-Name') - auth_token = headers.get('X-Auth-Token') - roles = headers.get('X-Roles', '').split(',') - auth_token_info = state.request.environ.get('keystone.token_info') -@@ -72,8 +72,8 @@ def before(self, state): - user_id=user_id, - project_name=project, - project_id=project_id, -- domain_id=domain_id, -- domain_name=domain_name, -+ user_domain_id=user_domain_id, -+ user_domain_name=user_domain_name, - roles=roles) - - -diff --git a/magnum/common/context.py b/magnum/common/context.py -index 547c9cc9b4..c2c3be1e23 100644 ---- a/magnum/common/context.py -+++ b/magnum/common/context.py -@@ -42,7 +42,7 @@ def __init__(self, auth_token=None, auth_url=None, domain_id=None, - """ - super(RequestContext, self).__init__(auth_token=auth_token, - user_id=user_name, -- project_id=project_name, -+ project_id=project_id, - is_admin=is_admin, - read_only=read_only, - show_deleted=show_deleted, -@@ -53,8 +53,12 @@ def __init__(self, auth_token=None, auth_url=None, domain_id=None, - self.user_id = user_id - self.project_name = project_name - self.project_id = project_id -- self.domain_id = domain_id -- self.domain_name = domain_name -+ # (ricolin) Rmove domain_id because oslo_policy use this args to -+ # judge if this request is a domain scope or not. We might be consider -+ # bring this back only if that judge in oslo_policy is no longer affect -+ # project scope enforce. -+ # self.domain_id = domain_id -+ # self.domain_name = domain_name - self.user_domain_id = user_domain_id - self.user_domain_name = user_domain_name - self.auth_url = auth_url -@@ -71,8 +75,6 @@ def to_dict(self): - value = super(RequestContext, self).to_dict() - value.update({'auth_token': self.auth_token, - 'auth_url': self.auth_url, -- 'domain_id': self.domain_id, -- 'domain_name': self.domain_name, - 'user_domain_id': self.user_domain_id, - 'user_domain_name': self.user_domain_name, - 'user_name': self.user_name, -diff --git a/magnum/common/policies/base.py b/magnum/common/policies/base.py -index 44c75b7daf..05ac11728b 100644 ---- a/magnum/common/policies/base.py -+++ b/magnum/common/policies/base.py -@@ -13,12 +13,79 @@ - # under the License. - from oslo_policy import policy - --ROLE_ADMIN = 'rule:context_is_admin' -+ - RULE_ADMIN_OR_OWNER = 'rule:admin_or_owner' --RULE_ADMIN_API = 'rule:admin_api' -+RULE_ADMIN_API = 'rule:context_is_admin' - RULE_ADMIN_OR_USER = 'rule:admin_or_user' - RULE_CLUSTER_USER = 'rule:cluster_user' - RULE_DENY_CLUSTER_USER = 'rule:deny_cluster_user' -+RULE_USER = "rule:is_user" -+# Generic check string for checking if a user is authorized on a particular -+# project, specifically with the member role. -+RULE_PROJECT_MEMBER = 'rule:project_member' -+# Generic check string for checking if a user is authorized on a particular -+# project but with read-only access. For example, this persona would be able to -+# list private images owned by a project but cannot make any writeable changes -+# to those images. -+RULE_PROJECT_READER = 'rule:project_reader' -+ -+RULE_USER_OR_CLUSTER_USER = ( -+ 'rule:user_or_cluster_user') -+RULE_ADMIN_OR_PROJECT_READER = ( -+ 'rule:admin_or_project_reader') -+RULE_ADMIN_OR_PROJECT_MEMBER = ( -+ 'rule:admin_or_project_member') -+RULE_ADMIN_OR_PROJECT_MEMBER_USER = ( -+ 'rule:admin_or_project_member_user') -+RULE_ADMIN_OR_PROJECT_MEMBER_USER_OR_CLUSTER_USER = ( -+ 'rule:admin_or_project_member_user_or_cluster_user') -+RULE_PROJECT_MEMBER_DENY_CLUSTER_USER = ( -+ 'rule:project_member_deny_cluster_user') -+RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER = ( -+ 'rule:admin_or_project_member_deny_cluster_user') -+RULE_PROJECT_READER_DENY_CLUSTER_USER = ( -+ 'rule:project_reader_deny_cluster_user') -+RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER = ( -+ 'rule:admin_or_project_reader_deny_cluster_user') -+RULE_ADMIN_OR_PROJECT_READER_USER_OR_CLUSTER_USER = ( -+ 'rule:admin_or_project_reader_user_or_cluster_user') -+ -+# ========================================================== -+# Deprecated Since OpenStack 2023.2(Magnum 17.0.0) and should be removed in -+# The following cycle. -+ -+DEPRECATED_REASON = """ -+The Magnum API now enforces scoped tokens and default reader and member roles. -+""" -+ -+DEPRECATED_SINCE = 'OpenStack 2023.2(Magnum 17.0.0)' -+ -+ -+DEPRECATED_DENY_CLUSTER_USER = policy.DeprecatedRule( -+ name=RULE_DENY_CLUSTER_USER, -+ check_str='not domain_id:%(trustee_domain_id)s', -+ deprecated_reason=DEPRECATED_REASON, -+ deprecated_since=DEPRECATED_SINCE -+) -+ -+DEPRECATED_RULE_ADMIN_OR_OWNER = policy.DeprecatedRule( -+ name=RULE_ADMIN_OR_OWNER, -+ check_str='is_admin:True or project_id:%(project_id)s', -+ deprecated_reason=DEPRECATED_REASON, -+ deprecated_since=DEPRECATED_SINCE -+) -+ -+# Only used for DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER -+RULE_ADMIN_OR_USER_OR_CLUSTER_USER = ( -+ 'rule:admin_or_user_or_cluster_user') -+ -+DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER = policy.DeprecatedRule( -+ name=RULE_ADMIN_OR_USER_OR_CLUSTER_USER, -+ check_str=f"(({RULE_ADMIN_API}) or ({RULE_USER_OR_CLUSTER_USER}))", -+ deprecated_reason=DEPRECATED_REASON, -+ deprecated_since=DEPRECATED_SINCE -+) -+# ========================================================== - - rules = [ - policy.RuleDefault( -@@ -29,14 +96,14 @@ - name='admin_or_owner', - check_str='is_admin:True or project_id:%(project_id)s' - ), -- policy.RuleDefault( -- name='admin_api', -- check_str='rule:context_is_admin' -- ), - policy.RuleDefault( - name='admin_or_user', - check_str='is_admin:True or user_id:%(user_id)s' - ), -+ policy.RuleDefault( -+ name='is_user', -+ check_str='user_id:%(user_id)s' -+ ), - policy.RuleDefault( - name='cluster_user', - check_str='user_id:%(trustee_user_id)s' -@@ -44,7 +111,95 @@ - policy.RuleDefault( - name='deny_cluster_user', - check_str='not domain_id:%(trustee_domain_id)s' -- ) -+ ), -+ policy.RuleDefault( -+ name='project_member', -+ check_str='role:member and project_id:%(project_id)s' -+ ), -+ policy.RuleDefault( -+ name='project_reader', -+ check_str='role:reader and project_id:%(project_id)s' -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_reader', -+ check_str=f"({RULE_ADMIN_API}) or ({RULE_PROJECT_READER})", -+ deprecated_rule=DEPRECATED_RULE_ADMIN_OR_OWNER -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_member', -+ check_str=f"({RULE_ADMIN_API}) or ({RULE_PROJECT_MEMBER})", -+ deprecated_rule=DEPRECATED_RULE_ADMIN_OR_OWNER -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_member_user', -+ check_str=( -+ f"({RULE_ADMIN_API}) or (({RULE_PROJECT_MEMBER}) and " -+ f"({RULE_USER}))" -+ ) -+ ), -+ policy.RuleDefault( -+ name='user_or_cluster_user', -+ check_str=( -+ f"(({RULE_USER}) or ({RULE_CLUSTER_USER}))" -+ ) -+ ), -+ policy.RuleDefault( -+ name='admin_or_user_or_cluster_user', -+ check_str=( -+ f"(({RULE_ADMIN_API}) or ({RULE_USER_OR_CLUSTER_USER}))" -+ ) -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_member_cluster_user', -+ check_str=( -+ f"({RULE_ADMIN_API}) or (({RULE_PROJECT_MEMBER}) " -+ f"and ({RULE_CLUSTER_USER}))" -+ ) -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_member_user_or_cluster_user', -+ check_str=( -+ f"({RULE_ADMIN_API}) or (({RULE_PROJECT_MEMBER}) and " -+ f"({RULE_USER_OR_CLUSTER_USER}))" -+ ), -+ deprecated_rule=DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER -+ ), -+ policy.RuleDefault( -+ name='project_member_deny_cluster_user', -+ check_str=( -+ f"(({RULE_PROJECT_MEMBER}) and ({RULE_DENY_CLUSTER_USER}))" -+ ), -+ deprecated_rule=DEPRECATED_DENY_CLUSTER_USER -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_member_deny_cluster_user', -+ check_str=( -+ f"({RULE_ADMIN_API}) or ({RULE_PROJECT_MEMBER_DENY_CLUSTER_USER})" -+ ), -+ deprecated_rule=DEPRECATED_DENY_CLUSTER_USER -+ ), -+ policy.RuleDefault( -+ name='project_reader_deny_cluster_user', -+ check_str=( -+ f"(({RULE_PROJECT_READER}) and ({RULE_DENY_CLUSTER_USER}))" -+ ), -+ deprecated_rule=DEPRECATED_DENY_CLUSTER_USER -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_reader_deny_cluster_user', -+ check_str=( -+ f"({RULE_ADMIN_API}) or ({RULE_PROJECT_READER_DENY_CLUSTER_USER})" -+ ), -+ deprecated_rule=DEPRECATED_DENY_CLUSTER_USER -+ ), -+ policy.RuleDefault( -+ name='admin_or_project_reader_user_or_cluster_user', -+ check_str=( -+ f"({RULE_ADMIN_API}) or (({RULE_PROJECT_READER}) and " -+ f"({RULE_USER_OR_CLUSTER_USER}))" -+ ), -+ deprecated_rule=DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER -+ ), - ] - - -diff --git a/magnum/common/policies/certificate.py b/magnum/common/policies/certificate.py -index 5e96b64f5b..32a7047a4b 100644 ---- a/magnum/common/policies/certificate.py -+++ b/magnum/common/policies/certificate.py -@@ -16,13 +16,12 @@ - from magnum.common.policies import base - - CERTIFICATE = 'certificate:%s' --RULE_ADMIN_OR_USER_OR_CLUSTER_USER = base.RULE_ADMIN_OR_USER + " or " + \ -- base.RULE_CLUSTER_USER - - rules = [ - policy.DocumentedRuleDefault( - name=CERTIFICATE % 'create', -- check_str=RULE_ADMIN_OR_USER_OR_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_USER_OR_CLUSTER_USER, -+ scope_types=["project"], - description='Sign a new certificate by the CA.', - operations=[ - { -@@ -33,7 +32,8 @@ - ), - policy.DocumentedRuleDefault( - name=CERTIFICATE % 'get', -- check_str=RULE_ADMIN_OR_USER_OR_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_USER_OR_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve CA information about the given bay/cluster.', - operations=[ - { -@@ -44,7 +44,8 @@ - ), - policy.DocumentedRuleDefault( - name=CERTIFICATE % 'rotate_ca', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, -+ scope_types=["project"], - description='Rotate the CA certificate on the given bay/cluster.', - operations=[ - { -diff --git a/magnum/common/policies/cluster.py b/magnum/common/policies/cluster.py -index 15b63226b2..5e1864c377 100644 ---- a/magnum/common/policies/cluster.py -+++ b/magnum/common/policies/cluster.py -@@ -20,7 +20,8 @@ - rules = [ - policy.DocumentedRuleDefault( - name=CLUSTER % 'create', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Create a new cluster.', - operations=[ - { -@@ -31,7 +32,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'delete', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Delete a cluster.', - operations=[ - { -@@ -53,7 +55,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'detail', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve a list of clusters with detail.', - operations=[ - { -@@ -75,7 +78,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'get', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve information about the given cluster.', - operations=[ - { -@@ -98,7 +102,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'get_all', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve a list of clusters.', - operations=[ - { -@@ -120,7 +125,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'update', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Update an existing cluster.', - operations=[ - { -@@ -131,7 +137,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'update_health_status', -- check_str=base.RULE_ADMIN_OR_USER + " or " + base.RULE_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_USER_OR_CLUSTER_USER, -+ scope_types=["project"], - description='Update the health status of an existing cluster.', - operations=[ - { -@@ -153,7 +160,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'resize', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Resize an existing cluster.', - operations=[ - { -@@ -164,7 +172,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER % 'upgrade', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Upgrade an existing cluster.', - operations=[ - { -diff --git a/magnum/common/policies/cluster_template.py b/magnum/common/policies/cluster_template.py -index d9b51737ad..c0d8337051 100644 ---- a/magnum/common/policies/cluster_template.py -+++ b/magnum/common/policies/cluster_template.py -@@ -20,18 +20,20 @@ - rules = [ - policy.DocumentedRuleDefault( - name=CLUSTER_TEMPLATE % 'create', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Create a new cluster template.', - operations=[ - { - 'path': '/v1/clustertemplates', - 'method': 'POST' - } -- ] -+ ], - ), - policy.DocumentedRuleDefault( - name=CLUSTER_TEMPLATE % 'delete', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, -+ scope_types=["project"], - description='Delete a cluster template.', - operations=[ - { -@@ -65,7 +67,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER_TEMPLATE % 'detail', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve a list of cluster templates with detail.', - operations=[ - { -@@ -76,7 +79,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER_TEMPLATE % 'get', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve information about the given cluster template.', - operations=[ - { -@@ -99,7 +103,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER_TEMPLATE % 'get_all', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve a list of cluster templates.', - operations=[ - { -@@ -121,7 +126,8 @@ - ), - policy.DocumentedRuleDefault( - name=CLUSTER_TEMPLATE % 'update', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, -+ scope_types=["project"], - description='Update an existing cluster template.', - operations=[ - { -diff --git a/magnum/common/policies/federation.py b/magnum/common/policies/federation.py -index b78b1a1b1e..4c347993c3 100644 ---- a/magnum/common/policies/federation.py -+++ b/magnum/common/policies/federation.py -@@ -20,7 +20,8 @@ - rules = [ - policy.DocumentedRuleDefault( - name=FEDERATION % 'create', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Create a new federation.', - operations=[ - { -@@ -31,7 +32,8 @@ - ), - policy.DocumentedRuleDefault( - name=FEDERATION % 'delete', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Delete a federation.', - operations=[ - { -@@ -42,7 +44,8 @@ - ), - policy.DocumentedRuleDefault( - name=FEDERATION % 'detail', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve a list of federations with detail.', - operations=[ - { -@@ -53,7 +56,8 @@ - ), - policy.DocumentedRuleDefault( - name=FEDERATION % 'get', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve information about the given federation.', - operations=[ - { -@@ -64,7 +68,8 @@ - ), - policy.DocumentedRuleDefault( - name=FEDERATION % 'get_all', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Retrieve a list of federations.', - operations=[ - { -@@ -75,7 +80,8 @@ - ), - policy.DocumentedRuleDefault( - name=FEDERATION % 'update', -- check_str=base.RULE_DENY_CLUSTER_USER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER, -+ scope_types=["project"], - description='Update an existing federation.', - operations=[ - { -diff --git a/magnum/common/policies/nodegroup.py b/magnum/common/policies/nodegroup.py -index 64b2d670ea..25bad88579 100644 ---- a/magnum/common/policies/nodegroup.py -+++ b/magnum/common/policies/nodegroup.py -@@ -24,7 +24,8 @@ - rules = [ - policy.DocumentedRuleDefault( - name=NODEGROUP % 'get', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER, -+ scope_types=["project"], - description='Retrieve information about the given nodegroup.', - operations=[ - { -@@ -35,7 +36,8 @@ - ), - policy.DocumentedRuleDefault( - name=NODEGROUP % 'get_all', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER, -+ scope_types=["project"], - description='Retrieve a list of nodegroups that belong to a cluster.', - operations=[ - { -@@ -68,7 +70,8 @@ - ), - policy.DocumentedRuleDefault( - name=NODEGROUP % 'create', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, -+ scope_types=["project"], - description='Create a new nodegroup.', - operations=[ - { -@@ -79,7 +82,8 @@ - ), - policy.DocumentedRuleDefault( - name=NODEGROUP % 'delete', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, -+ scope_types=["project"], - description='Delete a nodegroup.', - operations=[ - { -@@ -90,7 +94,8 @@ - ), - policy.DocumentedRuleDefault( - name=NODEGROUP % 'update', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, -+ scope_types=["project"], - description='Update an existing nodegroup.', - operations=[ - { -diff --git a/magnum/common/policies/quota.py b/magnum/common/policies/quota.py -index 4baecf7d84..574857b1a4 100644 ---- a/magnum/common/policies/quota.py -+++ b/magnum/common/policies/quota.py -@@ -42,7 +42,8 @@ - ), - policy.DocumentedRuleDefault( - name=QUOTA % 'get', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER, -+ scope_types=["project"], - description='Retrieve Quota information for the given project_id.', - operations=[ - { -diff --git a/magnum/common/policies/stats.py b/magnum/common/policies/stats.py -index c37164094b..64996443b7 100644 ---- a/magnum/common/policies/stats.py -+++ b/magnum/common/policies/stats.py -@@ -20,7 +20,8 @@ - rules = [ - policy.DocumentedRuleDefault( - name=STATS % 'get_all', -- check_str=base.RULE_ADMIN_OR_OWNER, -+ check_str=base.RULE_ADMIN_OR_PROJECT_READER, -+ scope_types=["project"], - description='Retrieve magnum stats.', - operations=[ - { -diff --git a/magnum/common/policy.py b/magnum/common/policy.py -index d4bfff77b5..989676efb1 100644 ---- a/magnum/common/policy.py -+++ b/magnum/common/policy.py -@@ -17,6 +17,7 @@ - - import decorator - from oslo_config import cfg -+from oslo_log import log as logging - from oslo_policy import opts - from oslo_policy import policy - from oslo_utils import importutils -@@ -27,6 +28,7 @@ - from magnum.common import policies - - -+LOG = logging.getLogger(__name__) - _ENFORCER = None - CONF = cfg.CONF - -@@ -105,8 +107,14 @@ def enforce(context, rule=None, target=None, - target = {'project_id': context.project_id, - 'user_id': context.user_id} - add_policy_attributes(target) -- return enforcer.enforce(rule, target, credentials, -- do_raise=do_raise, exc=exc, *args, **kwargs) -+ -+ try: -+ result = enforcer.enforce(rule, target, credentials, -+ do_raise=do_raise, exc=exc, *args, **kwargs) -+ except policy.InvalidScope as ex: -+ LOG.debug(f"Invalide scope while enforce policy :{str(ex)}") -+ raise exc(action=rule) -+ return result - - - def add_policy_attributes(target): -diff --git a/magnum/tests/fakes.py b/magnum/tests/fakes.py -index 4407975306..3a64078ce8 100644 ---- a/magnum/tests/fakes.py -+++ b/magnum/tests/fakes.py -@@ -25,7 +25,7 @@ - 'X-Roles': 'role1,role2', - 'X-Auth-Url': 'fake_auth_url', - 'X-Identity-Status': 'Confirmed', -- 'X-User-Domain-Name': 'domain', -+ 'X-User-Domain-Name': 'user_domain_name', - 'X-Project-Domain-Id': 'project_domain_id', - 'X-User-Domain-Id': 'user_domain_id', - 'OpenStack-API-Version': 'container-infra 1.0' -diff --git a/magnum/tests/unit/api/base.py b/magnum/tests/unit/api/base.py -index a4dd3fef63..ddf41277e4 100644 ---- a/magnum/tests/unit/api/base.py -+++ b/magnum/tests/unit/api/base.py -@@ -128,6 +128,9 @@ def put_json(self, path, params, expect_errors=False, headers=None, - with the request - :param status: expected status code of response - """ -+ # Provide member role for put request -+ if not headers: -+ headers = {"X-Roles": "member"} - return self._request_json(path=path, params=params, - expect_errors=expect_errors, - headers=headers, extra_environ=extra_environ, -@@ -146,6 +149,9 @@ def post_json(self, path, params, expect_errors=False, headers=None, - with the request - :param status: expected status code of response - """ -+ # Provide member role for post request -+ if not headers: -+ headers = {"X-Roles": "member"} - return self._request_json(path=path, params=params, - expect_errors=expect_errors, - headers=headers, extra_environ=extra_environ, -@@ -164,6 +170,9 @@ def patch_json(self, path, params, expect_errors=False, headers=None, - with the request - :param status: expected status code of response - """ -+ # Provide member role for patch request -+ if not headers: -+ headers = {"X-Roles": "member"} - return self._request_json(path=path, params=params, - expect_errors=expect_errors, - headers=headers, extra_environ=extra_environ, -@@ -184,6 +193,9 @@ def delete(self, path, expect_errors=False, headers=None, - """ - full_path = path_prefix + path - print('DELETE: %s' % (full_path)) -+ # Provide member role for delete request -+ if not headers: -+ headers = {"X-Roles": "member"} - response = self.app.delete(str(full_path), - headers=headers, - status=status, -@@ -215,6 +227,10 @@ def get_json(self, path, expect_errors=False, headers=None, - 'q.value': [], - 'q.op': [], - } -+ -+ # Provide reader role for get request -+ if not headers: -+ headers = {"X-Roles": "reader"} - for query in q: - for name in ['field', 'op', 'value']: - query_params['q.%s' % name].append(query.get(name, '')) -diff --git a/magnum/tests/unit/api/controllers/test_root.py b/magnum/tests/unit/api/controllers/test_root.py -index e187715016..31700761fd 100644 ---- a/magnum/tests/unit/api/controllers/test_root.py -+++ b/magnum/tests/unit/api/controllers/test_root.py -@@ -140,7 +140,9 @@ def test_noauth(self): - response = app.get('/v1/') - self.assertEqual(self.v1_expected, response.json) - -- response = app.get('/v1/clustertemplates') -+ response = app.get('/v1/clustertemplates', -+ headers={"X-Roles": "reader"} -+ ) - self.assertEqual(200, response.status_int) - - def test_auth_with_no_public_routes(self): -diff --git a/magnum/tests/unit/api/controllers/v1/test_certificate.py b/magnum/tests/unit/api/controllers/v1/test_certificate.py -index 02fcfb40a2..ecd14f0187 100644 ---- a/magnum/tests/unit/api/controllers/v1/test_certificate.py -+++ b/magnum/tests/unit/api/controllers/v1/test_certificate.py -@@ -21,7 +21,14 @@ - from magnum.tests.unit.objects import utils as obj_utils - - --HEADERS = {'OpenStack-API-Version': 'container-infra latest'} -+READER_HEADERS = { -+ 'OpenStack-API-Version': 'container-infra latest', -+ "X-Roles": "reader" -+} -+HEADERS = { -+ 'OpenStack-API-Version': 'container-infra latest', -+ "X-Roles": "member" -+} - - - class TestCertObject(base.TestCase): -@@ -59,7 +66,7 @@ def test_get_one(self): - self.conductor_api.get_ca_certificate.return_value = mock_cert - - response = self.get_json('/certificates/%s' % self.cluster.uuid, -- headers=HEADERS) -+ headers=READER_HEADERS) - - self.assertEqual(self.cluster.uuid, response['cluster_uuid']) - # check that bay is still valid as well -@@ -74,7 +81,7 @@ def test_get_one_by_name(self): - self.conductor_api.get_ca_certificate.return_value = mock_cert - - response = self.get_json('/certificates/%s' % self.cluster.name, -- headers=HEADERS) -+ headers=READER_HEADERS) - - self.assertEqual(self.cluster.uuid, response['cluster_uuid']) - # check that bay is still valid as well -@@ -84,7 +91,8 @@ def test_get_one_by_name(self): - - def test_get_one_by_name_not_found(self): - response = self.get_json('/certificates/not_found', -- expect_errors=True, headers=HEADERS) -+ expect_errors=True, -+ headers=READER_HEADERS) - - self.assertEqual(404, response.status_int) - self.assertEqual('application/json', response.content_type) -@@ -97,7 +105,8 @@ def test_get_one_by_name_multiple_cluster(self): - uuid=uuidutils.generate_uuid()) - - response = self.get_json('/certificates/test_cluster', -- expect_errors=True, headers=HEADERS) -+ expect_errors=True, -+ headers=READER_HEADERS) - - self.assertEqual(409, response.status_int) - self.assertEqual('application/json', response.content_type) -@@ -110,7 +119,7 @@ def test_links(self): - self.conductor_api.get_ca_certificate.return_value = mock_cert - - response = self.get_json('/certificates/%s' % self.cluster.uuid, -- headers=HEADERS) -+ headers=READER_HEADERS) - - self.assertIn('links', response.keys()) - self.assertEqual(2, len(response['links'])) -@@ -265,7 +274,7 @@ def test_policy_disallow_get_one(self): - self._common_policy_check( - "certificate:get", self.get_json, - '/certificates/%s' % cluster.uuid, -- expect_errors=True, headers=HEADERS) -+ expect_errors=True, headers=READER_HEADERS) - - def test_policy_disallow_create(self): - cluster = obj_utils.create_test_cluster(self.context) -diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster.py b/magnum/tests/unit/api/controllers/v1/test_cluster.py -index 016f8cc173..9ff2439f36 100755 ---- a/magnum/tests/unit/api/controllers/v1/test_cluster.py -+++ b/magnum/tests/unit/api/controllers/v1/test_cluster.py -@@ -494,7 +494,9 @@ def test_update_cluster_with_rollback_enabled(self): - '/clusters/%s/?rollback=True' % self.cluster_obj.uuid, - [{'path': '/node_count', 'value': node_count, - 'op': 'replace'}], -- headers={'OpenStack-API-Version': 'container-infra 1.3'}) -+ headers={'OpenStack-API-Version': 'container-infra 1.3', -+ "X-Roles": "member" -+ }) - - self.mock_cluster_update.assert_called_once_with( - mock.ANY, node_count, self.cluster_obj.health_status, -@@ -507,7 +509,9 @@ def test_update_cluster_with_rollback_disabled(self): - '/clusters/%s/?rollback=False' % self.cluster_obj.uuid, - [{'path': '/node_count', 'value': node_count, - 'op': 'replace'}], -- headers={'OpenStack-API-Version': 'container-infra 1.3'}) -+ headers={'OpenStack-API-Version': 'container-infra 1.3', -+ "X-Roles": "member" -+ }) - - self.mock_cluster_update.assert_called_once_with( - mock.ANY, node_count, self.cluster_obj.health_status, -@@ -520,7 +524,9 @@ def test_update_cluster_with_zero_node_count_fail(self): - '/clusters/%s' % self.cluster_obj.uuid, - [{'path': '/node_count', 'value': node_count, - 'op': 'replace'}], -- headers={'OpenStack-API-Version': 'container-infra 1.9'}, -+ headers={'OpenStack-API-Version': 'container-infra 1.9', -+ "X-Roles": "member" -+ }, - expect_errors=True) - - self.assertEqual(400, response.status_code) -@@ -531,7 +537,9 @@ def test_update_cluster_with_zero_node_count(self): - '/clusters/%s' % self.cluster_obj.uuid, - [{'path': '/node_count', 'value': node_count, - 'op': 'replace'}], -- headers={'OpenStack-API-Version': 'container-infra 1.10'}) -+ headers={'OpenStack-API-Version': 'container-infra 1.10', -+ "X-Roles": "member" -+ }) - - self.mock_cluster_update.assert_called_once_with( - mock.ANY, node_count, self.cluster_obj.health_status, -@@ -708,18 +716,24 @@ def test_create_cluster_with_cluster_template_name(self): - def test_create_cluster_with_zero_node_count_fail(self): - bdict = apiutils.cluster_post_data() - bdict['node_count'] = 0 -- response = self.post_json('/clusters', bdict, expect_errors=True, -- headers={"Openstack-Api-Version": -- "container-infra 1.9"}) -+ response = self.post_json( -+ '/clusters', bdict, expect_errors=True, -+ headers={ -+ "Openstack-Api-Version": "container-infra 1.9", -+ "X-Roles": "member" -+ }) - self.assertEqual('application/json', response.content_type) - self.assertEqual(400, response.status_int) - - def test_create_cluster_with_zero_node_count(self): - bdict = apiutils.cluster_post_data() - bdict['node_count'] = 0 -- response = self.post_json('/clusters', bdict, -- headers={"Openstack-Api-Version": -- "container-infra 1.10"}) -+ response = self.post_json( -+ '/clusters', bdict, -+ headers={ -+ "Openstack-Api-Version": "container-infra 1.10", -+ "X-Roles": "member" -+ }) - self.assertEqual('application/json', response.content_type) - self.assertEqual(202, response.status_int) - -diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py b/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py -index ba9304fe1b..22baf556ce 100644 ---- a/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py -+++ b/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py -@@ -46,7 +46,8 @@ def test_resize(self): - self.cluster_obj.uuid, - {"node_count": new_node_count}, - headers={"Openstack-Api-Version": -- "container-infra 1.7"}) -+ "container-infra 1.7", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - response = self.get_json('/clusters/%s' % self.cluster_obj.uuid) -@@ -69,7 +70,8 @@ def test_resize_with_nodegroup(self): - self.cluster_obj.uuid, - cluster_resize_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}) -+ "container-infra 1.9", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - response = self.get_json('/clusters/%s' % self.cluster_obj.uuid) -@@ -89,7 +91,8 @@ def test_resize_with_master_nodegroup(self): - self.cluster_obj.uuid, - cluster_resize_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}, -+ "container-infra 1.9", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(400, response.status_code) - -@@ -106,7 +109,8 @@ def test_resize_with_node_count_greater_than_max(self): - self.cluster_obj.uuid, - cluster_resize_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}, -+ "container-infra 1.9", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(400, response.status_code) - -@@ -123,7 +127,8 @@ def test_resize_with_node_count_less_than_min(self): - self.cluster_obj.uuid, - cluster_resize_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}, -+ "container-infra 1.9", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(400, response.status_code) - -@@ -140,7 +145,8 @@ def test_resize_with_zero_node_count_fail(self): - self.cluster_obj.uuid, - cluster_resize_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}, -+ "container-infra 1.9", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(400, response.status_code) - -@@ -157,7 +163,8 @@ def test_resize_with_zero_node_count(self): - self.cluster_obj.uuid, - cluster_resize_req, - headers={"Openstack-Api-Version": -- "container-infra 1.10"}) -+ "container-infra 1.10", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - -@@ -195,7 +202,8 @@ def test_upgrade(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.8"}) -+ "container-infra 1.8", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - def test_upgrade_cluster_as_admin(self): -@@ -226,7 +234,8 @@ def test_upgrade_cluster_as_admin(self): - '/clusters/%s/actions/upgrade' % - cluster_uuid, - cluster_upgrade_req, -- headers={"Openstack-Api-Version": "container-infra 1.8"}) -+ headers={"Openstack-Api-Version": "container-infra 1.8", -+ "X-Roles": "member"}) - - self.assertEqual(202, response.status_int) - -@@ -239,7 +248,8 @@ def test_upgrade_default_worker(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}) -+ "container-infra 1.9", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - def test_upgrade_default_master(self): -@@ -251,7 +261,8 @@ def test_upgrade_default_master(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}) -+ "container-infra 1.9", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - def test_upgrade_non_default_ng(self): -@@ -263,7 +274,8 @@ def test_upgrade_non_default_ng(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}) -+ "container-infra 1.9", -+ "X-Roles": "member"}) - self.assertEqual(202, response.status_code) - - def test_upgrade_cluster_not_found(self): -@@ -273,7 +285,8 @@ def test_upgrade_cluster_not_found(self): - response = self.post_json('/clusters/not_there/actions/upgrade', - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.8"}, -+ "container-infra 1.8", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(404, response.status_code) - -@@ -285,7 +298,8 @@ def test_upgrade_ct_not_found(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.8"}, -+ "container-infra 1.8", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(404, response.status_code) - -@@ -298,7 +312,8 @@ def test_upgrade_ng_not_found(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}, -+ "container-infra 1.9", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(404, response.status_code) - -@@ -311,6 +326,7 @@ def test_upgrade_non_default_ng_invalid_ct(self): - self.cluster_obj.uuid, - cluster_upgrade_req, - headers={"Openstack-Api-Version": -- "container-infra 1.9"}, -+ "container-infra 1.9", -+ "X-Roles": "member"}, - expect_errors=True) - self.assertEqual(409, response.status_code) -diff --git a/magnum/tests/unit/api/controllers/v1/test_nodegroup.py b/magnum/tests/unit/api/controllers/v1/test_nodegroup.py -index a6f73d54b2..68304a10f6 100644 ---- a/magnum/tests/unit/api/controllers/v1/test_nodegroup.py -+++ b/magnum/tests/unit/api/controllers/v1/test_nodegroup.py -@@ -47,24 +47,26 @@ def test_nodegroup_init(self): - class NodeGroupControllerTest(api_base.FunctionalTest): - headers = {"Openstack-Api-Version": "container-infra latest"} - -- def _add_headers(self, kwargs): -+ def _add_headers(self, kwargs, roles=None): - if 'headers' not in kwargs: - kwargs['headers'] = self.headers -+ if roles: -+ kwargs['headers']['X-Roles'] = ",".join(roles) - - def get_json(self, *args, **kwargs): -- self._add_headers(kwargs) -+ self._add_headers(kwargs, roles=['reader']) - return super(NodeGroupControllerTest, self).get_json(*args, **kwargs) - - def post_json(self, *args, **kwargs): -- self._add_headers(kwargs) -+ self._add_headers(kwargs, roles=['member']) - return super(NodeGroupControllerTest, self).post_json(*args, **kwargs) - - def delete(self, *args, **kwargs): -- self._add_headers(kwargs) -+ self._add_headers(kwargs, roles=['member']) - return super(NodeGroupControllerTest, self).delete(*args, **kwargs) - - def patch_json(self, *args, **kwargs): -- self._add_headers(kwargs) -+ self._add_headers(kwargs, roles=['member']) - return super(NodeGroupControllerTest, self).patch_json(*args, **kwargs) - - -diff --git a/magnum/tests/unit/api/controllers/v1/test_quota.py b/magnum/tests/unit/api/controllers/v1/test_quota.py -index b6b47c481a..07e78857ed 100644 ---- a/magnum/tests/unit/api/controllers/v1/test_quota.py -+++ b/magnum/tests/unit/api/controllers/v1/test_quota.py -@@ -207,7 +207,7 @@ def test_get_all_non_admin(self, mock_policy): - project_id="proj-id-"+str(i)) - quota_list.append(quota) - -- headers = {'X-Project-Id': 'proj-id-2'} -+ headers = {'X-Project-Id': 'proj-id-2', "X-Roles": "member"} - response = self.get_json('/quotas', headers=headers) - self.assertEqual(1, len(response['quotas'])) - self.assertEqual('proj-id-2', response['quotas'][0]['project_id']) -diff --git a/magnum/tests/unit/api/controllers/v1/test_stats.py b/magnum/tests/unit/api/controllers/v1/test_stats.py -index bb7aac28f4..2e41222d34 100644 ---- a/magnum/tests/unit/api/controllers/v1/test_stats.py -+++ b/magnum/tests/unit/api/controllers/v1/test_stats.py -@@ -21,7 +21,14 @@ - class TestStatsController(api_base.FunctionalTest): - - def setUp(self): -- self.base_headers = {'OpenStack-API-Version': 'container-infra 1.4'} -+ self.base_headers = { -+ "X-Roles": "reader", -+ "OpenStack-API-Version": "container-infra 1.4" -+ } -+ self.base_admin_headers = { -+ "X-Roles": "admin", -+ "OpenStack-API-Version": "container-infra 1.4" -+ } - super(TestStatsController, self).setUp() - obj_utils.create_test_cluster_template(self.context) - -@@ -39,7 +46,7 @@ def test_admin_get_all_stats(self, mock_context, mock_policy): - obj_utils.create_test_cluster(self.context, - project_id=234, - uuid='uuid2') -- response = self.get_json('/stats', headers=self.base_headers) -+ response = self.get_json('/stats', headers=self.base_admin_headers) - expected = {u'clusters': 2, u'nodes': 12} - self.assertEqual(expected, response) - -@@ -54,7 +61,7 @@ def test_admin_get_tenant_stats(self, mock_context, mock_policy): - uuid='uuid2') - self.context.is_admin = True - response = self.get_json('/stats?project_id=234', -- headers=self.base_headers) -+ headers=self.base_admin_headers) - expected = {u'clusters': 1, u'nodes': 6} - self.assertEqual(expected, response) - -@@ -69,7 +76,7 @@ def test_admin_get_invalid_tenant_stats(self, mock_context, mock_policy): - uuid='uuid2') - self.context.is_admin = True - response = self.get_json('/stats?project_id=34', -- headers=self.base_headers) -+ headers=self.base_admin_headers) - expected = {u'clusters': 0, u'nodes': 0} - self.assertEqual(expected, response) - -diff --git a/magnum/tests/unit/api/test_hooks.py b/magnum/tests/unit/api/test_hooks.py -index 9332c93120..3cbfde4363 100644 ---- a/magnum/tests/unit/api/test_hooks.py -+++ b/magnum/tests/unit/api/test_hooks.py -@@ -34,7 +34,8 @@ def setUp(self): - super(TestContextHook, self).setUp() - self.app = fakes.FakeApp() - -- def test_context_hook_before_method(self): -+ @mock.patch("magnum.common.policy.check_is_admin") -+ def test_context_hook_before_method(self, m_c): - state = mock.Mock(request=fakes.FakePecanRequest()) - hook = hooks.ContextHook() - hook.before(state) -@@ -51,12 +52,13 @@ def test_context_hook_before_method(self): - self.assertEqual(fakes.fakeAuthTokenHeaders['X-Roles'], - ','.join(ctx.roles)) - self.assertEqual(fakes.fakeAuthTokenHeaders['X-User-Domain-Name'], -- ctx.domain_name) -+ ctx.user_domain_name) - self.assertEqual(fakes.fakeAuthTokenHeaders['X-User-Domain-Id'], -- ctx.domain_id) -+ ctx.user_domain_id) - self.assertIsNone(ctx.auth_token_info) - -- def test_context_hook_before_method_auth_info(self): -+ @mock.patch("magnum.common.policy.check_is_admin") -+ def test_context_hook_before_method_auth_info(self, c_m): - state = mock.Mock(request=fakes.FakePecanRequest()) - state.request.environ['keystone.token_info'] = 'assert_this' - hook = hooks.ContextHook() -diff --git a/magnum/tests/unit/common/policies/__init__.py b/magnum/tests/unit/common/policies/__init__.py -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/magnum/tests/unit/common/policies/base.py b/magnum/tests/unit/common/policies/base.py -new file mode 100644 -index 0000000000..22572c0a46 ---- /dev/null -+++ b/magnum/tests/unit/common/policies/base.py -@@ -0,0 +1,37 @@ -+# 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. -+ -+from oslo_config import cfg -+ -+from magnum.tests.unit.api import base as api_base -+ -+ -+CONF = cfg.CONF -+ -+ -+class PolicyFunctionalTest(api_base.FunctionalTest): -+ def setUp(self): -+ super(PolicyFunctionalTest, self).setUp() -+ CONF.set_override('enforce_scope', True, group='oslo_policy') -+ CONF.set_override('enforce_new_defaults', True, group='oslo_policy') -+ self.reader_headers = { -+ "X-Roles": "reader", -+ } -+ self.member_headers = { -+ "X-Roles": "member", -+ } -+ self.admin_headers = { -+ "X-Roles": "admin", -+ } -+ self.foo_headers = { -+ "X-Roles": "foo", -+ } -diff --git a/magnum/tests/unit/common/policies/test_certificate_policy.py b/magnum/tests/unit/common/policies/test_certificate_policy.py -new file mode 100644 -index 0000000000..cc53a71645 ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_certificate_policy.py -@@ -0,0 +1,72 @@ -+# 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. -+ -+from unittest import mock -+from webtest.app import AppError -+ -+from magnum.tests.unit.api import utils as apiutils -+from magnum.tests.unit.common.policies import base -+from magnum.tests.unit.objects import utils as obj_utils -+ -+READER_HEADERS = { -+ 'OpenStack-API-Version': 'container-infra latest', -+ "X-Roles": "reader" -+} -+HEADERS = { -+ 'OpenStack-API-Version': 'container-infra latest', -+ "X-Roles": "member" -+} -+ -+ -+class TestCertifiactePolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestCertifiactePolicy, self).setUp() -+ self.cluster = obj_utils.create_test_cluster(self.context) -+ -+ conductor_api_patcher = mock.patch('magnum.conductor.api.API') -+ self.conductor_api_class = conductor_api_patcher.start() -+ self.conductor_api = mock.MagicMock() -+ self.conductor_api_class.return_value = self.conductor_api -+ self.addCleanup(conductor_api_patcher.stop) -+ -+ self.conductor_api.sign_certificate.side_effect = self._fake_sign -+ -+ @staticmethod -+ def _fake_sign(cluster, cert): -+ cert.pem = 'fake-pem' -+ return cert -+ -+ def test_get_no_permission(self): -+ exc = self.assertRaises( -+ AppError, -+ self.get_json, -+ f"/certificates/{self.cluster.uuid}", -+ headers=HEADERS) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_create_no_permission(self): -+ new_cert = apiutils.cert_post_data(cluster_uuid=self.cluster.uuid) -+ del new_cert['pem'] -+ -+ exc = self.assertRaises( -+ AppError, self.post_json, -+ '/certificates', new_cert, -+ headers=READER_HEADERS) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_update_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.patch_json, -+ f"/certificates/{self.cluster.uuid}", {}, -+ headers=READER_HEADERS -+ ) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_cluster_policy.py b/magnum/tests/unit/common/policies/test_cluster_policy.py -new file mode 100644 -index 0000000000..01cfd25c5c ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_cluster_policy.py -@@ -0,0 +1,65 @@ -+# 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. -+ -+from webtest.app import AppError -+ -+from magnum.tests.unit.api import utils as apiutils -+from magnum.tests.unit.common.policies import base -+from magnum.tests.unit.objects import utils as obj_utils -+ -+ -+class TestClusterPolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestClusterPolicy, self).setUp() -+ self.cluster = obj_utils.create_test_cluster( -+ self.context, name='cluster_example_A', node_count=3 -+ ) -+ -+ def test_get_all_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, '/clusters', -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_get_no_permission(self): -+ exc = self.assertRaises( -+ AppError, -+ self.get_json, -+ f"/clusters/{self.cluster.uuid}", -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_create_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.post_json, -+ '/clusters', apiutils.cluster_post_data(), -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_update_no_permission(self): -+ cluster_dict = [ -+ {'path': '/node_count', 'value': 4, 'op': 'replace'} -+ ] -+ exc = self.assertRaises( -+ AppError, self.patch_json, -+ f"/clusters/{self.cluster.name}", cluster_dict, -+ headers=self.reader_headers -+ ) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_delete_no_permission(self): -+ # delete cluster -+ exc = self.assertRaises( -+ AppError, self.delete, f"/clusters/{self.cluster.uuid}", -+ headers=self.reader_headers -+ ) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_cluster_template_policy.py b/magnum/tests/unit/common/policies/test_cluster_template_policy.py -new file mode 100644 -index 0000000000..c6eb9b60a6 ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_cluster_template_policy.py -@@ -0,0 +1,74 @@ -+# 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. -+ -+from webtest.app import AppError -+ -+from magnum.tests.unit.api import utils as apiutils -+from magnum.tests.unit.common.policies import base -+from magnum.tests.unit.objects import utils as obj_utils -+ -+ -+class TestClusterTemplatePolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestClusterTemplatePolicy, self).setUp() -+ self.clustertemplate = obj_utils.create_test_cluster_template( -+ self.context -+ ) -+ -+ def test_get_all_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, '/clustertemplates', -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_get_detail_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, -+ '/clustertemplates/detail', -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_get_no_permission(self): -+ exc = self.assertRaises( -+ AppError, -+ self.get_json, -+ f"/clustertemplates/{self.clustertemplate.uuid}", -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_create_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.post_json, -+ '/clustertemplates', -+ apiutils.cluster_template_post_data(), -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_update_no_permission(self): -+ clustertemplate_data = [ -+ {'path': '/dns_nameserver', 'op': 'remove'}] -+ exc = self.assertRaises( -+ AppError, -+ self.patch_json, -+ f"/clustertemplates/{self.clustertemplate.uuid}", -+ clustertemplate_data, -+ headers=self.reader_headers -+ ) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_delete_no_permission(self): -+ # delete clustertemplate -+ exc = self.assertRaises( -+ AppError, self.delete, -+ f"/clustertemplates/{self.clustertemplate.uuid}", -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_federation_policy.py b/magnum/tests/unit/common/policies/test_federation_policy.py -new file mode 100644 -index 0000000000..68eb1d6212 ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_federation_policy.py -@@ -0,0 +1,67 @@ -+# 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. -+ -+from oslo_utils import uuidutils -+from webtest.app import AppError -+ -+from magnum.tests.unit.common.policies import base -+from magnum.tests.unit.objects import utils as obj_utils -+ -+ -+class TestFederationPolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestFederationPolicy, self).setUp() -+ self.create_frederation() -+ -+ def create_frederation(self): -+ self.fake_uuid = uuidutils.generate_uuid() -+ self.federation = obj_utils.create_test_federation( -+ self.context, uuid=self.fake_uuid) -+ -+ def test_get_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, '/federations', -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_get_reader(self): -+ response = self.get_json('/federations') -+ self.assertEqual(self.fake_uuid, response['federations'][0]['uuid']) -+ -+ def test_create_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.post_json, '/federations', {}, -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_update_no_permission(self): -+ new_member = obj_utils.create_test_cluster(self.context) -+ exc = self.assertRaises( -+ AppError, self.patch_json, '/federations/%s' % self.fake_uuid, -+ [{'path': '/member_ids', 'value': new_member.uuid, 'op': 'add'}], -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_delete_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.delete, -+ '/federations/%s' % self.fake_uuid, -+ headers=self.reader_headers -+ ) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_detail_list_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, -+ '/federations/detail', -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_magnum_service_policy.py b/magnum/tests/unit/common/policies/test_magnum_service_policy.py -new file mode 100644 -index 0000000000..9f8153d3a4 ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_magnum_service_policy.py -@@ -0,0 +1,26 @@ -+# 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. -+ -+from webtest.app import AppError -+ -+from magnum.tests.unit.common.policies import base -+ -+ -+class TestMagnumServicePolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestMagnumServicePolicy, self).setUp() -+ -+ def test_get_all_no_permission(self): -+ exc = self.assertRaises(AppError, -+ self.get_json, "/mservices", -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_nodegroup_policy.py b/magnum/tests/unit/common/policies/test_nodegroup_policy.py -new file mode 100644 -index 0000000000..73f3e107e4 ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_nodegroup_policy.py -@@ -0,0 +1,74 @@ -+# 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. -+ -+from oslo_utils import uuidutils -+from webtest.app import AppError -+ -+from magnum import objects -+from magnum.tests.unit.api import utils as apiutils -+from magnum.tests.unit.common.policies import base -+from magnum.tests.unit.objects import utils as obj_utils -+ -+ -+class TestNodeGroupPolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestNodeGroupPolicy, self).setUp() -+ obj_utils.create_test_cluster_template(self.context) -+ self.cluster_uuid = uuidutils.generate_uuid() -+ obj_utils.create_test_cluster( -+ self.context, uuid=self.cluster_uuid) -+ self.cluster = objects.Cluster.get_by_uuid(self.context, -+ self.cluster_uuid) -+ self.nodegroup = obj_utils.create_test_nodegroup( -+ self.context, cluster_id=self.cluster.uuid, is_default=False) -+ self.url = f"/clusters/{self.cluster.uuid}/nodegroups/" -+ self.member = {"Openstack-Api-Version": "container-infra latest"} -+ self.member.update(self.member_headers) -+ self.reader = {"Openstack-Api-Version": "container-infra latest"} -+ self.reader.update(self.reader_headers) -+ -+ def test_get_all_no_permission(self): -+ exc = self.assertRaises(AppError, -+ self.get_json, self.url, -+ headers=self.member) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_get_no_permission(self): -+ exc = self.assertRaises( -+ AppError, -+ self.get_json, -+ f"{self.url}foo", -+ headers=self.member) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_create_no_permission(self): -+ exc = self.assertRaises(AppError, -+ self.post_json, self.url, -+ apiutils.nodegroup_post_data(), -+ headers=self.reader) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_update_no_permission(self): -+ ng_dict = [ -+ {'path': '/max_node_count', 'value': 4, 'op': 'replace'}] -+ exc = self.assertRaises( -+ AppError, self.patch_json, -+ self.url + self.nodegroup.uuid, ng_dict, -+ headers=self.reader) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_delete_no_permission(self): -+ # delete cluster -+ exc = self.assertRaises( -+ AppError, self.delete, self.url + self.nodegroup.uuid, -+ headers=self.reader) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_quota_policy.py b/magnum/tests/unit/common/policies/test_quota_policy.py -new file mode 100644 -index 0000000000..48d4a09c2c ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_quota_policy.py -@@ -0,0 +1,74 @@ -+# 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. -+ -+from unittest import mock -+from webtest.app import AppError -+ -+from magnum.common import clients -+from magnum.tests.unit.api import utils as apiutils -+from magnum.tests.unit.common.policies import base -+from magnum.tests.unit.objects import utils as obj_utils -+ -+ -+class TestQuotaPolicy(base.PolicyFunctionalTest): -+ def setUp(self): -+ super(TestQuotaPolicy, self).setUp() -+ -+ def test_get_all_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, '/quotas', -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ def test_get_no_permission(self): -+ quota = obj_utils.create_test_quota(self.context) -+ exc = self.assertRaises( -+ AppError, -+ self.get_json, -+ f"/quotas/{quota['project_id']}/{quota['resource']}", -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ @mock.patch.object(clients.OpenStackClients, 'keystone') -+ def test_create_no_permission(self, mock_keystone): -+ exc = self.assertRaises( -+ AppError, self.post_json, -+ '/quotas', apiutils.quota_post_data(), -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ @mock.patch.object(clients.OpenStackClients, 'keystone') -+ def test_update_no_permission(self, mock_keystone): -+ with mock.patch("magnum.common.policy.enforce"): -+ quota_dict = apiutils.quota_post_data(hard_limit=5) -+ self.post_json('/quotas', quota_dict) -+ quota_dict['hard_limit'] = 20 -+ exc = self.assertRaises( -+ AppError, self.patch_json, '/quotas', quota_dict, -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -+ -+ @mock.patch.object(clients.OpenStackClients, 'keystone') -+ def test_delete_no_permission(self, mock_keystone): -+ with mock.patch("magnum.common.policy.enforce"): -+ quota_dict = apiutils.quota_post_data() -+ response = self.post_json('/quotas', quota_dict) -+ self.assertEqual('application/json', response.content_type) -+ self.assertEqual(201, response.status_int) -+ -+ project_id = quota_dict['project_id'] -+ resource = quota_dict['resource'] -+ # delete quota -+ exc = self.assertRaises( -+ AppError, self.delete, f"/quotas/{project_id}/{resource}", -+ headers=self.reader_headers) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/policies/test_stats_policy.py b/magnum/tests/unit/common/policies/test_stats_policy.py -new file mode 100644 -index 0000000000..20cf1bee5c ---- /dev/null -+++ b/magnum/tests/unit/common/policies/test_stats_policy.py -@@ -0,0 +1,33 @@ -+# 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. -+ -+from webtest.app import AppError -+ -+from magnum.tests.unit.common.policies import base -+ -+ -+class TestStatsPolicy(base.PolicyFunctionalTest): -+ def test_stat_reader(self): -+ response = self.get_json('/stats', headers=self.reader_headers) -+ expected = {u'clusters': 0, u'nodes': 0} -+ self.assertEqual(expected, response) -+ -+ def test_stat_admin(self): -+ response = self.get_json('/stats', headers=self.admin_headers) -+ expected = {u'clusters': 0, u'nodes': 0} -+ self.assertEqual(expected, response) -+ -+ def test_stat_no_permission(self): -+ exc = self.assertRaises( -+ AppError, self.get_json, '/stats', -+ headers=self.member_headers) -+ self.assertIn("403 Forbidden", str(exc)) -diff --git a/magnum/tests/unit/common/test_context.py b/magnum/tests/unit/common/test_context.py -index c72c2c763d..aed4d33ebd 100644 ---- a/magnum/tests/unit/common/test_context.py -+++ b/magnum/tests/unit/common/test_context.py -@@ -19,29 +19,30 @@ - class ContextTestCase(base.TestCase): - - def _create_context(self, roles=None): -- return magnum_context.RequestContext(auth_token='auth_token1', -- auth_url='auth_url1', -- domain_id='domain_id1', -- domain_name='domain_name1', -- user_name='user1', -- user_id='user-id1', -- project_name='tenant1', -- project_id='tenant-id1', -- roles=roles, -- is_admin=True, -- read_only=True, -- show_deleted=True, -- request_id='request_id1', -- trust_id='trust_id1', -- auth_token_info='token_info1') -+ return magnum_context.RequestContext( -+ auth_token='auth_token1', -+ auth_url='auth_url1', -+ user_domain_id='user_domain_id1', -+ user_domain_name='user_domain_name1', -+ user_name='user1', -+ user_id='user-id1', -+ project_name='tenant1', -+ project_id='tenant-id1', -+ roles=roles, -+ is_admin=True, -+ read_only=True, -+ show_deleted=True, -+ request_id='request_id1', -+ trust_id='trust_id1', -+ auth_token_info='token_info1') - - def test_context(self): - ctx = self._create_context() - - self.assertEqual("auth_token1", ctx.auth_token) - self.assertEqual("auth_url1", ctx.auth_url) -- self.assertEqual("domain_id1", ctx.domain_id) -- self.assertEqual("domain_name1", ctx.domain_name) -+ self.assertEqual("user_domain_id1", ctx.user_domain_id) -+ self.assertEqual("user_domain_name1", ctx.user_domain_name) - self.assertEqual("user1", ctx.user_name) - self.assertEqual("user-id1", ctx.user_id) - self.assertEqual("tenant1", ctx.project_name) -@@ -59,8 +60,8 @@ def test_context_with_roles(self): - - self.assertEqual("auth_token1", ctx.auth_token) - self.assertEqual("auth_url1", ctx.auth_url) -- self.assertEqual("domain_id1", ctx.domain_id) -- self.assertEqual("domain_name1", ctx.domain_name) -+ self.assertEqual("user_domain_id1", ctx.user_domain_id) -+ self.assertEqual("user_domain_name1", ctx.user_domain_name) - self.assertEqual("user1", ctx.user_name) - self.assertEqual("user-id1", ctx.user_id) - self.assertEqual("tenant1", ctx.project_name) -@@ -80,8 +81,8 @@ def test_to_dict_from_dict(self): - - self.assertEqual(ctx.auth_token, ctx2.auth_token) - self.assertEqual(ctx.auth_url, ctx2.auth_url) -- self.assertEqual(ctx.domain_id, ctx2.domain_id) -- self.assertEqual(ctx.domain_name, ctx2.domain_name) -+ self.assertEqual(ctx.user_domain_id, ctx2.user_domain_id) -+ self.assertEqual(ctx.user_domain_name, ctx2.user_domain_name) - self.assertEqual(ctx.user_name, ctx2.user_name) - self.assertEqual(ctx.user_id, ctx2.user_id) - self.assertEqual(ctx.project_id, ctx2.project_id) -diff --git a/releasenotes/notes/allow_admin_perform_acitons-cc988655bb72b3f3.yaml b/releasenotes/notes/allow_admin_perform_acitons-cc988655bb72b3f3.yaml -new file mode 100644 -index 0000000000..6cb516451c ---- /dev/null -+++ b/releasenotes/notes/allow_admin_perform_acitons-cc988655bb72b3f3.yaml -@@ -0,0 +1,9 @@ -+--- -+upgrade: -+ - | -+ To make sure better have backward compatibility, -+ we set specific rule to allow admin perform all actions. -+ This will apply on part of APIs in -+ * Cluster -+ * Cluster Template -+ * federation -diff --git a/releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml b/releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml -new file mode 100644 -index 0000000000..69b9fec5eb ---- /dev/null -+++ b/releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml -@@ -0,0 +1,13 @@ -+--- -+upgrade: -+ - | -+ The Magnum service now allows enables policies (RBAC) new defaults -+ and scope checks. These are controlled by the following (default) config -+ options in ``magnum.conf`` file:: -+ -+ [oslo_policy] -+ enforce_new_defaults=False -+ enforce_scope=False -+ -+ We will change the default to True in the following cycle. -+ If you want to enable them then modify both values to True. diff --git a/images/magnum/patches/0001-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch b/images/magnum/patches/magnum/0000-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch similarity index 100% rename from images/magnum/patches/0001-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch rename to images/magnum/patches/magnum/0000-update-chart-metadata-version-to-reflect-breaking-change-in-helm-v3-5-2.patch diff --git a/images/manila/Earthfile b/images/manila/Earthfile index 320fc8fe6..57181426a 100644 --- a/images/manila/Earthfile +++ b/images/manila/Earthfile @@ -1,17 +1,20 @@ VERSION 0.7 +ARG --global PROJECT=manila +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=98bc755673fe48a9c67203e4262315b048efe25d + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + image: - ARG PROJECT=manila - ARG RELEASE=zed - ARG REF=9ea49e2b9df7da16d5700810eee18710dc90e6a4 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "iproute2 openvswitch-switch" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/manila/patches/0000-fix-stop-using-batch_op-for-rename_table.patch b/images/manila/patches/manila/0000-fix-stop-using-batch_op-for-rename_table.patch similarity index 80% rename from images/manila/patches/0000-fix-stop-using-batch_op-for-rename_table.patch rename to images/manila/patches/manila/0000-fix-stop-using-batch_op-for-rename_table.patch index a55e4e67b..c904b265b 100644 --- a/images/manila/patches/0000-fix-stop-using-batch_op-for-rename_table.patch +++ b/images/manila/patches/manila/0000-fix-stop-using-batch_op-for-rename_table.patch @@ -1,6 +1,6 @@ From eb7f03c667261557d7f809f7851bad6b3eea4646 Mon Sep 17 00:00:00 2001 From: Mohammed Naser -Date: Mon, 08 Jan 2024 14:00:37 -0500 +Date: Mon, 8 Jan 2024 14:00:37 -0500 Subject: [PATCH] fix: Stop using batch_op for rename_table For migrations that rename tables, batch_op is not needed, which @@ -8,12 +8,14 @@ is also even causing issues with newer versions of Alembic. Change-Id: Ib43f5a24c497f7d97cb2d852b99489b0c3bd75fb --- + .../alembic/versions/5077ffcc5f1c_add_share_instances.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manila/db/migrations/alembic/versions/5077ffcc5f1c_add_share_instances.py b/manila/db/migrations/alembic/versions/5077ffcc5f1c_add_share_instances.py -index 42d26b7..373e308 100644 +index 42d26b75e..373e308d0 100644 --- a/manila/db/migrations/alembic/versions/5077ffcc5f1c_add_share_instances.py +++ b/manila/db/migrations/alembic/versions/5077ffcc5f1c_add_share_instances.py -@@ -245,8 +245,8 @@ +@@ -245,8 +245,8 @@ def upgrade_export_locations_table(connection): with op.batch_alter_table("share_export_locations") as batch_op: batch_op.drop_constraint('sel_id_fk', type_='foreignkey') batch_op.drop_column('share_id') @@ -24,3 +26,6 @@ index 42d26b7..373e308 100644 def downgrade_export_locations_table(connection): +-- +2.34.1 + diff --git a/images/neutron/Earthfile b/images/neutron/Earthfile index 8b61017f0..a9b4712b5 100644 --- a/images/neutron/Earthfile +++ b/images/neutron/Earthfile @@ -1,21 +1,24 @@ VERSION 0.7 +ARG --global PROJECT=neutron +ARG --global RELEASE=zed +ARG --global PROJECT_REF=222c997022392561c2de2cb493f0f5214eb20dfc + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="git+https://github.com/openstack/neutron-vpnaas.git@256464aea691f8b4957ba668a117963353f34e4c" + platform-image: - ARG PROJECT=neutron - ARG RELEASE=zed - ARG REF=222c997022392561c2de2cb493f0f5214eb20dfc - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "git+https://github.com/openstack/neutron-vpnaas.git@256464aea691f8b4957ba668a117963353f34e4c" - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "conntrack dnsmasq dnsmasq-utils ebtables ethtool haproxy iproute2 ipset iptables iputils-arping jq keepalived lshw openvswitch-switch strongswan uuid-runtime" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} image: BUILD --platform linux/amd64 --platform linux/arm64 +platform-image diff --git a/images/neutron/patches/0000-fix-netns-deletion-of-broken-namespaces.patch b/images/neutron/patches/neutron/0000-fix-netns-deletion-of-broken-namespaces.patch similarity index 86% rename from images/neutron/patches/0000-fix-netns-deletion-of-broken-namespaces.patch rename to images/neutron/patches/neutron/0000-fix-netns-deletion-of-broken-namespaces.patch index a1540adef..a20200b77 100644 --- a/images/neutron/patches/0000-fix-netns-deletion-of-broken-namespaces.patch +++ b/images/neutron/patches/neutron/0000-fix-netns-deletion-of-broken-namespaces.patch @@ -1,4 +1,4 @@ -From f8130f36e3cdb67fd9be64a61ac22b487200e2bc Mon Sep 17 00:00:00 2001 +From 69c49c4ef24648f97d895bfaacd7336917634565 Mon Sep 17 00:00:00 2001 From: Felix Huettner Date: Fri, 22 Sep 2023 16:25:10 +0200 Subject: [PATCH] fix netns deletion of broken namespaces @@ -26,13 +26,19 @@ which is critical for VM startup. Closes-Bug: #2037102 Change-Id: I7c43812fed5903f98a2e491076c24a8d926a59b4 +(cherry picked from commit 566fea3fed837b0130023303c770aade391d3d61) --- + neutron/agent/linux/ip_lib.py | 17 ++++++++++++- + neutron/agent/ovn/metadata/agent.py | 5 +++- + neutron/tests/unit/agent/linux/test_ip_lib.py | 15 +++++++++++ + .../unit/agent/ovn/metadata/test_agent.py | 25 +++++++++++++++++++ + 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py -index 9953729..196dc17 100644 +index 10bd33d9e1..5d2593da47 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py -@@ -259,7 +259,22 @@ +@@ -259,7 +259,22 @@ class IPWrapper(SubProcessBase): return ip def namespace_is_empty(self): @@ -57,10 +63,10 @@ index 9953729..196dc17 100644 def garbage_collect_namespace(self): """Conditionally destroy the namespace if it is empty.""" diff --git a/neutron/agent/ovn/metadata/agent.py b/neutron/agent/ovn/metadata/agent.py -index 7a09145..888ab15 100644 +index 1745239701..861715d8e1 100644 --- a/neutron/agent/ovn/metadata/agent.py +++ b/neutron/agent/ovn/metadata/agent.py -@@ -478,7 +478,10 @@ +@@ -430,7 +430,10 @@ class MetadataAgent(object): ns.startswith(NS_PREFIX) and ns not in metadata_namespaces] for ns in unused_namespaces: @@ -73,10 +79,10 @@ index 7a09145..888ab15 100644 # resync all network namespaces based on the associated datapaths, # even those that are already running. This is to make sure diff --git a/neutron/tests/unit/agent/linux/test_ip_lib.py b/neutron/tests/unit/agent/linux/test_ip_lib.py -index c488e90..3956142 100644 +index d1c74fb3f7..159cafdb8e 100644 --- a/neutron/tests/unit/agent/linux/test_ip_lib.py +++ b/neutron/tests/unit/agent/linux/test_ip_lib.py -@@ -357,6 +357,23 @@ +@@ -357,6 +357,21 @@ class TestIpWrapper(base.BaseTestCase): self.assertNotIn(mock.call().delete('ns'), ip_ns_cmd_cls.mock_calls) @@ -92,19 +98,17 @@ index c488e90..3956142 100644 + self.assertTrue(ip.garbage_collect_namespace()) + + mock_get_devices.assert_called_once_with() -+ expected = [mock.call(ip), -+ mock.call().exists('ns'), -+ mock.call().delete('ns')] -+ self.assertEqual(ip_ns_cmd_cls.mock_calls, expected) ++ expected = [mock.call().delete('ns')] ++ ip_ns_cmd_cls.assert_has_calls(expected) + @mock.patch.object(priv_lib, 'create_interface') def test_add_vlan(self, create): retval = ip_lib.IPWrapper().add_vlan('eth0.1', 'eth0', '1') diff --git a/neutron/tests/unit/agent/ovn/metadata/test_agent.py b/neutron/tests/unit/agent/ovn/metadata/test_agent.py -index 73487e1..cb6ee43 100644 +index 6df7da702d..9bf9f0db52 100644 --- a/neutron/tests/unit/agent/ovn/metadata/test_agent.py +++ b/neutron/tests/unit/agent/ovn/metadata/test_agent.py -@@ -138,6 +138,31 @@ +@@ -134,6 +134,31 @@ class TestMetadataAgent(base.BaseTestCase): lnn.assert_called_once_with() tdp.assert_called_once_with('3') @@ -136,3 +140,6 @@ index 73487e1..cb6ee43 100644 def test_get_networks_datapaths(self): """Test get_networks_datapaths returns only datapath objects for the networks containing vif ports of type ''(blank) and 'external'. +-- +2.34.1 + diff --git a/images/nova/Earthfile b/images/nova/Earthfile index 3d86b603b..2780578ca 100644 --- a/images/nova/Earthfile +++ b/images/nova/Earthfile @@ -1,21 +1,24 @@ VERSION 0.7 +ARG --global PROJECT=nova +ARG --global RELEASE=zed +ARG --global PROJECT_REF=226f3e95c1cdadd1845c7adee55f5c5f29f3a7a8 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + platform-image: - ARG PROJECT=nova - ARG RELEASE=zed - ARG REF=226f3e95c1cdadd1845c7adee55f5c5f29f3a7a8 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "ceph-common genisoimage iproute2 libosinfo-bin lsscsi ndctl nvme-cli openssh-client ovmf python3-libvirt python3-rados python3-rbd qemu-efi-aarch64 qemu-utils sysfsutils udev util-linux" - DO ../+APPLY_PATCHES GIT CLONE --branch v1.4.0 https://github.com/novnc/noVNC.git /usr/share/novnc SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} image: BUILD --platform linux/amd64 --platform linux/arm64 +platform-image diff --git a/images/octavia/Earthfile b/images/octavia/Earthfile index 16e5799a0..d37ba3665 100644 --- a/images/octavia/Earthfile +++ b/images/octavia/Earthfile @@ -1,18 +1,21 @@ VERSION 0.7 +ARG --global PROJECT=octavia +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=88d7315a60314e44fcce88ad198ceb3c0c107fe6 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="ovn-octavia-provider" + image: - ARG PROJECT=octavia - ARG RELEASE=zed - ARG REF=07c33fec4578e2529a2a5fc8fad4cde929597849 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "ovn-octavia-provider" - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "isc-dhcp-client openssh-client" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/openstack-service/2023.1/upper-constraints.txt b/images/openstack-service/2023.1/upper-constraints.txt index 1962f4211..beede4e2f 100644 --- a/images/openstack-service/2023.1/upper-constraints.txt +++ b/images/openstack-service/2023.1/upper-constraints.txt @@ -540,7 +540,6 @@ sphinxcontrib-devhelp==1.0.5 python-blazarclient==3.7.0 alembic==1.13.1 execnet==1.9.0 -glance-store==4.6.1 sphinxcontrib-programoutput==0.17 storpool.spopenstack==3.2.0 sphinx-testing==1.0.1 diff --git a/images/openstack-service/2023.2/upper-constraints.txt b/images/openstack-service/2023.2/upper-constraints.txt index 52c23383b..2e62bc784 100644 --- a/images/openstack-service/2023.2/upper-constraints.txt +++ b/images/openstack-service/2023.2/upper-constraints.txt @@ -549,7 +549,6 @@ sphinxcontrib-devhelp==1.0.5 python-blazarclient==3.7.0 alembic==1.13.1 execnet==1.9.0 -glance-store==4.6.1 sphinxcontrib-programoutput==0.17 storpool.spopenstack==3.2.0 sphinx-testing==1.0.1 diff --git a/images/openstack-service/Earthfile b/images/openstack-service/Earthfile index 20c1f50a5..702943290 100644 --- a/images/openstack-service/Earthfile +++ b/images/openstack-service/Earthfile @@ -1,6 +1,45 @@ VERSION 0.7 -build: +PIP_INSTALL: + COMMAND + ARG PACKAGES + RUN --mount=type=cache,target=/root/.cache \ + /var/lib/openstack/bin/pip3 install \ + --constraint /upper-constraints.txt \ + ${PACKAGES} + +GIT_CHECKOUT: + COMMAND + ARG PROJECT + ARG PROJECT_REPO=https://github.com/openstack/${PROJECT} + ARG PROJECT_REF + GIT CLONE --branch ${PROJECT_REF} ${PROJECT_REPO} /src + WORKDIR /src + RUN \ + git remote set-url origin ${PROJECT_REPO} && \ + git fetch --unshallow + COPY --if-exists patches/${PROJECT} /patches + IF [ -d /patches ] + RUN git apply --verbose /patches/*.patch + END + +BUILD_VENV: + COMMAND + ARG PROJECT + ARG PROJECT_REF + DO +GIT_CHECKOUT --PROJECT=${PROJECT} --PROJECT_REF=${PROJECT_REF} + ARG EXTRAS="" + ARG PIP_PACKAGES="" + DO +PIP_INSTALL --PACKAGES "/src${EXTRAS} ${PIP_PACKAGES}" + SAVE ARTIFACT /var/lib/openstack venv + +requirements: + FROM ../base+image + ARG RELEASE + COPY ${RELEASE}/upper-constraints.txt /upper-constraints.txt + SAVE ARTIFACT /upper-constraints.txt + +builder: ARG RELEASE FROM ../cloud-archive-base+image --RELEASE=${RELEASE} DO ../+APT_INSTALL --PACKAGES "\ @@ -19,41 +58,14 @@ build: python3-venv" RUN --mount type=cache,target=/root/.cache \ python3 -m venv --upgrade --system-site-packages /var/lib/openstack - ENV UWSGI_PROFILE_OVERRIDE=ssl=true - RUN --mount type=cache,target=/root/.cache \ - mkdir -p /wheels && \ - /var/lib/openstack/bin/pip3 wheel --wheel-dir /wheels uwsgi - COPY ${RELEASE}/upper-constraints.txt /upper-constraints.txt - ARG PROJECT - ARG PROJECT_REF - ARG PROJECT_REPO=https://opendev.org/openstack/${PROJECT} - GIT CLONE --branch ${PROJECT_REF} ${PROJECT_REPO} /src - RUN \ - cd /src && \ - git fetch --unshallow - ARG EXTRAS="" - ARG PIP_PACKAGES="" - RUN --mount=type=cache,target=/root/.cache \ - /var/lib/openstack/bin/pip3 install \ - --constraint /upper-constraints.txt \ - --find-links /wheels/ \ - pymysql \ - python-memcached \ - cryptography \ - uwsgi \ - /src${EXTRAS} \ - ${PIP_PACKAGES} - SAVE ARTIFACT /var/lib/openstack venv + COPY \ + (+requirements/upper-constraints.txt --RELEASE=${RELEASE}) \ + /upper-constraints.txt + DO +PIP_INSTALL --PACKAGES "pymysql python-memcached cryptography uwsgi" image: - ARG RELEASE + ARG --required RELEASE FROM ../cloud-archive-base+image --RELEASE=${RELEASE} - ARG PROJECT - ARG PROJECT_REF - ARG PIP_PACKAGES - DO ../+CREATE_PROJECT_USER --PROJECT=${PROJECT} ENV PATH=/var/lib/openstack/bin:$PATH - COPY \ - (+build/venv --RELEASE=${RELEASE} --PROJECT=${PROJECT} --PROJECT_REF=${PROJECT_REF} --PIP_PACKAGES=${PIP_PACKAGES}) \ - /var/lib/openstack - LABEL org.opencontainers.image.source=https://github.com/vexxhost/atmosphere + ARG --required PROJECT + DO ../+CREATE_PROJECT_USER --PROJECT=${PROJECT} diff --git a/images/openstack-service/master/upper-constraints.txt b/images/openstack-service/master/upper-constraints.txt index 1b044b94b..667fcb5b0 100644 --- a/images/openstack-service/master/upper-constraints.txt +++ b/images/openstack-service/master/upper-constraints.txt @@ -553,7 +553,6 @@ sphinxcontrib-devhelp==1.0.5 python-blazarclient==3.7.0 alembic==1.13.1 execnet==2.0.2 -glance-store==4.6.1 sphinxcontrib-programoutput==0.17 storpool.spopenstack==3.2.0 sphinx-testing==1.0.1 diff --git a/images/openstack-service/zed/upper-constraints.txt b/images/openstack-service/zed/upper-constraints.txt index 1d844e396..6d94a1a98 100644 --- a/images/openstack-service/zed/upper-constraints.txt +++ b/images/openstack-service/zed/upper-constraints.txt @@ -541,7 +541,6 @@ sphinxcontrib-devhelp==1.0.5 python-blazarclient==3.7.0 alembic==1.13.1 execnet==1.9.0 -glance-store==4.6.1 sphinxcontrib-programoutput==0.17 storpool.spopenstack==3.2.0 sphinx-testing==1.0.1 diff --git a/images/placement/Earthfile b/images/placement/Earthfile index 81a33694d..64d6afddd 100644 --- a/images/placement/Earthfile +++ b/images/placement/Earthfile @@ -1,14 +1,18 @@ VERSION 0.7 +ARG --global PROJECT=placement +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=a361622d749d3b24aad638ec1b03a7d7124a87b3 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + image: - ARG PROJECT=placement - ARG RELEASE=zed - ARG REF=d7ced6bd2fc82caf458f20b5652888164b1bbb70 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} - DO ../+APPLY_PATCHES + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/senlin/Earthfile b/images/senlin/Earthfile index 60da266e7..7e677882e 100644 --- a/images/senlin/Earthfile +++ b/images/senlin/Earthfile @@ -1,14 +1,18 @@ VERSION 0.7 +ARG --global PROJECT=senlin +ARG --global RELEASE=2023.2 +ARG --global PROJECT_REF=5382259276d6be6807634c58c7b69b03b57ad6f5 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} + image: - ARG PROJECT=senlin - ARG RELEASE=zed - ARG REF=b6ef17b0f787fb7a0609ba36dc13097882a6a3ff - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} - DO ../+APPLY_PATCHES + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/images/tempest/Earthfile b/images/tempest/Earthfile index 062d82ac0..9f180c780 100644 --- a/images/tempest/Earthfile +++ b/images/tempest/Earthfile @@ -1,18 +1,21 @@ VERSION 0.7 +ARG --global PROJECT=tempest +ARG --global RELEASE=master +ARG --global PROJECT_REF=699749ec27897efe9bd7824664237c16c3339c03 + +build: + FROM ../openstack-service+builder --RELEASE=${RELEASE} + DO ../openstack-service+BUILD_VENV \ + --PROJECT=${PROJECT} \ + --PROJECT_REF=${PROJECT_REF} \ + --PIP_PACKAGES="git+https://github.com/openstack/barbican-tempest-plugin.git git+https://github.com/openstack/cinder-tempest-plugin.git git+https://github.com/openstack/heat-tempest-plugin.git git+https://github.com/openstack/keystone-tempest-plugin.git git+https://github.com/openstack/neutron-tempest-plugin.git" + image: - ARG PROJECT=tempest - ARG RELEASE=master - ARG REF=699749ec27897efe9bd7824664237c16c3339c03 - FROM ../openstack-service+image \ - --PROJECT ${PROJECT} \ - --RELEASE ${RELEASE} \ - --PROJECT_REF ${REF} \ - --PIP_PACKAGES "git+https://github.com/openstack/barbican-tempest-plugin.git git+https://github.com/openstack/cinder-tempest-plugin.git git+https://github.com/openstack/heat-tempest-plugin.git git+https://github.com/openstack/keystone-tempest-plugin.git git+https://github.com/openstack/neutron-tempest-plugin.git" - DO \ - ../+APT_INSTALL \ + FROM ../openstack-service+image --RELEASE ${RELEASE} --PROJECT ${PROJECT} + COPY +build/venv /var/lib/openstack + DO ../+APT_INSTALL \ --PACKAGES "iputils-ping" - DO ../+APPLY_PATCHES SAVE IMAGE --push \ ghcr.io/vexxhost/atmosphere/${PROJECT}:${RELEASE} \ - ghcr.io/vexxhost/atmosphere/${PROJECT}:${REF} + ghcr.io/vexxhost/atmosphere/${PROJECT}:${PROJECT_REF} diff --git a/roles/defaults/vars/main.yml b/roles/defaults/vars/main.yml index 7ff5bcc0b..dc34073a1 100644 --- a/roles/defaults/vars/main.yml +++ b/roles/defaults/vars/main.yml @@ -14,9 +14,9 @@ _atmosphere_images: alertmanager: quay.io/prometheus/alertmanager:v0.26.0@sha256:361db356b33041437517f1cd298462055580585f26555c317df1a3caf2868552 - barbican_api: ghcr.io/vexxhost/atmosphere/barbican:zed@sha256:1cdfcefaf7def5031b97148f5d9d3d280b19c90ad63b3857e6554f258555311a - barbican_db_sync: ghcr.io/vexxhost/atmosphere/barbican:zed@sha256:1cdfcefaf7def5031b97148f5d9d3d280b19c90ad63b3857e6554f258555311a - bootstrap: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e + barbican_api: ghcr.io/vexxhost/atmosphere/barbican:2023.2@sha256:e36e6e5882bfc6d8a20497206a69cf8d7abe9450a50a6166759f65295ae021ab + barbican_db_sync: ghcr.io/vexxhost/atmosphere/barbican:2023.2@sha256:e36e6e5882bfc6d8a20497206a69cf8d7abe9450a50a6166759f65295ae021ab + bootstrap: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 ceph_config_helper: ghcr.io/vexxhost/atmosphere/libvirtd@sha256:68274a76b635cf78a513e0b9324e49efdc653714bf974161e5940ddfda206114 ceph: quay.io/ceph/ceph:v16.2.11@sha256:1b9803c8984bef8b82f05e233e8fe8ed8f0bba8e5cc2c57f6efaccbeea682add cert_manager_cainjector: quay.io/jetstack/cert-manager-cainjector:v1.7.1@sha256:985743eeed2b62f68ee06e583f1d5a371e1c35af4b1980a1b2571d29174cce47 @@ -25,14 +25,14 @@ _atmosphere_images: cert_manager_webhook: quay.io/jetstack/cert-manager-webhook:v1.7.1@sha256:a926d60b6f23553ca5d11ac9cd66bcc692136e838613c8bc0d60c6c35a3cbcfc cilium_node: quay.io/cilium/cilium:v1.13.3@sha256:77176464a1e11ea7e89e984ac7db365e7af39851507e94f137dcf56c87746314 cilium_operator: quay.io/cilium/operator-generic:v1.13.3@sha256:fa7003cbfdf8358cb71786afebc711b26e5e44a2ed99bd4944930bba915b8910 - cinder_api: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_backup_storage_init: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_backup: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_db_sync: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_scheduler: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_storage_init: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_volume_usage_audit: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 - cinder_volume: ghcr.io/vexxhost/atmosphere/cinder:zed@sha256:79a803e82b98b1822268f1451394d4d52cf289c8ed661a783461db4ba03b0a95 + cinder_api: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_backup_storage_init: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_backup: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_db_sync: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_scheduler: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_storage_init: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_volume_usage_audit: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 + cinder_volume: ghcr.io/vexxhost/atmosphere/cinder:2023.2@sha256:d07e77592f478a373b4043865947dc436babe8fbc37d7fe4a0381c3fea27fc55 cluster_api_controller: registry.k8s.io/cluster-api/cluster-api-controller:v1.5.1@sha256:5210087161fdc09c98e47f847c07ed3ff93470e774cb1d5a792e2f76eaa5cf12 cluster_api_kubeadm_bootstrap_controller: registry.k8s.io/cluster-api/kubeadm-bootstrap-controller:v1.5.1@sha256:6d73f991862d0df9724fab31a4a694681d9181e772c265d2c5b9b0b26b572479 cluster_api_kubeadm_control_plane_controller: registry.k8s.io/cluster-api/kubeadm-control-plane-controller:v1.5.1@sha256:8d926bcd3e0ca6be6cb9212f692f0ea6790f83862f4dc02fae0c7e0b35e76907 @@ -43,31 +43,31 @@ _atmosphere_images: csi_rbd_provisioner: registry.k8s.io/sig-storage/csi-provisioner:v3.1.0@sha256:92107bb668a9de58a09247596c337bc5b46a1d145685eb55ef489ae16952f5bd csi_rbd_resizer: registry.k8s.io/sig-storage/csi-resizer:v1.3.0@sha256:35ec0c736ec8266bd4a46f9e942315f148f3139beed99879d0ad8b8e5074d641 csi_rbd_snapshotter: registry.k8s.io/sig-storage/csi-snapshotter:v4.2.0@sha256:bd7dafbd0d4fe81f23f01c9a7432de067bdf085f70d61492f5ffddd9c5264358 - db_drop: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - db_init: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e + db_drop: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + db_init: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 dep_check: ghcr.io/vexxhost/atmosphere/kubernetes-entrypoint:latest@sha256:a1993b58da2afb16b44d4e510bd217ab872a4c10f598909edc39e72cda92f0b5 - designate_api: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - designate_central: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - designate_db_sync: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - designate_mdns: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - designate_producer: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - designate_sink: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - designate_worker: ghcr.io/vexxhost/atmosphere/designate:zed@sha256:5f12564675b8f111cb334af27d69c75bde77ebf5899f85ddcb484c481df5a8bc - glance_api: ghcr.io/vexxhost/atmosphere/glance:zed@sha256:209722d4e9b1cbbd834e166a8ea090f07bc7aa4083d21bb21bfc137a70f6536f - glance_db_sync: ghcr.io/vexxhost/atmosphere/glance:zed@sha256:209722d4e9b1cbbd834e166a8ea090f07bc7aa4083d21bb21bfc137a70f6536f - glance_metadefs_load: ghcr.io/vexxhost/atmosphere/glance:zed@sha256:209722d4e9b1cbbd834e166a8ea090f07bc7aa4083d21bb21bfc137a70f6536f - glance_registry: ghcr.io/vexxhost/atmosphere/glance:zed@sha256:209722d4e9b1cbbd834e166a8ea090f07bc7aa4083d21bb21bfc137a70f6536f - glance_storage_init: ghcr.io/vexxhost/atmosphere/glance:zed@sha256:209722d4e9b1cbbd834e166a8ea090f07bc7aa4083d21bb21bfc137a70f6536f + designate_api: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + designate_central: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + designate_db_sync: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + designate_mdns: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + designate_producer: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + designate_sink: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + designate_worker: ghcr.io/vexxhost/atmosphere/designate:2023.2@sha256:3d40cdcba4c806d68fd58ea15c263b783b5a7e64aa87228ed3c5ddf14f4ab240 + glance_api: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:90a212dc90be925b33809a8488ab50cd7c1b09bf619b045c4cd24c409784bfcc + glance_db_sync: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:90a212dc90be925b33809a8488ab50cd7c1b09bf619b045c4cd24c409784bfcc + glance_metadefs_load: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:90a212dc90be925b33809a8488ab50cd7c1b09bf619b045c4cd24c409784bfcc + glance_registry: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:90a212dc90be925b33809a8488ab50cd7c1b09bf619b045c4cd24c409784bfcc + glance_storage_init: ghcr.io/vexxhost/atmosphere/glance:2023.2@sha256:90a212dc90be925b33809a8488ab50cd7c1b09bf619b045c4cd24c409784bfcc grafana_sidecar: quay.io/kiwigrid/k8s-sidecar:1.24.6@sha256:3b70b9f1a81e67c97e4cd32c9a918fa44fd2c9f66bdd0d28d8b82d7b502cb5e4 grafana: docker.io/grafana/grafana:10.1.0@sha256:047c1c5aa6fef257b6c2516f95c8fcd9f28707c201c6413dd78328b6cbedff6f haproxy: docker.io/library/haproxy:2.5@sha256:ea38b570dd7836aa6b85ef1fb19d1e03f5322cccd62e688f0c2b79e38ac4f391 - heat_api: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - heat_cfn: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - heat_cloudwatch: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - heat_db_sync: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - heat_engine_cleaner: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - heat_engine: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - heat_purge_deleted: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e + heat_api: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + heat_cfn: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + heat_cloudwatch: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + heat_db_sync: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + heat_engine_cleaner: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + heat_engine: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + heat_purge_deleted: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 horizon_db_sync: ghcr.io/vexxhost/atmosphere/horizon:2023.2@sha256:ef3876e0425182a2b741ebb696ebb4c9e79044d0fabf7afbf8d0025898db58a4 horizon: ghcr.io/vexxhost/atmosphere/horizon:2023.2@sha256:ef3876e0425182a2b741ebb696ebb4c9e79044d0fabf7afbf8d0025898db58a4 ingress_nginx_controller: registry.k8s.io/ingress-nginx/controller:v1.1.1@sha256:e16123f3932f44a2bba8bc3cf1c109cea4495ee271d6d16ab99228b58766d3ab @@ -75,17 +75,17 @@ _atmosphere_images: ingress_nginx_kube_webhook_certgen: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:23a03c9c381fba54043d0f6148efeaf4c1ca2ed176e43455178b5c5ebf15ad70 # noqa: yaml[line-length] keepalived: us-docker.pkg.dev/vexxhost-infra/openstack/keepalived:2.0.19@sha256:4fe20cd5c200e301e1a790c9aca8c3fc651c8461afea9d37c56a462d3bfa48bb keycloak: quay.io/keycloak/keycloak:22.0.1-0@sha256:5b872e841ea9e394d89bdf250146434532d9c2001404540d46621d60f87494e7 - keystone_api: ghcr.io/vexxhost/atmosphere/keystone:zed@sha256:e2201904496c4eeaaf42cc90ccfb2bdbef3a70310b3ab7cf6d981d0b7aa5d78c - keystone_credential_cleanup: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - keystone_credential_rotate: ghcr.io/vexxhost/atmosphere/keystone:zed@sha256:e2201904496c4eeaaf42cc90ccfb2bdbef3a70310b3ab7cf6d981d0b7aa5d78c - keystone_credential_setup: ghcr.io/vexxhost/atmosphere/keystone:zed@sha256:e2201904496c4eeaaf42cc90ccfb2bdbef3a70310b3ab7cf6d981d0b7aa5d78c - keystone_db_sync: ghcr.io/vexxhost/atmosphere/keystone:zed@sha256:e2201904496c4eeaaf42cc90ccfb2bdbef3a70310b3ab7cf6d981d0b7aa5d78c - keystone_domain_manage: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - keystone_fernet_rotate: ghcr.io/vexxhost/atmosphere/keystone:zed@sha256:e2201904496c4eeaaf42cc90ccfb2bdbef3a70310b3ab7cf6d981d0b7aa5d78c - keystone_fernet_setup: ghcr.io/vexxhost/atmosphere/keystone:zed@sha256:e2201904496c4eeaaf42cc90ccfb2bdbef3a70310b3ab7cf6d981d0b7aa5d78c - ks_endpoints: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - ks_service: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - ks_user: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e + keystone_api: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:1e46e5a6e67c10095d3ca597fb166fc5fbb07fb38034a5020244cb0ee200091d + keystone_credential_cleanup: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + keystone_credential_rotate: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:1e46e5a6e67c10095d3ca597fb166fc5fbb07fb38034a5020244cb0ee200091d + keystone_credential_setup: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:1e46e5a6e67c10095d3ca597fb166fc5fbb07fb38034a5020244cb0ee200091d + keystone_db_sync: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:1e46e5a6e67c10095d3ca597fb166fc5fbb07fb38034a5020244cb0ee200091d + keystone_domain_manage: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + keystone_fernet_rotate: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:1e46e5a6e67c10095d3ca597fb166fc5fbb07fb38034a5020244cb0ee200091d + keystone_fernet_setup: ghcr.io/vexxhost/atmosphere/keystone:2023.2@sha256:1e46e5a6e67c10095d3ca597fb166fc5fbb07fb38034a5020244cb0ee200091d + ks_endpoints: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + ks_service: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + ks_user: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 kube_apiserver: registry.k8s.io/kube-apiserver:v1.22.17@sha256:d88d1c8f972e10ff4b4176f3185434e2832d3805c457fa9e8816f1da2fdf3b93 kube_controller_manager: registry.k8s.io/kube-controller-manager:v1.22.17@sha256:c3e041c8c8c9ffd33d421c8c1de1f42da52b616bfcf61880498e9efc9ec88005 kube_coredns: registry.k8s.io/coredns/coredns:v1.8.4@sha256:10683d82b024a58cc248c468c2632f9d1b260500f7cd9bb8e73f751048d7d6d4 @@ -101,16 +101,16 @@ _atmosphere_images: local_path_provisioner: docker.io/rancher/local-path-provisioner:v0.0.24@sha256:5bb33992a4ec3034c28b5e0b3c4c2ac35d3613b25b79455eb4b1a95adc82cdc0 loki_gateway: docker.io/nginxinc/nginx-unprivileged:1.19-alpine@sha256:bbd46452aae30a7cc7bc438f267af812c7a2b0f3b5bcd4cc55eb99669cea3f28 loki: docker.io/grafana/loki:2.7.3@sha256:8e3abbd89173066721fa07bddfee1c1a7a8fe59bed5b00a2fa09d2b3cef8758c - magnum_api: ghcr.io/vexxhost/atmosphere/magnum:zed@sha256:df5a2662803e423cf6d158254e519095930a70ea050aa51d1871f1c7d19aa060 - magnum_cluster_api_proxy: ghcr.io/vexxhost/atmosphere/magnum:zed@sha256:df5a2662803e423cf6d158254e519095930a70ea050aa51d1871f1c7d19aa060 - magnum_conductor: ghcr.io/vexxhost/atmosphere/magnum:zed@sha256:df5a2662803e423cf6d158254e519095930a70ea050aa51d1871f1c7d19aa060 - magnum_db_sync: ghcr.io/vexxhost/atmosphere/magnum:zed@sha256:df5a2662803e423cf6d158254e519095930a70ea050aa51d1871f1c7d19aa060 + magnum_api: ghcr.io/vexxhost/atmosphere/magnum:2023.2@sha256:0712bdda7f3bf80a42acdae3fe29d526fa20292ed8dfc265655e91280c8d8244 + magnum_cluster_api_proxy: ghcr.io/vexxhost/atmosphere/magnum:2023.2@sha256:0712bdda7f3bf80a42acdae3fe29d526fa20292ed8dfc265655e91280c8d8244 + magnum_conductor: ghcr.io/vexxhost/atmosphere/magnum:2023.2@sha256:0712bdda7f3bf80a42acdae3fe29d526fa20292ed8dfc265655e91280c8d8244 + magnum_db_sync: ghcr.io/vexxhost/atmosphere/magnum:2023.2@sha256:0712bdda7f3bf80a42acdae3fe29d526fa20292ed8dfc265655e91280c8d8244 magnum_registry: quay.io/vexxhost/magnum-cluster-api-registry:latest@sha256:b954f23ccdbfb2b5b43f6a4e6f7ef5f2ba7bfc81f31de54cf141a56b26628c41 - manila_api: ghcr.io/vexxhost/atmosphere/manila:zed@sha256:5c590bf7fc738e8ab11dc267285c207a06098bc113bd70696f6928a7a887e844 - manila_data: ghcr.io/vexxhost/atmosphere/manila:zed@sha256:5c590bf7fc738e8ab11dc267285c207a06098bc113bd70696f6928a7a887e844 - manila_db_sync: ghcr.io/vexxhost/atmosphere/manila:zed@sha256:5c590bf7fc738e8ab11dc267285c207a06098bc113bd70696f6928a7a887e844 - manila_scheduler: ghcr.io/vexxhost/atmosphere/manila:zed@sha256:5c590bf7fc738e8ab11dc267285c207a06098bc113bd70696f6928a7a887e844 - manila_share: ghcr.io/vexxhost/atmosphere/manila:zed@sha256:5c590bf7fc738e8ab11dc267285c207a06098bc113bd70696f6928a7a887e844 + manila_api: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:cf30be0f2ed730274147e9e6d1d68d419fc3bb62f3e6bf201d7d37636d8eda7c + manila_data: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:cf30be0f2ed730274147e9e6d1d68d419fc3bb62f3e6bf201d7d37636d8eda7c + manila_db_sync: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:cf30be0f2ed730274147e9e6d1d68d419fc3bb62f3e6bf201d7d37636d8eda7c + manila_scheduler: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:cf30be0f2ed730274147e9e6d1d68d419fc3bb62f3e6bf201d7d37636d8eda7c + manila_share: ghcr.io/vexxhost/atmosphere/manila:2023.2@sha256:cf30be0f2ed730274147e9e6d1d68d419fc3bb62f3e6bf201d7d37636d8eda7c memcached: docker.io/library/memcached:1.6.17@sha256:d20c577c08863b09b21ecd21d0384d0a800f39d82f37045b3608f677a0a9400f netoffload: ghcr.io/vexxhost/netoffload:v1.0.1@sha256:60f092e5d5f156c2f933c199ea72274f80eb758d3e0dc2f2b1be62174c3f7183 neutron_bagpipe_bgp: ghcr.io/vexxhost/atmosphere/neutron:zed@sha256:14a8bf03360ddf6f83926bf144fdb2ae9db80a08eb0b6a54cf6a44fe48bd5887 @@ -132,7 +132,7 @@ _atmosphere_images: node_feature_discovery: registry.k8s.io/nfd/node-feature-discovery:v0.11.2@sha256:24b2abfb5956b6a2a9a0f4248232838d02235d65044078c43d8bdcf29344f141 nova_api: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca nova_archive_deleted_rows: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca - nova_cell_setup_init: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e + nova_cell_setup_init: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 nova_cell_setup: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca nova_compute_ironic: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca nova_compute_ssh: ghcr.io/vexxhost/atmosphere/nova-ssh:latest@sha256:902ef58f699de769b6809e8b8bb43c47daec14478c9b8952bec1dc7671f4d2cc @@ -144,15 +144,15 @@ _atmosphere_images: nova_novncproxy: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca nova_placement: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca nova_scheduler: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca - nova_service_cleaner: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e + nova_service_cleaner: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 nova_spiceproxy_assets: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca nova_spiceproxy: ghcr.io/vexxhost/atmosphere/nova:zed@sha256:584c9e0a1c503110c95ff511610993e9b41d99091579291c7726db155b6fa0ca - octavia_api: ghcr.io/vexxhost/atmosphere/octavia:zed@sha256:37bdfe3d4cf538301afd5467b949bd2b624018d3a0afd6963393ad3a160d0283 - octavia_db_sync: ghcr.io/vexxhost/atmosphere/octavia:zed@sha256:37bdfe3d4cf538301afd5467b949bd2b624018d3a0afd6963393ad3a160d0283 - octavia_health_manager_init: ghcr.io/vexxhost/atmosphere/heat:zed@sha256:3b3c2da31dec32ac7f1e40e23ac242e07071cc89bd8e54a6e006294b15da191e - octavia_health_manager: ghcr.io/vexxhost/atmosphere/octavia:zed@sha256:37bdfe3d4cf538301afd5467b949bd2b624018d3a0afd6963393ad3a160d0283 - octavia_housekeeping: ghcr.io/vexxhost/atmosphere/octavia:zed@sha256:37bdfe3d4cf538301afd5467b949bd2b624018d3a0afd6963393ad3a160d0283 - octavia_worker: ghcr.io/vexxhost/atmosphere/octavia:zed@sha256:37bdfe3d4cf538301afd5467b949bd2b624018d3a0afd6963393ad3a160d0283 + octavia_api: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:7b865b938379bcd75eeb90a457a2a19a6a70c0cf28fea250777ca75974ea1389 + octavia_db_sync: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:7b865b938379bcd75eeb90a457a2a19a6a70c0cf28fea250777ca75974ea1389 + octavia_health_manager_init: ghcr.io/vexxhost/atmosphere/heat:2023.2@sha256:c5118e27245b53db06e5098e980816d5f2a8f2615dde49d5e0c5b3172ee69bf6 + octavia_health_manager: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:7b865b938379bcd75eeb90a457a2a19a6a70c0cf28fea250777ca75974ea1389 + octavia_housekeeping: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:7b865b938379bcd75eeb90a457a2a19a6a70c0cf28fea250777ca75974ea1389 + octavia_worker: ghcr.io/vexxhost/atmosphere/octavia:2023.2@sha256:7b865b938379bcd75eeb90a457a2a19a6a70c0cf28fea250777ca75974ea1389 openvswitch_db_server: ghcr.io/vexxhost/atmosphere/openvswitch:3.1.0-65@sha256:c68347b6b1479fda5ccf3165492b989ebe49985fa30661ed4f1ea208fa2a110e openvswitch_vswitchd: ghcr.io/vexxhost/atmosphere/openvswitch:3.1.0-65@sha256:c68347b6b1479fda5ccf3165492b989ebe49985fa30661ed4f1ea208fa2a110e ovn_controller: ghcr.io/vexxhost/atmosphere/ovn-host:23.03.0-69@sha256:03b4174e347d14e370aff7399a34f5fcbab1176dcf72c22ffbb0e8c1f66628a6 @@ -164,8 +164,8 @@ _atmosphere_images: percona_xtradb_cluster_operator: docker.io/percona/percona-xtradb-cluster-operator:1.13.0@sha256:c674d63242f1af521edfbaffae2ae02fb8d010c0557a67a9c42d2b4a50db5243 percona_xtradb_cluster: docker.io/percona/percona-xtradb-cluster:8.0.32-24.2@sha256:1f978ab8912e1b5fc66570529cb7e7a4ec6a38adbfce1ece78159b0fcfa7d47a percona_version_service: docker.io/perconalab/version-service:main-3325140@sha256:b7928130fca1e35ce7feaeec326fef836229a8b4de2f6f6ea5b6d2c7a48cd071 - placement_db_sync: ghcr.io/vexxhost/atmosphere/placement:zed@sha256:015e7b312d7efee6db95e6942d76ca7941e7a13473410c353913fb7d244d79fd - placement: ghcr.io/vexxhost/atmosphere/placement:zed@sha256:015e7b312d7efee6db95e6942d76ca7941e7a13473410c353913fb7d244d79fd + placement_db_sync: ghcr.io/vexxhost/atmosphere/placement:2023.2@sha256:439732fb29bdda398de9889e06a0e6052f13e2f9f5a9ccd115fc19c77cebe03c + placement: ghcr.io/vexxhost/atmosphere/placement:2023.2@sha256:439732fb29bdda398de9889e06a0e6052f13e2f9f5a9ccd115fc19c77cebe03c prometheus_config_reloader: quay.io/prometheus-operator/prometheus-config-reloader:v0.67.1@sha256:0fe3cf36985e0e524801a0393f88fa4b5dd5ffdf0f091ff78ee02f2d281631b5 prometheus_ipmi_exporter: us-docker.pkg.dev/vexxhost-infra/openstack/ipmi-exporter:1.4.0@sha256:4898da9cc11961a56363e8b3f3437d0f45b46585b20c79e33e97fbe7232e05d2 prometheus_memcached_exporter: quay.io/prometheus/memcached-exporter:v0.10.0@sha256:fa5a2de1a4744da66fb369bee81232f5ea52208bc643e409a60f66d699ac27b2 @@ -182,12 +182,12 @@ _atmosphere_images: rabbitmq_server: docker.io/library/rabbitmq:3.10.2-management@sha256:350ab6d773e3af45183466488fe3259df36cd6ade437b4366a59e8052458cc3a rabbitmq_topology_operator: docker.io/rabbitmqoperator/messaging-topology-operator:1.6.0@sha256:5052e8bdb26996c62315f0707c6fb291fd84492e360cca7351e2c3fdf659be43 rook_ceph: docker.io/rook/ceph:v1.10.10@sha256:9ae0eca578ef6e38492e5f90073050491382d8772914ddb8ffe4fca8d365b850 - senlin_api: ghcr.io/vexxhost/atmosphere/senlin:zed@sha256:df168fbf7dce6f4bc6de334b596d832237a4a4f3e6da235f5929282142b35112 - senlin_conductor: ghcr.io/vexxhost/atmosphere/senlin:zed@sha256:df168fbf7dce6f4bc6de334b596d832237a4a4f3e6da235f5929282142b35112 - senlin_db_sync: ghcr.io/vexxhost/atmosphere/senlin:zed@sha256:df168fbf7dce6f4bc6de334b596d832237a4a4f3e6da235f5929282142b35112 - senlin_engine_cleaner: ghcr.io/vexxhost/atmosphere/senlin:zed@sha256:df168fbf7dce6f4bc6de334b596d832237a4a4f3e6da235f5929282142b35112 - senlin_engine: ghcr.io/vexxhost/atmosphere/senlin:zed@sha256:df168fbf7dce6f4bc6de334b596d832237a4a4f3e6da235f5929282142b35112 - senlin_health_manager: ghcr.io/vexxhost/atmosphere/senlin:zed@sha256:df168fbf7dce6f4bc6de334b596d832237a4a4f3e6da235f5929282142b35112 + senlin_api: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:f718174547f3f66e5af758a10c87f7a75e9cbe1fe277cef27130fd512f727401 + senlin_conductor: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:f718174547f3f66e5af758a10c87f7a75e9cbe1fe277cef27130fd512f727401 + senlin_db_sync: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:f718174547f3f66e5af758a10c87f7a75e9cbe1fe277cef27130fd512f727401 + senlin_engine_cleaner: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:f718174547f3f66e5af758a10c87f7a75e9cbe1fe277cef27130fd512f727401 + senlin_engine: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:f718174547f3f66e5af758a10c87f7a75e9cbe1fe277cef27130fd512f727401 + senlin_health_manager: ghcr.io/vexxhost/atmosphere/senlin:2023.2@sha256:f718174547f3f66e5af758a10c87f7a75e9cbe1fe277cef27130fd512f727401 staffeln_db_sync: ghcr.io/vexxhost/staffeln:v2.2.3@sha256:ee3d8ab2c17d21b4a64a48abfb089df98700b6bc7cee5db36b5ef9c357317736 staffeln_conductor: ghcr.io/vexxhost/staffeln:v2.2.3@sha256:ee3d8ab2c17d21b4a64a48abfb089df98700b6bc7cee5db36b5ef9c357317736 staffeln_api: ghcr.io/vexxhost/staffeln:v2.2.3@sha256:ee3d8ab2c17d21b4a64a48abfb089df98700b6bc7cee5db36b5ef9c357317736