feat: upgrade to bobcat (#887)
diff --git a/.github/renovate.json b/.github/renovate.json
index 8e4fae4..c9fc620 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=(?<depName>.*)",
- "ARG RELEASE=(?<version>.*)",
- "ARG REF=(?<currentDigest>.*)"
+ "ARG --global RELEASE=(?<version>.*)",
+ "ARG --global PROJECT=(?<depName>.*)",
+ "ARG --global PROJECT_REF=(?<currentDigest>.*)"
]
},
{
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index bb25beb..17c6b27 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -6,7 +6,7 @@
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 888110c..4ae563e 100644
--- a/Earthfile
+++ b/Earthfile
@@ -27,7 +27,6 @@
--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 0000000..4a7acfb
--- /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 512b9db..0000000
--- 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 f5ff111..21cd0d8 100644
--- a/images/Earthfile
+++ b/images/Earthfile
@@ -29,17 +29,23 @@
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 af81b11..0c843ff 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 c075abc..89449e0 100644
--- a/images/base/Earthfile
+++ b/images/base/Earthfile
@@ -2,3 +2,4 @@
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 c02de0c..402127f 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 f3014be..d88dc10 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 8e203c9..c40c403 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 0000000..d57f318
--- /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 <abogott@wikimedia.org>
+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 87ee43b..c55fc42 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 6ff9199..fe9ac5f 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 50d68c9..211d055 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 <okozachenko1203@gmail.com>
Date: Thu, 2 Nov 2023 01:27:20 +1100
Subject: [PATCH] fix: ignore errors when flavors are deleted
@@ -13,7 +13,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..2e5b936
--- /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 <jeremyboylet@gmail.com>
+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 <jeremyboylet@gmail.com>
+
+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 88%
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 aaa5058..a64b453 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 <mnaser@vexxhost.com>
Date: Mon, 20 Feb 2023 00:55:14 +0000
Subject: [PATCH] fix: disable resizing for admins
@@ -11,14 +11,13 @@
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 @@
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 @@
};
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 @@
});
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 74b2ed9..5edcd7c 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 9478a03..7aae428 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 @@
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 0000000..83689fa
--- /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 <andrew.bonney@bbc.co.uk>
+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 07c358f..31792d2 100644
--- a/images/libvirtd/Earthfile
+++ b/images/libvirtd/Earthfile
@@ -3,7 +3,6 @@
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 f7e189f..645d99c 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 8d7c411..0000000
--- 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 <mnaser@vexxhost.com>
-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 <jakub@stackhpc.com>
----
- .../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 bc69c96..0000000
--- 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 <dxm523@gmail.com>
-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 <dxm523@gmail.com>
-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 a79d935..0000000
--- 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 <dale@catalystcloud.nz>
-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 7d302cf..0000000
--- 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 <mnasiadka@gmail.com>
-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`
- <https://hub.docker.com/r/k8scloudprovider/cinder-csi-plugin/tags>`_.
- 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
- <https://quay.io/repository/k8scsi/csi-attacher?tab=tags>`_.
- 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
- <https://quay.io/repository/k8scsi/csi-provisioner?tab=tags>`_.
- 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
- <https://quay.io/repository/k8scsi/csi-snapshotter?tab=tags>`_.
- 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
- <https://quay.io/repository/k8scsi/csi-resizer?tab=tags>`_.
- 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
- <https://quay.io/repository/k8scsi/csi-node-driver-registrar?tab=tags>`_.
- 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 <<EOF | kubectl apply -f -
-+---
-+apiVersion: v1
-+kind: Secret
-+metadata:
-+ name: cinder-csi-cloud-config
-+ namespace: kube-system
-+type: Opaque
-+stringData:
-+ cloud-config: |-
-+ [Global]
-+ auth-url=$AUTH_URL
-+ user-id=$TRUSTEE_USER_ID
-+ password=$TRUSTEE_PASSWORD
-+ trust-id=$TRUST_ID
-+ region=$REGION_NAME
-+ ca-file=/etc/kubernetes/ca-bundle.crt
-+EOF
-+
-+ kubectl apply -f ${{CINDER_CSI_DEPLOY}}
-+fi
-+printf "Finished running ${{step}}\\n"
-+"""
-+
-+with open("magnum/drivers/common/templates/kubernetes/fragments/enable-cinder-csi.sh", "w") as fd:
-+ fd.write(template)
diff --git a/images/magnum/patches/0005-secure-rbac.patch b/images/magnum/patches/0005-secure-rbac.patch
deleted file mode 100644
index 4f4ea6e..0000000
--- a/images/magnum/patches/0005-secure-rbac.patch
+++ /dev/null
@@ -1,1969 +0,0 @@
-From 7ffb23c87d04ea2c7f5b07a0af98573cb69379e0 Mon Sep 17 00:00:00 2001
-From: Rico Lin <ricolin@ricolky.com>
-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 320fc8f..5718142 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 a55e4e6..c904b26 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 <mnaser@vexxhost.com>
-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 @@
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 @@
def downgrade_export_locations_table(connection):
+--
+2.34.1
+
diff --git a/images/neutron/Earthfile b/images/neutron/Earthfile
index 8b61017..a9b4712 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 85%
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 a1540ad..a20200b 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 <felix.huettner@mail.schwarz>
Date: Fri, 22 Sep 2023 16:25:10 +0200
Subject: [PATCH] fix netns deletion of broken namespaces
@@ -26,13 +26,19 @@
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 @@
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 @@
# 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 @@
+ 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 @@
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 3d86b60..2780578 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 16e5799..d37ba36 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 1962f42..beede4e 100644
--- a/images/openstack-service/2023.1/upper-constraints.txt
+++ b/images/openstack-service/2023.1/upper-constraints.txt
@@ -540,7 +540,6 @@
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 52c2338..2e62bc7 100644
--- a/images/openstack-service/2023.2/upper-constraints.txt
+++ b/images/openstack-service/2023.2/upper-constraints.txt
@@ -549,7 +549,6 @@
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 20c1f50..7029432 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 @@
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 1b044b9..667fcb5 100644
--- a/images/openstack-service/master/upper-constraints.txt
+++ b/images/openstack-service/master/upper-constraints.txt
@@ -553,7 +553,6 @@
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 1d844e3..6d94a1a 100644
--- a/images/openstack-service/zed/upper-constraints.txt
+++ b/images/openstack-service/zed/upper-constraints.txt
@@ -541,7 +541,6 @@
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 81a3369..64d6afd 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 60da266..7e67788 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 062d82a..9f180c7 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 7ff5bcc..dc34073 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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