replacing my package-lock with masters

This commit is contained in:
Ana Clara Zoppi Serpa 2024-06-11 12:50:59 -07:00
Родитель 5875f5d98d a70b607697
Коммит 2ee5231333
139 изменённых файлов: 23716 добавлений и 20269 удалений

2
.github/workflows/golint.yml поставляемый
Просмотреть файл

@ -25,7 +25,7 @@ jobs:
go-version-file: go.mod
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v6
with:
version: v1.56.2
args: -v --timeout 15m

12
Dockerfile.ci-azext-aro Normal file
Просмотреть файл

@ -0,0 +1,12 @@
FROM mcr.microsoft.com/azure-cli:2.61.0 AS builder
RUN pip install pytest
COPY /python /data/
WORKDIR /data/az/aro
RUN pytest --ignore=azext_aro/tests/latest/integration
RUN python3 setup.py bdist_wheel
FROM mcr.microsoft.com/azure-cli:2.61.0-cbl-mariner2.0 AS final
COPY --from=builder /data/az/aro/dist /opt/az
RUN az extension add --yes --source /opt/az/aro-*-py2.py3-none-any.whl

Просмотреть файл

@ -6,6 +6,7 @@ ARG ARO_VERSION
# builder is responsible for all compilation and validation of the RP
###############################################################################
FROM ${REGISTRY}/ubi8/nodejs-16 as portal-build
LABEL aro-portal-build=true
WORKDIR /build/portal/v2
USER root
@ -23,6 +24,7 @@ RUN npm run lint && npm run build
###############################################################################
FROM ${REGISTRY}/ubi8/go-toolset:1.20.12-5 AS builder
ARG ARO_VERSION
LABEL aro-builder=true
USER root
WORKDIR /app
@ -54,13 +56,14 @@ RUN go build -ldflags "-X github.com/Azure/ARO-RP/pkg/util/version.GitCommit=${A
RUN go test ./test/e2e/... -tags e2e,codec.safe -c -ldflags "-X github.com/Azure/ARO-RP/pkg/util/version.GitCommit=${ARO_VERSION}" -o e2e.test
# Additional tests
RUN ARO_RUN_PKI_TESTS=nope go run gotest.tools/gotestsum@v1.11.0 --format pkgname --junitfile report.xml -- -coverprofile=cover.out ./...
RUN ARO_SKIP_PKI_TESTS=true go run gotest.tools/gotestsum@v1.11.0 --format pkgname --junitfile report.xml -- -coverprofile=cover.out ./...
RUN hack/fips/validate-fips.sh ./aro
###############################################################################
# Stage 3: final is our slim image with minimal layers and tools
###############################################################################
FROM ${REGISTRY}/ubi8/ubi-minimal AS final
LABEL aro-final=true
RUN microdnf update && microdnf clean all
COPY --from=builder /app/aro /app/e2e.test /usr/local/bin/
ENTRYPOINT ["aro"]

Просмотреть файл

@ -14,7 +14,7 @@ WORKDIR ${GOPATH}/src/github.com/open-policy-agent/gatekeeper
USER root
RUN curl -Lq $DOWNLOAD_URL | tar -xz --strip-components=1
RUN go build -mod vendor -a -ldflags "-X github.com/open-policy-agent/gatekeeper/pkg/version.Version=latest" -o manager
RUN go build -mod vendor -a -ldflags "-X github.com/open-policy-agent/gatekeeper/pkg/version.Version=$GATEKEEPER_VERSION" -o manager
#### Runtime container
FROM ${REGISTRY}/ubi8/ubi-minimal:latest

Просмотреть файл

@ -14,8 +14,7 @@ FLUENTBIT_VERSION = 1.9.10
FLUENTBIT_IMAGE ?= ${RP_IMAGE_ACR}.azurecr.io/fluentbit:$(FLUENTBIT_VERSION)-cm$(MARINER_VERSION)
AUTOREST_VERSION = 3.6.3
AUTOREST_IMAGE = quay.io/openshift-on-azure/autorest:${AUTOREST_VERSION}
GATEKEEPER_VERSION = v3.10.0
GATEKEEPER_IMAGE ?= ${RP_IMAGE_ACR}.azurecr.io/gatekeeper:$(GATEKEEPER_VERSION)
GATEKEEPER_VERSION = v3.15.1
GOTESTSUM = gotest.tools/gotestsum@v1.11.0
ifneq ($(shell uname -s),Darwin)
@ -40,6 +39,7 @@ else
endif
ARO_IMAGE ?= $(ARO_IMAGE_BASE):$(VERSION)
GATEKEEPER_IMAGE ?= ${REGISTRY}/gatekeeper:$(GATEKEEPER_VERSION)
check-release:
# Check that VERSION is a valid tag when building an official release (when RELEASE=true).
@ -67,6 +67,10 @@ az: pyenv
python3 ./setup.py bdist_wheel || true && \
rm -f ~/.azure/commandIndex.json # https://github.com/Azure/azure-cli/issues/14997
.PHONY: azext-aro
azext-aro:
docker build --platform=linux/amd64 . -f Dockerfile.ci-azext-aro --no-cache=$(NO_CACHE) -t azext-aro:latest
clean:
rm -rf python/az/aro/{aro.egg-info,build,dist} aro
find python -type f -name '*.pyc' -delete
@ -79,6 +83,9 @@ client: generate
ci-rp: fix-macos-vendor
docker build . -f Dockerfile.ci-rp --ulimit=nofile=4096:4096 --build-arg REGISTRY=$(REGISTRY) --build-arg ARO_VERSION=$(VERSION) --no-cache=$(NO_CACHE)
ci-clean:
docker image prune --all --filter="label=aro-*=true"
# TODO: hard coding dev-config.yaml is clunky; it is also probably convenient to
# override COMMIT.
deploy:
@ -278,4 +285,4 @@ vendor:
install-go-tools:
go install ${GOTESTSUM}
.PHONY: admin.kubeconfig aks.kubeconfig aro az ci-portal ci-rp clean client deploy dev-config.yaml discoverycache fix-macos-vendor generate image-aro-multistage image-fluentbit image-proxy init-contrib lint-go runlocal-rp proxy publish-image-aro-multistage publish-image-fluentbit publish-image-proxy secrets secrets-update e2e.test tunnel test-e2e test-go test-python vendor build-all validate-go unit-test-go coverage-go validate-fips install-go-tools
.PHONY: admin.kubeconfig aks.kubeconfig aro az ci-rp ci-clean clean client deploy dev-config.yaml discoverycache fix-macos-vendor generate image-aro-multistage image-fluentbit image-proxy init-contrib lint-go runlocal-rp proxy publish-image-aro-multistage publish-image-fluentbit publish-image-proxy secrets secrets-update e2e.test tunnel test-e2e test-go test-python vendor build-all validate-go unit-test-go coverage-go validate-fips install-go-tools

Просмотреть файл

@ -12,7 +12,6 @@ import (
"os"
"strings"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/containers/image/v5/types"
"github.com/sirupsen/logrus"
@ -74,33 +73,10 @@ func mirror(ctx context.Context, log *logrus.Entry) error {
return err
}
// Geneva allows anonymous pulls
var srcAuthGeneva *types.DockerAuthConfig
// We can lose visibility of early image mirroring errors because logs are trimmed in the output of Ev2 pipelines.
// If images fail to mirror, those errors need to be returned together and logged at the end of the execution.
var imageMirroringErrors []string
// Geneva mirroring from upstream only takes place in Public Cloud, in
// sovereign clouds a separate mirror process mirrors from the public cloud
if env.Environment().Environment == azure.PublicCloud {
srcAcrGeneva := "linuxgeneva-microsoft" + acrDomainSuffix
mirrorImages := []string{
// https://eng.ms/docs/products/geneva/collect/references/linuxcontainers
srcAcrGeneva + "/distroless/genevamdm:2.2024.328.1744-c5fb79-20240328t1935",
srcAcrGeneva + "/distroless/genevamdsd:mariner_20240327.2",
}
for _, ref := range mirrorImages {
log.Printf("mirroring %s -> %s", ref, pkgmirror.DestLastIndex(dstAcr+acrDomainSuffix, ref))
err = pkgmirror.Copy(ctx, pkgmirror.DestLastIndex(dstAcr+acrDomainSuffix, ref), ref, dstAuth, srcAuthGeneva)
if err != nil {
imageMirroringErrors = append(imageMirroringErrors, fmt.Sprintf("%s: %s\n", ref, err))
}
}
} else {
log.Printf("skipping Geneva mirroring due to not being in Public")
}
for _, ref := range []string{
// https://mcr.microsoft.com/en-us/product/azure-cli/about
@ -134,7 +110,7 @@ func mirror(ctx context.Context, log *logrus.Entry) error {
"quay.io/app-sre/managed-upgrade-operator:v0.1.952-44b631a",
// https://quay.io/repository/app-sre/hive?tab=tags
"quay.io/app-sre/hive:83aedb9f6e",
"quay.io/app-sre/hive:d7ead609f4",
} {
log.Printf("mirroring %s -> %s", ref, pkgmirror.Dest(dstAcr+acrDomainSuffix, ref))

Просмотреть файл

@ -163,6 +163,11 @@ func rp(ctx context.Context, log, audit *logrus.Entry) error {
return err
}
dbPlatformWorkloadIdentityRoleSets, err := database.NewPlatformWorkloadIdentityRoleSets(ctx, dbc, dbName)
if err != nil {
return err
}
go database.EmitMetrics(ctx, log, dbOpenShiftClusters, metrics)
feAead, err := encryption.NewMulti(ctx, _env.ServiceKeyvault(), env.FrontendEncryptionSecretV2Name, env.FrontendEncryptionSecretName)
@ -173,7 +178,7 @@ func rp(ctx context.Context, log, audit *logrus.Entry) error {
if err != nil {
return err
}
f, err := frontend.NewFrontend(ctx, audit, log.WithField("component", "frontend"), _env, dbAsyncOperations, dbClusterManagerConfiguration, dbOpenShiftClusters, dbSubscriptions, dbOpenShiftVersions, api.APIs, metrics, clusterm, feAead, hiveClusterManager, adminactions.NewKubeActions, adminactions.NewAzureActions, clusterdata.NewParallelEnricher(metrics, _env))
f, err := frontend.NewFrontend(ctx, audit, log.WithField("component", "frontend"), _env, dbAsyncOperations, dbClusterManagerConfiguration, dbOpenShiftClusters, dbSubscriptions, dbOpenShiftVersions, dbPlatformWorkloadIdentityRoleSets, api.APIs, metrics, clusterm, feAead, hiveClusterManager, adminactions.NewKubeActions, adminactions.NewAzureActions, clusterdata.NewParallelEnricher(metrics, _env))
if err != nil {
return err
}

Просмотреть файл

@ -3,4 +3,6 @@ export ARO_IMAGE=arointsvc.azurecr.io/aro:latest
export NO_CACHE=false
export AZURE_EXTENSION_DEV_SOURCES="$(pwd)/python"
export ARO_SKIP_PKI_TESTS=true
. secrets/env

10
go.mod
Просмотреть файл

@ -18,7 +18,7 @@ require (
github.com/alvaroloes/enumer v1.1.2
github.com/apparentlymart/go-cidr v1.1.0
github.com/codahale/etm v0.0.0-20141003032925-c00c9e6fb4c9
github.com/containers/image/v5 v5.29.2
github.com/containers/image/v5 v5.29.3
github.com/containers/podman/v4 v4.9.4
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/coreos/go-semver v0.3.0
@ -29,7 +29,7 @@ require (
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-bindata/go-bindata v3.1.2+incompatible
github.com/go-chi/chi/v5 v5.0.8
github.com/go-logr/logr v1.4.1
github.com/go-logr/logr v1.4.2
github.com/go-test/deep v1.1.0
github.com/gofrs/uuid v4.2.0+incompatible
github.com/golang-jwt/jwt/v4 v4.5.0
@ -59,7 +59,7 @@ require (
github.com/openshift/api v3.9.1-0.20191111211345-a27ff30ebf09+incompatible
github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a
github.com/openshift/cloud-credential-operator v0.0.0-00010101000000-000000000000
github.com/openshift/hive/apis v0.0.0-20240510150258-83aedb9f6e73
github.com/openshift/hive/apis v0.0.0-20240529172037-d7ead609f495
github.com/openshift/library-go v0.0.0-20220525173854-9b950a41acdc
github.com/openshift/machine-config-operator v0.0.1-0.20230519222939-1abc13efbb0d
github.com/pires/go-proxyproto v0.6.2
@ -80,9 +80,9 @@ require (
golang.org/x/sync v0.6.0
golang.org/x/text v0.15.0
golang.org/x/tools v0.19.0
k8s.io/api v0.30.0
k8s.io/api v0.30.1
k8s.io/apiextensions-apiserver v0.25.0
k8s.io/apimachinery v0.30.0
k8s.io/apimachinery v0.30.1
k8s.io/cli-runtime v0.25.16
k8s.io/client-go v0.26.2
k8s.io/code-generator v0.25.16

8
go.sum
Просмотреть файл

@ -122,8 +122,8 @@ github.com/containers/buildah v1.33.7 h1:Y2kNea+hNNyZ74ppYFWmD0cLc/DwZ5A4NEUPQWP
github.com/containers/buildah v1.33.7/go.mod h1:pphfdjrwtTWkuIy1aDyZMEVyMfmm0DsbvxLGxxEU1cM=
github.com/containers/common v0.57.4 h1:kmfBad92kUjP5X44BPpOwMe+eZQqaKETfS+ASeL0g+g=
github.com/containers/common v0.57.4/go.mod h1:o3L3CyOI9yr+JC8l4dZgvqTxcjs3qdKmkek00uchgvw=
github.com/containers/image/v5 v5.29.2 h1:b8U0XYWhaQbKucK73IbmSm8WQyKAhKDbAHQc45XlsOw=
github.com/containers/image/v5 v5.29.2/go.mod h1:kQ7qcDsps424ZAz24thD+x7+dJw1vgur3A9tTDsj97E=
github.com/containers/image/v5 v5.29.3 h1:RJHdxP+ZiC+loIFG2DTmjlVNWTS7o5jrdrRScUrY1VE=
github.com/containers/image/v5 v5.29.3/go.mod h1:kQ7qcDsps424ZAz24thD+x7+dJw1vgur3A9tTDsj97E=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.1.9 h1:2Csfba4jse85Raxk5HIyEk8OwZNjRvfkhEGijOjIdEM=
@ -233,8 +233,8 @@ github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQr
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=

Просмотреть файл

@ -33,14 +33,14 @@ type PlatformWorkloadIdentityRoleSetProperties struct {
// PlatformWorkloadIdentityRole represents a mapping from a particular OCP operator to the built-in role that should be assigned to that operator's corresponding managed identity.
type PlatformWorkloadIdentityRole struct {
// OperatorName represents the name of the operator that this role is for.
OperatorName string `json:"operatorName,omitempty" mutable:"true"`
OperatorName string `json:"operatorName,omitempty" mutable:"true" validate:"required"`
// RoleDefinitionName represents the name of the role.
RoleDefinitionName string `json:"roleDefinitionName,omitempty" mutable:"true"`
RoleDefinitionName string `json:"roleDefinitionName,omitempty" mutable:"true" validate:"required"`
// RoleDefinitionID represents the resource ID of the role definition.
RoleDefinitionID string `json:"roleDefinitionId,omitempty" mutable:"true"`
RoleDefinitionID string `json:"roleDefinitionId,omitempty" mutable:"true" validate:"required"`
// ServiceAccounts represents the set of service accounts associated with the given operator, since each service account needs its own federated credential.
ServiceAccounts []string `json:"serviceAccounts,omitempty" mutable:"true"`
ServiceAccounts []string `json:"serviceAccounts,omitempty" mutable:"true" validate:"required"`
}

Просмотреть файл

@ -1,11 +1,10 @@
package admin
import "github.com/Azure/ARO-RP/pkg/api"
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
/*
TODO: Uncomment once API endpoints have been implemented and this code is being used.
type platformWorkloadIdentityRoleSetConverter struct{}
// platformWorkloadIdentityRoleSetConverter.ToExternal returns a new external representation
@ -21,12 +20,17 @@ func (c platformWorkloadIdentityRoleSetConverter) ToExternal(s *api.PlatformWork
},
}
for i, r := range s.Properties.PlatformWorkloadIdentityRoles {
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = make([]string, 0, len(r.ServiceAccounts))
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = append(out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts, r.ServiceAccounts...)
for _, r := range s.Properties.PlatformWorkloadIdentityRoles {
role := PlatformWorkloadIdentityRole{
OperatorName: r.OperatorName,
RoleDefinitionName: r.RoleDefinitionName,
RoleDefinitionID: r.RoleDefinitionID,
ServiceAccounts: make([]string, 0, len(r.ServiceAccounts)),
}
role.ServiceAccounts = append(role.ServiceAccounts, r.ServiceAccounts...)
out.Properties.PlatformWorkloadIdentityRoles = append(out.Properties.PlatformWorkloadIdentityRoles, role)
}
return out
@ -56,12 +60,16 @@ func (c platformWorkloadIdentityRoleSetConverter) ToInternal(_new interface{}, o
out.Properties.OpenShiftVersion = new.Properties.OpenShiftVersion
out.Properties.PlatformWorkloadIdentityRoles = make([]api.PlatformWorkloadIdentityRole, 0, len(new.Properties.PlatformWorkloadIdentityRoles))
for i, r := range new.Properties.PlatformWorkloadIdentityRoles {
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = make([]string, 0, len(r.ServiceAccounts))
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = append(out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts, r.ServiceAccounts...)
for _, r := range new.Properties.PlatformWorkloadIdentityRoles {
role := api.PlatformWorkloadIdentityRole{
OperatorName: r.OperatorName,
RoleDefinitionName: r.RoleDefinitionName,
RoleDefinitionID: r.RoleDefinitionID,
ServiceAccounts: make([]string, 0, len(r.ServiceAccounts)),
}
role.ServiceAccounts = append(role.ServiceAccounts, r.ServiceAccounts...)
out.Properties.PlatformWorkloadIdentityRoles = append(out.Properties.PlatformWorkloadIdentityRoles, role)
}
}
*/

Просмотреть файл

@ -1,11 +1,17 @@
package admin
import (
"fmt"
"net/http"
"strings"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/util/immutable"
)
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
/*
TODO: Uncomment once API endpoints have been implemented and this code is being used.
type platformWorkloadIdentityRoleSetStaticValidator struct{}
func (sv platformWorkloadIdentityRoleSetStaticValidator) Static(_new interface{}, _current *api.PlatformWorkloadIdentityRoleSet) error {
@ -37,27 +43,31 @@ func (sv platformWorkloadIdentityRoleSetStaticValidator) validate(new *PlatformW
return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "properties.platformWorkloadIdentityRoles", "Must be provided and must be non-empty")
}
errs := []error{}
missingProperties := []string{}
for i, r := range new.Properties.PlatformWorkloadIdentityRoles {
if r.OperatorName == "" {
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].operatorName", i), "Must be provided"))
missingProperties = append(missingProperties, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].operatorName", i))
}
if r.RoleDefinitionName == "" {
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].roleDefinitionName", i), "Must be provided"))
missingProperties = append(missingProperties, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].roleDefinitionName", i))
}
if r.RoleDefinitionID == "" {
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].roleDefinitionId", i), "Must be provided"))
missingProperties = append(missingProperties, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].roleDefinitionId", i))
}
if r.ServiceAccounts == nil || len(r.ServiceAccounts) == 0 {
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].serviceAccounts", i), "Must be provided and must be non-empty"))
missingProperties = append(missingProperties, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].serviceAccounts", i))
}
}
return errors.Join(errs...)
if len(missingProperties) > 0 {
return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, strings.Join(missingProperties, ", "), "Must be provided")
}
return nil
}
func (sv platformWorkloadIdentityRoleSetStaticValidator) validateDelta(new, current *PlatformWorkloadIdentityRoleSet) error {
@ -68,4 +78,3 @@ func (sv platformWorkloadIdentityRoleSetStaticValidator) validateDelta(new, curr
}
return nil
}
*/

Просмотреть файл

@ -12,9 +12,11 @@ const APIVersion = "admin"
func init() {
api.APIs[APIVersion] = &api.Version{
OpenShiftClusterConverter: openShiftClusterConverter{},
OpenShiftClusterStaticValidator: openShiftClusterStaticValidator{},
OpenShiftVersionConverter: openShiftVersionConverter{},
OpenShiftVersionStaticValidator: openShiftVersionStaticValidator{},
OpenShiftClusterConverter: openShiftClusterConverter{},
OpenShiftClusterStaticValidator: openShiftClusterStaticValidator{},
OpenShiftVersionConverter: openShiftVersionConverter{},
OpenShiftVersionStaticValidator: openShiftVersionStaticValidator{},
PlatformWorkloadIdentityRoleSetConverter: platformWorkloadIdentityRoleSetConverter{},
PlatformWorkloadIdentityRoleSetStaticValidator: platformWorkloadIdentityRoleSetStaticValidator{},
}
}

Просмотреть файл

@ -37,6 +37,16 @@ type OpenShiftVersionStaticValidator interface {
Static(interface{}, *OpenShiftVersion) error
}
type PlatformWorkloadIdentityRoleSetConverter interface {
ToExternal(*PlatformWorkloadIdentityRoleSet) interface{}
ToExternalList([]*PlatformWorkloadIdentityRoleSet) interface{}
ToInternal(interface{}, *PlatformWorkloadIdentityRoleSet)
}
type PlatformWorkloadIdentityRoleSetStaticValidator interface {
Static(interface{}, *PlatformWorkloadIdentityRoleSet) error
}
type SyncSetConverter interface {
ToExternal(*SyncSet) interface{}
ToExternalList([]*SyncSet) interface{}
@ -63,18 +73,20 @@ type SecretConverter interface {
// Version is a set of endpoints implemented by each API version
type Version struct {
OpenShiftClusterConverter OpenShiftClusterConverter
OpenShiftClusterStaticValidator OpenShiftClusterStaticValidator
OpenShiftClusterCredentialsConverter OpenShiftClusterCredentialsConverter
OpenShiftClusterAdminKubeconfigConverter OpenShiftClusterAdminKubeconfigConverter
OpenShiftVersionConverter OpenShiftVersionConverter
OpenShiftVersionStaticValidator OpenShiftVersionStaticValidator
OperationList OperationList
SyncSetConverter SyncSetConverter
MachinePoolConverter MachinePoolConverter
SyncIdentityProviderConverter SyncIdentityProviderConverter
SecretConverter SecretConverter
ClusterManagerStaticValidator ClusterManagerStaticValidator
OpenShiftClusterConverter OpenShiftClusterConverter
OpenShiftClusterStaticValidator OpenShiftClusterStaticValidator
OpenShiftClusterCredentialsConverter OpenShiftClusterCredentialsConverter
OpenShiftClusterAdminKubeconfigConverter OpenShiftClusterAdminKubeconfigConverter
OpenShiftVersionConverter OpenShiftVersionConverter
OpenShiftVersionStaticValidator OpenShiftVersionStaticValidator
PlatformWorkloadIdentityRoleSetConverter PlatformWorkloadIdentityRoleSetConverter
PlatformWorkloadIdentityRoleSetStaticValidator PlatformWorkloadIdentityRoleSetStaticValidator
OperationList OperationList
SyncSetConverter SyncSetConverter
MachinePoolConverter MachinePoolConverter
SyncIdentityProviderConverter SyncIdentityProviderConverter
SecretConverter SecretConverter
ClusterManagerStaticValidator ClusterManagerStaticValidator
}
// APIs is the map of registered API versions

Просмотреть файл

@ -24,10 +24,13 @@ func (c platformWorkloadIdentityRoleSetConverter) ToExternal(s *api.PlatformWork
},
}
for i, r := range s.Properties.PlatformWorkloadIdentityRoles {
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
for _, r := range s.Properties.PlatformWorkloadIdentityRoles {
role := PlatformWorkloadIdentityRole{
OperatorName: r.OperatorName,
RoleDefinitionName: r.RoleDefinitionName,
RoleDefinitionID: r.RoleDefinitionID,
}
out.Properties.PlatformWorkloadIdentityRoles = append(out.Properties.PlatformWorkloadIdentityRoles, role)
}
return out
@ -57,9 +60,12 @@ func (c platformWorkloadIdentityRoleSetConverter) ToInternal(_new interface{}, o
out.Properties.OpenShiftVersion = new.Properties.OpenShiftVersion
out.Properties.PlatformWorkloadIdentityRoles = make([]api.PlatformWorkloadIdentityRole, 0, len(new.Properties.PlatformWorkloadIdentityRoles))
for i, r := range new.Properties.PlatformWorkloadIdentityRoles {
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
for _, r := range new.Properties.PlatformWorkloadIdentityRoles {
role := api.PlatformWorkloadIdentityRole{
OperatorName: r.OperatorName,
RoleDefinitionName: r.RoleDefinitionName,
RoleDefinitionID: r.RoleDefinitionID,
}
out.Properties.PlatformWorkloadIdentityRoles = append(out.Properties.PlatformWorkloadIdentityRoles, role)
}
}

Просмотреть файл

@ -22,6 +22,7 @@ func init() {
OpenShiftClusterCredentialsConverter: openShiftClusterCredentialsConverter{},
OpenShiftClusterAdminKubeconfigConverter: openShiftClusterAdminKubeconfigConverter{},
OpenShiftVersionConverter: openShiftVersionConverter{},
PlatformWorkloadIdentityRoleSetConverter: platformWorkloadIdentityRoleSetConverter{},
OperationList: api.OperationList{
Operations: []api.Operation{
api.OperationResultsRead,

Просмотреть файл

@ -7,6 +7,8 @@ import (
"context"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
configclient "github.com/openshift/client-go/config/clientset/versioned"
@ -31,6 +33,7 @@ import (
aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned"
"github.com/Azure/ARO-RP/pkg/operator/deploy"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armnetwork"
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/common"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/authorization"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/compute"
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/features"
@ -72,7 +75,8 @@ type manager struct {
virtualMachines compute.VirtualMachinesClient
interfaces network.InterfacesClient // TODO: use armInterfaces instead.
armInterfaces armnetwork.InterfacesClient
publicIPAddresses network.PublicIPAddressesClient
publicIPAddresses network.PublicIPAddressesClient // TODO: use armPublicIPAddresses instead.
armPublicIPAddresses armnetwork.PublicIPAddressesClient
loadBalancers network.LoadBalancersClient // TODO: use armLoadBalancers instead.
armLoadBalancers armnetwork.LoadBalancersClient
privateEndpoints network.PrivateEndpointsClient
@ -159,12 +163,24 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
return nil, err
}
armLoadBalancersClient, err := armnetwork.NewLoadBalancersClient(_env.Environment(), r.SubscriptionID, fpCredential)
clientOptions := arm.ClientOptions{
ClientOptions: azcore.ClientOptions{
Cloud: _env.Environment().Cloud,
Retry: common.RetryOptions,
},
}
armLoadBalancersClient, err := armnetwork.NewLoadBalancersClient(r.SubscriptionID, fpCredential, &clientOptions)
if err != nil {
return nil, err
}
armInterfacesClient, err := armnetwork.NewInterfacesClient(_env.Environment(), r.SubscriptionID, fpCredential)
armInterfacesClient, err := armnetwork.NewInterfacesClient(r.SubscriptionID, fpCredential, &clientOptions)
if err != nil {
return nil, err
}
armPublicIPAddressesClient, err := armnetwork.NewPublicIPAddressesClient(r.SubscriptionID, fpCredential, &clientOptions)
if err != nil {
return nil, err
}
@ -186,6 +202,7 @@ func New(ctx context.Context, log *logrus.Entry, _env env.Interface, db database
interfaces: network.NewInterfacesClient(_env.Environment(), r.SubscriptionID, fpAuthorizer),
armInterfaces: armInterfacesClient,
publicIPAddresses: network.NewPublicIPAddressesClient(_env.Environment(), r.SubscriptionID, fpAuthorizer),
armPublicIPAddresses: armPublicIPAddressesClient,
loadBalancers: network.NewLoadBalancersClient(_env.Environment(), r.SubscriptionID, fpAuthorizer),
armLoadBalancers: armLoadBalancersClient,
privateEndpoints: network.NewPrivateEndpointsClient(_env.Environment(), r.SubscriptionID, fpAuthorizer),

Просмотреть файл

@ -164,25 +164,27 @@ func (m *manager) populateDatabaseIntIP(ctx context.Context) error {
return err
}
// this function can only be called on create - not on update - because it
// updateAPIIPEarly updates the `doc` with the public and private IP of the API server,
// and updates the DNS record of the API server according to the API server visibility.
// This function can only be called on create - not on update - because it
// refers to -pip-v4, which doesn't exist on pre-DNS change clusters.
func (m *manager) updateAPIIPEarly(ctx context.Context) error {
infraID := m.doc.OpenShiftCluster.Properties.InfraID
resourceGroup := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
lb, err := m.loadBalancers.Get(ctx, resourceGroup, infraID+"-internal", "")
lb, err := m.armLoadBalancers.Get(ctx, resourceGroup, infraID+"-internal", nil)
if err != nil {
return err
}
intIPAddress := *((*lb.FrontendIPConfigurations)[0].PrivateIPAddress)
intIPAddress := *lb.Properties.FrontendIPConfigurations[0].Properties.PrivateIPAddress
ipAddress := intIPAddress
if m.doc.OpenShiftCluster.Properties.APIServerProfile.Visibility == api.VisibilityPublic {
ip, err := m.publicIPAddresses.Get(ctx, resourceGroup, infraID+"-pip-v4", "")
ip, err := m.armPublicIPAddresses.Get(ctx, resourceGroup, infraID+"-pip-v4", nil)
if err != nil {
return err
}
ipAddress = *ip.IPAddress
ipAddress = *ip.Properties.IPAddress
}
err = m.dns.Update(ctx, m.doc.OpenShiftCluster, ipAddress)

Просмотреть файл

@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2"
mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network"
"github.com/Azure/go-autorest/autorest/to"
"github.com/golang/mock/gomock"
@ -18,6 +19,7 @@ import (
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/database/cosmosdb"
mock_armnetwork "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/azuresdk/armnetwork"
mock_network "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/network"
mock_dns "github.com/Azure/ARO-RP/pkg/util/mocks/dns"
mock_env "github.com/Azure/ARO-RP/pkg/util/mocks/env"
@ -26,6 +28,11 @@ import (
utilerror "github.com/Azure/ARO-RP/test/util/error"
)
const (
privateIP = "10.0.0.1"
publicIP = "1.2.3.4"
)
func TestCreateOrUpdateRouterIPFromCluster(t *testing.T) {
ctx := context.Background()
@ -61,7 +68,7 @@ func TestCreateOrUpdateRouterIPFromCluster(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = "1.2.3.4"
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = publicIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(dns *mock_dns.MockManager) {
@ -77,7 +84,7 @@ func TestCreateOrUpdateRouterIPFromCluster(t *testing.T) {
Status: corev1.ServiceStatus{
LoadBalancer: corev1.LoadBalancerStatus{
Ingress: []corev1.LoadBalancerIngress{{
IP: "1.2.3.4",
IP: publicIP,
}},
},
},
@ -217,7 +224,7 @@ func TestCreateOrUpdateRouterIPEarly(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = "1.2.3.4"
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = publicIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(publicIPAddresses *mock_network.MockPublicIPAddressesClient, dns *mock_dns.MockManager, subnet *mock_subnet.MockManager) {
@ -225,7 +232,7 @@ func TestCreateOrUpdateRouterIPEarly(t *testing.T) {
Get(gomock.Any(), "clusterResourceGroup", "infra-default-v4", "").
Return(mgmtnetwork.PublicIPAddress{
PublicIPAddressPropertiesFormat: &mgmtnetwork.PublicIPAddressPropertiesFormat{
IPAddress: to.StringPtr("1.2.3.4"),
IPAddress: to.StringPtr(publicIP),
},
}, nil)
dns.EXPECT().
@ -262,13 +269,13 @@ func TestCreateOrUpdateRouterIPEarly(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = "1.2.3.4"
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = publicIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(publicIPAddresses *mock_network.MockPublicIPAddressesClient, dns *mock_dns.MockManager, subnet *mock_subnet.MockManager) {
subnet.EXPECT().
GetHighestFreeIP(gomock.Any(), "subnetid").
Return("1.2.3.4", nil)
Return(publicIP, nil)
dns.EXPECT().
CreateOrUpdateRouter(gomock.Any(), gomock.Any(), gomock.Any()).
Return(nil)
@ -308,13 +315,13 @@ func TestCreateOrUpdateRouterIPEarly(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = "1.2.3.4"
doc.OpenShiftCluster.Properties.IngressProfiles[0].IP = publicIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(publicIPAddresses *mock_network.MockPublicIPAddressesClient, dns *mock_dns.MockManager, subnet *mock_subnet.MockManager) {
subnet.EXPECT().
GetHighestFreeIP(gomock.Any(), "enricheWPsubnetid").
Return("1.2.3.4", nil)
Return(publicIP, nil)
dns.EXPECT().
CreateOrUpdateRouter(gomock.Any(), gomock.Any(), gomock.Any()).
Return(nil)
@ -402,7 +409,7 @@ func TestPopulateDatabaseIntIP(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = "10.0.0.1"
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = privateIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(loadBalancers *mock_network.MockLoadBalancersClient) {
@ -413,7 +420,7 @@ func TestPopulateDatabaseIntIP(t *testing.T) {
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr("10.0.0.1"),
PrivateIPAddress: to.StringPtr(privateIP),
},
},
},
@ -441,7 +448,7 @@ func TestPopulateDatabaseIntIP(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = "10.0.0.1"
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = privateIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(loadBalancers *mock_network.MockLoadBalancersClient) {
@ -452,7 +459,7 @@ func TestPopulateDatabaseIntIP(t *testing.T) {
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr("10.0.0.1"),
PrivateIPAddress: to.StringPtr(privateIP),
},
},
},
@ -472,7 +479,7 @@ func TestPopulateDatabaseIntIP(t *testing.T) {
ResourceGroupID: resourceGroupID,
},
APIServerProfile: api.APIServerProfile{
IntIP: "10.0.0.1",
IntIP: privateIP,
},
ProvisioningState: api.ProvisioningStateCreating,
InfraID: "infra",
@ -540,7 +547,7 @@ func TestUpdateAPIIPEarly(t *testing.T) {
for _, tt := range []struct {
name string
fixtureChecker func(*testdatabase.Fixture, *testdatabase.Checker, *cosmosdb.FakeOpenShiftClusterDocumentClient)
mocks func(*mock_network.MockLoadBalancersClient, *mock_network.MockPublicIPAddressesClient, *mock_dns.MockManager)
mocks func(*mock_armnetwork.MockLoadBalancersClient, *mock_armnetwork.MockPublicIPAddressesClient, *mock_dns.MockManager)
wantErr string
}{
{
@ -565,33 +572,37 @@ func TestUpdateAPIIPEarly(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.APIServerProfile.IP = "1.2.3.4"
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = "10.0.0.1"
doc.OpenShiftCluster.Properties.APIServerProfile.IP = publicIP
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = privateIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(loadBalancers *mock_network.MockLoadBalancersClient, publicIPAddresses *mock_network.MockPublicIPAddressesClient, dns *mock_dns.MockManager) {
mocks: func(loadBalancers *mock_armnetwork.MockLoadBalancersClient, publicIPAddresses *mock_armnetwork.MockPublicIPAddressesClient, dns *mock_dns.MockManager) {
loadBalancers.EXPECT().
Get(gomock.Any(), "clusterResourceGroup", "infra-internal", "").
Return(mgmtnetwork.LoadBalancer{
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr("10.0.0.1"),
Get(gomock.Any(), "clusterResourceGroup", "infra-internal", nil).
Return(armnetwork.LoadBalancersClientGetResponse{
LoadBalancer: armnetwork.LoadBalancer{
Properties: &armnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
{
Properties: &armnetwork.FrontendIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr(privateIP),
},
},
},
},
},
}, nil)
publicIPAddresses.EXPECT().
Get(gomock.Any(), "clusterResourceGroup", "infra-pip-v4", "").
Return(mgmtnetwork.PublicIPAddress{
PublicIPAddressPropertiesFormat: &mgmtnetwork.PublicIPAddressPropertiesFormat{
IPAddress: to.StringPtr("1.2.3.4"),
Get(gomock.Any(), "clusterResourceGroup", "infra-pip-v4", nil).
Return(armnetwork.PublicIPAddressesClientGetResponse{
PublicIPAddress: armnetwork.PublicIPAddress{
Properties: &armnetwork.PublicIPAddressPropertiesFormat{
IPAddress: to.StringPtr(publicIP),
},
},
}, nil)
dns.EXPECT().
Update(gomock.Any(), gomock.Any(), gomock.Any()).
Update(gomock.Any(), gomock.Any(), publicIP).
Return(nil)
},
},
@ -617,26 +628,28 @@ func TestUpdateAPIIPEarly(t *testing.T) {
fixture.AddOpenShiftClusterDocuments(doc)
doc.Dequeues = 1
doc.OpenShiftCluster.Properties.APIServerProfile.IP = "10.0.0.1"
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = "10.0.0.1"
doc.OpenShiftCluster.Properties.APIServerProfile.IP = privateIP
doc.OpenShiftCluster.Properties.APIServerProfile.IntIP = privateIP
checker.AddOpenShiftClusterDocuments(doc)
},
mocks: func(loadBalancers *mock_network.MockLoadBalancersClient, publicIPAddresses *mock_network.MockPublicIPAddressesClient, dns *mock_dns.MockManager) {
mocks: func(loadBalancers *mock_armnetwork.MockLoadBalancersClient, publicIPAddresses *mock_armnetwork.MockPublicIPAddressesClient, dns *mock_dns.MockManager) {
loadBalancers.EXPECT().
Get(gomock.Any(), "clusterResourceGroup", "infra-internal", "").
Return(mgmtnetwork.LoadBalancer{
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr("10.0.0.1"),
Get(gomock.Any(), "clusterResourceGroup", "infra-internal", nil).
Return(armnetwork.LoadBalancersClientGetResponse{
LoadBalancer: armnetwork.LoadBalancer{
Properties: &armnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{
{
Properties: &armnetwork.FrontendIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr(privateIP),
},
},
},
},
},
}, nil)
dns.EXPECT().
Update(gomock.Any(), gomock.Any(), gomock.Any()).
Update(gomock.Any(), gomock.Any(), privateIP).
Return(nil)
},
},
@ -645,8 +658,8 @@ func TestUpdateAPIIPEarly(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
loadBalancers := mock_network.NewMockLoadBalancersClient(controller)
publicIPAddresses := mock_network.NewMockPublicIPAddressesClient(controller)
loadBalancers := mock_armnetwork.NewMockLoadBalancersClient(controller)
publicIPAddresses := mock_armnetwork.NewMockPublicIPAddressesClient(controller)
dns := mock_dns.NewMockManager(controller)
if tt.mocks != nil {
tt.mocks(loadBalancers, publicIPAddresses, dns)
@ -671,11 +684,11 @@ func TestUpdateAPIIPEarly(t *testing.T) {
}
m := &manager{
doc: doc,
db: dbOpenShiftClusters,
publicIPAddresses: publicIPAddresses,
loadBalancers: loadBalancers,
dns: dns,
doc: doc,
db: dbOpenShiftClusters,
armPublicIPAddresses: publicIPAddresses,
armLoadBalancers: loadBalancers,
dns: dns,
}
err = m.updateAPIIPEarly(ctx)
@ -706,7 +719,7 @@ func TestEnsureGatewayCreate(t *testing.T) {
},
{
name: "noop: IP set",
gatewayPrivateEndpointIP: "1.2.3.4",
gatewayPrivateEndpointIP: privateIP,
},
{
name: "error: private endpoint connection not found",
@ -720,7 +733,7 @@ func TestEnsureGatewayCreate(t *testing.T) {
IPConfigurations: &[]mgmtnetwork.InterfaceIPConfiguration{
{
InterfaceIPConfigurationPropertiesFormat: &mgmtnetwork.InterfaceIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr("1.2.3.4"),
PrivateIPAddress: to.StringPtr(privateIP),
},
},
},
@ -751,7 +764,7 @@ func TestEnsureGatewayCreate(t *testing.T) {
IPConfigurations: &[]mgmtnetwork.InterfaceIPConfiguration{
{
InterfaceIPConfigurationPropertiesFormat: &mgmtnetwork.InterfaceIPConfigurationPropertiesFormat{
PrivateIPAddress: to.StringPtr("1.2.3.4"),
PrivateIPAddress: to.StringPtr(privateIP),
},
},
},
@ -815,7 +828,7 @@ func TestEnsureGatewayCreate(t *testing.T) {
ID: resourceID,
Properties: api.OpenShiftClusterProperties{
NetworkProfile: api.NetworkProfile{
GatewayPrivateEndpointIP: "1.2.3.4",
GatewayPrivateEndpointIP: privateIP,
GatewayPrivateLinkID: "1234",
},
},

Просмотреть файл

@ -19,6 +19,16 @@ import (
const outboundRuleV4 = "outbound-rule-v4"
type deleteIPResult struct {
name string
err error
}
type createIPResult struct {
ip mgmtnetwork.PublicIPAddress
err error
}
func (m *manager) reconcileLoadBalancerProfile(ctx context.Context) error {
if m.doc.OpenShiftCluster.Properties.NetworkProfile.OutboundType != api.OutboundTypeLoadbalancer || m.doc.OpenShiftCluster.Properties.ArchitectureVersion == api.ArchitectureVersionV1 {
return nil
@ -68,7 +78,7 @@ func (m *manager) reconcileOutboundRuleV4IPsInner(ctx context.Context, lb mgmtne
}
}
desiredOutboundIPs, err := m.getDesiredOutboundIPs(ctx)
desiredOutboundIPs, err := m.reconcileOutboundIPs(ctx)
if err != nil {
return err
}
@ -95,9 +105,29 @@ func (m *manager) reconcileOutboundRuleV4IPsInner(ctx context.Context, lb mgmtne
return nil
}
// Remove all frontend ip config in use by outbound-rule-v4. Frontend IP config that is used by load balancer rules will be saved.
// Remove outbound-rule-v4 IPs and corresponding frontendIPConfig from load balancer
func removeOutboundIPsFromLB(lb mgmtnetwork.LoadBalancer) {
// get all outbound rule fip config to remove
removeOutboundRuleV4FrontendIPConfig(lb)
setOutboundRuleV4(lb, []mgmtnetwork.SubResource{})
}
func removeOutboundRuleV4FrontendIPConfig(lb mgmtnetwork.LoadBalancer) {
var savedFIPConfig = make([]mgmtnetwork.FrontendIPConfiguration, 0, len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations))
var outboundRuleFrontendConfig = getOutboundRuleV4FIPConfigs(lb)
for i := 0; i < len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations); i++ {
fipConfigID := *(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].ID
fipConfig := (*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i]
hasLBRules := (*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].LoadBalancingRules != nil
if _, ok := outboundRuleFrontendConfig[fipConfigID]; ok && !hasLBRules {
continue
}
savedFIPConfig = append(savedFIPConfig, fipConfig)
}
lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations = &savedFIPConfig
}
func getOutboundRuleV4FIPConfigs(lb mgmtnetwork.LoadBalancer) map[string]mgmtnetwork.SubResource {
var obRuleV4FIPConfigs = make(map[string]mgmtnetwork.SubResource)
for _, obRule := range *lb.LoadBalancerPropertiesFormat.OutboundRules {
if *obRule.Name == outboundRuleV4 {
@ -106,36 +136,22 @@ func removeOutboundIPsFromLB(lb mgmtnetwork.LoadBalancer) {
fipConfig := (*obRule.OutboundRulePropertiesFormat.FrontendIPConfigurations)[i]
obRuleV4FIPConfigs[fipConfigID] = fipConfig
}
// clear outbound-rule-v4 frontend ip config
*obRule.FrontendIPConfigurations = []mgmtnetwork.SubResource{}
break
}
}
// rebuild frontend ip config without outbound-rule-v4 frontend ip config, preserving
// the public api server frontend ip config if the api server is public
var savedFIPConfig = make([]mgmtnetwork.FrontendIPConfiguration, 0, len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations))
for i := 0; i < len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations); i++ {
fipConfigID := *(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].ID
fipConfig := (*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i]
fipLBRules := (*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].LoadBalancingRules
if _, ok := obRuleV4FIPConfigs[fipConfigID]; ok && fipLBRules == nil {
continue
}
savedFIPConfig = append(savedFIPConfig, fipConfig)
}
lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations = &savedFIPConfig
return obRuleV4FIPConfigs
}
// return a map of Frontend IP Configs where the key is the ID of the Frontend IP Config
// Returns a map of Frontend IP Configurations. Frontend IP Configurations can be looked up by Public IP Address ID or Frontend IP Configuration ID
func getFrontendIPConfigs(lb mgmtnetwork.LoadBalancer) map[string]mgmtnetwork.FrontendIPConfiguration {
// map out frontendConfig to ID of public IP addresses for quick lookup
var frontendIPConfigs = make(map[string]mgmtnetwork.FrontendIPConfiguration, len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations))
for i := 0; i < len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations); i++ {
fipConfigIPID := *(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].FrontendIPConfigurationPropertiesFormat.PublicIPAddress.ID
fipConfigID := *(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].ID
fipConfigIPAddressID := *(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].FrontendIPConfigurationPropertiesFormat.PublicIPAddress.ID
fipConfig := (*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i]
frontendIPConfigs[fipConfigIPID] = fipConfig
frontendIPConfigs[fipConfigID] = fipConfig
frontendIPConfigs[fipConfigIPAddressID] = fipConfig
}
return frontendIPConfigs
@ -147,21 +163,24 @@ func addOutboundIPsToLB(resourceGroupID string, lb mgmtnetwork.LoadBalancer, obI
outboundRuleV4FrontendIPConfig := []mgmtnetwork.SubResource{}
// add IP Addresses to frontendConfig
for _, obIPOrPrefix := range obIPsOrIPPrefixes {
for _, obIPOrIPPrefix := range obIPsOrIPPrefixes {
// check if the frontend config exists in the map to avoid duplicate entries
if _, ok := frontendIPConfigs[obIPOrPrefix.ID]; !ok {
frontendIPConfigName := stringutils.LastTokenByte(obIPOrPrefix.ID, '/')
if _, ok := frontendIPConfigs[obIPOrIPPrefix.ID]; !ok {
frontendIPConfigName := stringutils.LastTokenByte(obIPOrIPPrefix.ID, '/')
frontendConfigID := fmt.Sprintf("%s/providers/Microsoft.Network/loadBalancers/%s/frontendIPConfigurations/%s", resourceGroupID, *lb.Name, frontendIPConfigName)
*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations = append(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations, newFrontendIPConfig(frontendIPConfigName, frontendConfigID, obIPOrPrefix.ID))
*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations = append(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations, newFrontendIPConfig(frontendIPConfigName, frontendConfigID, obIPOrIPPrefix.ID))
outboundRuleV4FrontendIPConfig = append(outboundRuleV4FrontendIPConfig, newOutboundRuleFrontendIPConfig(frontendConfigID))
} else {
// frontendIPConfig already exists and just needs to be added to the outbound rule
frontendConfig := frontendIPConfigs[obIPOrPrefix.ID]
frontendConfig := frontendIPConfigs[obIPOrIPPrefix.ID]
outboundRuleV4FrontendIPConfig = append(outboundRuleV4FrontendIPConfig, newOutboundRuleFrontendIPConfig(*frontendConfig.ID))
}
}
// update outbound-rule-v4
setOutboundRuleV4(lb, outboundRuleV4FrontendIPConfig)
}
func setOutboundRuleV4(lb mgmtnetwork.LoadBalancer, outboundRuleV4FrontendIPConfig []mgmtnetwork.SubResource) {
for _, outboundRule := range *lb.LoadBalancerPropertiesFormat.OutboundRules {
if *outboundRule.Name == outboundRuleV4 {
outboundRule.OutboundRulePropertiesFormat.FrontendIPConfigurations = &outboundRuleV4FrontendIPConfig
@ -174,38 +193,28 @@ func addOutboundIPsToLB(resourceGroupID string, lb mgmtnetwork.LoadBalancer, obI
// The default outbound ip is saved if the api server is public.
func (m *manager) deleteUnusedManagedIPs(ctx context.Context) error {
resourceGroupName := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
infraID := m.doc.OpenShiftCluster.Properties.InfraID
managedIPs, err := m.getClusterManagedIPs(ctx)
unusedManagedIPs, err := m.getUnusedManagedIPs(ctx)
if err != nil {
return err
}
lb, err := m.loadBalancers.Get(ctx, resourceGroupName, infraID, "")
if err != nil {
return err
}
outboundIPs := getOutboundIPsFromLB(lb)
outboundIPMap := make(map[string]api.ResourceReference, len(outboundIPs))
for i := 0; i < len(outboundIPs); i++ {
outboundIPMap[strings.ToLower(outboundIPs[i].ID)] = outboundIPs[i]
}
ch := make(chan deleteIPResult)
defer close(ch)
var cleanupErrors []string
for _, ip := range managedIPs {
// don't delete api server ip
if *ip.Name == infraID+"-pip-v4" && m.doc.OpenShiftCluster.Properties.APIServerProfile.Visibility == api.VisibilityPublic {
continue
}
if _, ok := outboundIPMap[strings.ToLower(*ip.ID)]; !ok && strings.Contains(strings.ToLower(*ip.ID), strings.ToLower(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID)) {
ipName := stringutils.LastTokenByte(*ip.ID, '/')
m.log.Infof("deleting managed public IP Address: %s", ipName)
err := m.publicIPAddresses.DeleteAndWait(ctx, resourceGroupName, ipName)
if err != nil {
cleanupErrors = append(cleanupErrors, fmt.Sprintf("deletion of unused managed ip %s failed with error: %v", ipName, err))
}
for _, id := range unusedManagedIPs {
ipName := stringutils.LastTokenByte(id, '/')
go m.deleteIPAddress(ctx, resourceGroupName, ipName, ch)
}
for range unusedManagedIPs {
result := <-ch
if result.err != nil {
cleanupErrors = append(cleanupErrors, fmt.Sprintf("deletion of unused managed ip %s failed with error: %v", result.name, result.err))
}
}
if cleanupErrors != nil {
return fmt.Errorf("failed to cleanup unused managed ips\n%s", strings.Join(cleanupErrors, "\n"))
}
@ -213,9 +222,50 @@ func (m *manager) deleteUnusedManagedIPs(ctx context.Context) error {
return nil
}
func (m *manager) deleteIPAddress(ctx context.Context, resourceGroupName string, ipName string, ch chan<- deleteIPResult) {
m.log.Infof("deleting managed public IP Address: %s", ipName)
err := m.publicIPAddresses.DeleteAndWait(ctx, resourceGroupName, ipName)
ch <- deleteIPResult{
name: ipName,
err: err,
}
}
func (m *manager) getUnusedManagedIPs(ctx context.Context) ([]string, error) {
resourceGroupName := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
infraID := m.doc.OpenShiftCluster.Properties.InfraID
managedIPs, err := m.getClusterManagedIPs(ctx)
if err != nil {
return nil, err
}
lb, err := m.loadBalancers.Get(ctx, resourceGroupName, infraID, "")
if err != nil {
return nil, err
}
outboundIPs := getOutboundIPsFromLB(lb)
outboundIPMap := make(map[string]api.ResourceReference, len(outboundIPs))
for i := 0; i < len(outboundIPs); i++ {
outboundIPMap[strings.ToLower(outboundIPs[i].ID)] = outboundIPs[i]
}
var unusedManagedIPs []string
for _, ip := range managedIPs {
// don't delete api server ip
if *ip.Name == infraID+"-pip-v4" && m.doc.OpenShiftCluster.Properties.APIServerProfile.Visibility == api.VisibilityPublic {
continue
}
if _, ok := outboundIPMap[strings.ToLower(*ip.ID)]; !ok && strings.Contains(strings.ToLower(*ip.ID), strings.ToLower(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID)) {
unusedManagedIPs = append(unusedManagedIPs, *ip.ID)
}
}
return unusedManagedIPs, nil
}
// Returns the desired RP managed outbound publicIPAddresses. Additional Managed Outbound IPs
// will be created as required to satisfy ManagedOutboundIP.Count.
func (m *manager) getDesiredOutboundIPs(ctx context.Context) ([]api.ResourceReference, error) {
func (m *manager) reconcileOutboundIPs(ctx context.Context) ([]api.ResourceReference, error) {
// Determine source of outbound IPs
// TODO: add customer provided ip and ip prefixes
if m.doc.OpenShiftCluster.Properties.NetworkProfile.LoadBalancerProfile.ManagedOutboundIPs != nil {
@ -230,23 +280,27 @@ func (m *manager) getDesiredOutboundIPs(ctx context.Context) ([]api.ResourceRefe
func (m *manager) reconcileDesiredManagedIPs(ctx context.Context) ([]api.ResourceReference, error) {
infraID := m.doc.OpenShiftCluster.Properties.InfraID
managedOBIPCount := m.doc.OpenShiftCluster.Properties.NetworkProfile.LoadBalancerProfile.ManagedOutboundIPs.Count
desiredIPAddresses := make([]api.ResourceReference, 0, managedOBIPCount)
ipAddresses, err := m.getClusterManagedIPs(ctx)
if err != nil {
return nil, err
}
// create additional IPs if needed
numToCreate := managedOBIPCount - len(ipAddresses)
for i := 0; i < numToCreate; i++ {
ipAddress, err := m.createPublicIPAddress(ctx)
if numToCreate > 0 {
err = m.createPublicIPAddresses(ctx, ipAddresses, numToCreate)
if err != nil {
return nil, err
}
ipAddresses[*ipAddress.Name] = ipAddress
}
desiredIPAddresses := getDesiredOutboundIPs(managedOBIPCount, ipAddresses, infraID)
return desiredIPAddresses, nil
}
func getDesiredOutboundIPs(managedOBIPCount int, ipAddresses map[string]mgmtnetwork.PublicIPAddress, infraID string) []api.ResourceReference {
desiredIPAddresses := make([]api.ResourceReference, 0, managedOBIPCount)
// ensure that when scaling managed ips down the default outbound IP is reused incase the api server visibility is public
desiredCount := 0
if defaultIP, ok := ipAddresses[infraID+"-pip-v4"]; ok {
@ -263,8 +317,31 @@ func (m *manager) reconcileDesiredManagedIPs(ctx context.Context) ([]api.Resourc
break
}
}
return desiredIPAddresses
}
return desiredIPAddresses, nil
func (m *manager) createPublicIPAddresses(ctx context.Context, ipAddresses map[string]mgmtnetwork.PublicIPAddress, numToCreate int) error {
ch := make(chan createIPResult)
defer close(ch)
var errResults []string
// create additional IPs if needed
for i := 0; i < numToCreate; i++ {
go m.createPublicIPAddress(ctx, ch)
}
for i := 0; i < numToCreate; i++ {
result := <-ch
if result.err != nil {
errResults = append(errResults, fmt.Sprintf("creation of ip address %s failed with error: %s", *result.ip.Name, result.err.Error()))
} else {
ipAddresses[*result.ip.Name] = result.ip
}
}
if len(errResults) > 0 {
return fmt.Errorf("failed to create required IPs\n%s", strings.Join(errResults, "\n"))
}
return nil
}
// Get all current managed IP Addresses in cluster resource group based on naming convention.
@ -279,7 +356,7 @@ func (m *manager) getClusterManagedIPs(ctx context.Context) (map[string]mgmtnetw
}
for i := 0; i < len(result); i++ {
// <infraID>-pip-v4 is not necessarily managed but is the default installed outbound IP
// <infraID>-pip-v4 is the default installed outbound IP
if *result[i].Name == infraID+"-pip-v4" || strings.Contains(*result[i].Name, "-outbound-pip-v4") {
ipAddresses[*result[i].Name] = result[i]
}
@ -293,41 +370,23 @@ func genManagedOutboundIPName() string {
}
// Create a managed outbound IP Address.
func (m *manager) createPublicIPAddress(ctx context.Context) (mgmtnetwork.PublicIPAddress, error) {
func (m *manager) createPublicIPAddress(ctx context.Context, ch chan<- createIPResult) {
name := genManagedOutboundIPName()
resourceGroupName := stringutils.LastTokenByte(m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, '/')
resourceID := fmt.Sprintf("%s/providers/Microsoft.Network/publicIPAddresses/%s", m.doc.OpenShiftCluster.Properties.ClusterProfile.ResourceGroupID, name)
m.log.Infof("creating public IP Address: %s", name)
publicIPAddress := mgmtnetwork.PublicIPAddress{
Name: &name,
ID: &resourceID,
Location: &m.doc.OpenShiftCluster.Location,
PublicIPAddressPropertiesFormat: &mgmtnetwork.PublicIPAddressPropertiesFormat{
PublicIPAllocationMethod: mgmtnetwork.Static,
PublicIPAddressVersion: mgmtnetwork.IPv4,
},
Sku: &mgmtnetwork.PublicIPAddressSku{
Name: mgmtnetwork.PublicIPAddressSkuNameStandard,
},
}
publicIPAddress := newPublicIPAddress(name, resourceID, m.doc.OpenShiftCluster.Location)
err := m.publicIPAddresses.CreateOrUpdateAndWait(ctx, resourceGroupName, name, publicIPAddress)
if err != nil {
return mgmtnetwork.PublicIPAddress{}, err
ch <- createIPResult{
ip: publicIPAddress,
err: err,
}
return publicIPAddress, nil
}
func getOutboundIPsFromLB(lb mgmtnetwork.LoadBalancer) []api.ResourceReference {
var outboundIPs []api.ResourceReference
fipConfigs := make(map[string]mgmtnetwork.FrontendIPConfiguration, len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations))
for i := 0; i < len(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations); i++ {
fipConfigID := *(*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i].ID
fipConfig := (*lb.LoadBalancerPropertiesFormat.FrontendIPConfigurations)[i]
fipConfigs[fipConfigID] = fipConfig
}
fipConfigs := getFrontendIPConfigs(lb)
for _, obRule := range *lb.LoadBalancerPropertiesFormat.OutboundRules {
if *obRule.Name == outboundRuleV4 {
@ -360,6 +419,21 @@ func (m *manager) patchEffectiveOutboundIPs(ctx context.Context, outboundIPs []a
return nil
}
func newPublicIPAddress(name, resourceID, location string) mgmtnetwork.PublicIPAddress {
return mgmtnetwork.PublicIPAddress{
Name: &name,
ID: &resourceID,
Location: &location,
PublicIPAddressPropertiesFormat: &mgmtnetwork.PublicIPAddressPropertiesFormat{
PublicIPAllocationMethod: mgmtnetwork.Static,
PublicIPAddressVersion: mgmtnetwork.IPv4,
},
Sku: &mgmtnetwork.PublicIPAddressSku{
Name: mgmtnetwork.PublicIPAddressSkuNameStandard,
},
}
}
func newFrontendIPConfig(name string, id string, publicIPorIPPrefixID string) mgmtnetwork.FrontendIPConfiguration {
// TODO: add check for publicIPorIPPrefixID
return mgmtnetwork.FrontendIPConfiguration{

Просмотреть файл

@ -23,7 +23,7 @@ import (
testdatabase "github.com/Azure/ARO-RP/test/database"
)
func TestGetDesiredOutboundIPs(t *testing.T) {
func TestReconcileOutboundIPs(t *testing.T) {
ctx := context.Background()
infraID := "infraID"
clusterRGID := "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG"
@ -121,8 +121,8 @@ func TestGetDesiredOutboundIPs(t *testing.T) {
}
tt.m.publicIPAddresses = publicIPAddressClient
// Run getDesiredOutboundIPs and assert the correct results
outboundIPs, err := tt.m.getDesiredOutboundIPs(ctx)
// Run reconcileOutboundIPs and assert the correct results
outboundIPs, err := tt.m.reconcileOutboundIPs(ctx)
assert.Equal(t, tt.expectedErr, err, "Unexpected error exception")
// results are not deterministic when scaling down so just check desired length
assert.Len(t, outboundIPs, tt.m.doc.OpenShiftCluster.Properties.NetworkProfile.LoadBalancerProfile.ManagedOutboundIPs.Count)
@ -303,8 +303,60 @@ func TestAddOutboundIPsToLB(t *testing.T) {
ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/infraID-pip-v4",
},
},
currentLB: getClearedLB(),
expectedLB: fakeUpdatedLoadBalancer(0),
currentLB: getClearedLB(),
expectedLB: mgmtnetwork.LoadBalancer{
Name: to.StringPtr("infraID"),
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
Name: to.StringPtr("ae3506385907e44eba9ef9bf76eac973"),
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/ae3506385907e44eba9ef9bf76eac973"),
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
LoadBalancingRules: &[]mgmtnetwork.SubResource{
{
ID: to.StringPtr("ae3506385907e44eba9ef9bf76eac973-TCP-80"),
},
{
ID: to.StringPtr("ae3506385907e44eba9ef9bf76eac973-TCP-443"),
},
},
PublicIPAddress: &mgmtnetwork.PublicIPAddress{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/infraID-default-v4"),
},
},
},
{
Name: to.StringPtr("public-lb-ip-v4"),
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/public-lb-ip-v4"),
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
LoadBalancingRules: &[]mgmtnetwork.SubResource{
{
ID: to.StringPtr("api-internal-v4"),
},
},
OutboundRules: &[]mgmtnetwork.SubResource{{
ID: to.StringPtr(outboundRuleV4),
}},
PublicIPAddress: &mgmtnetwork.PublicIPAddress{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/infraID-pip-v4"),
},
},
},
},
OutboundRules: &[]mgmtnetwork.OutboundRule{
{
Name: to.StringPtr(outboundRuleV4),
OutboundRulePropertiesFormat: &mgmtnetwork.OutboundRulePropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.SubResource{
{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/public-lb-ip-v4"),
},
},
},
},
},
},
},
},
{
name: "add multiple outbound IPs to LB",
@ -316,8 +368,72 @@ func TestAddOutboundIPsToLB(t *testing.T) {
ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/uuid1-outbound-pip-v4",
},
},
currentLB: getClearedLB(),
expectedLB: fakeUpdatedLoadBalancer(1),
currentLB: getClearedLB(),
expectedLB: mgmtnetwork.LoadBalancer{
Name: to.StringPtr("infraID"),
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
Name: to.StringPtr("ae3506385907e44eba9ef9bf76eac973"),
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/ae3506385907e44eba9ef9bf76eac973"),
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
LoadBalancingRules: &[]mgmtnetwork.SubResource{
{
ID: to.StringPtr("ae3506385907e44eba9ef9bf76eac973-TCP-80"),
},
{
ID: to.StringPtr("ae3506385907e44eba9ef9bf76eac973-TCP-443"),
},
},
PublicIPAddress: &mgmtnetwork.PublicIPAddress{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/infraID-default-v4"),
},
},
},
{
Name: to.StringPtr("public-lb-ip-v4"),
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/public-lb-ip-v4"),
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
LoadBalancingRules: &[]mgmtnetwork.SubResource{
{
ID: to.StringPtr("api-internal-v4"),
},
},
OutboundRules: &[]mgmtnetwork.SubResource{{
ID: to.StringPtr(outboundRuleV4),
}},
PublicIPAddress: &mgmtnetwork.PublicIPAddress{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/infraID-pip-v4"),
},
},
},
{
Name: to.StringPtr("uuid1-outbound-pip-v4"),
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/uuid1-outbound-pip-v4"),
FrontendIPConfigurationPropertiesFormat: &mgmtnetwork.FrontendIPConfigurationPropertiesFormat{
PublicIPAddress: &mgmtnetwork.PublicIPAddress{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/publicIPAddresses/uuid1-outbound-pip-v4"),
},
},
},
},
OutboundRules: &[]mgmtnetwork.OutboundRule{
{
Name: to.StringPtr(outboundRuleV4),
OutboundRulePropertiesFormat: &mgmtnetwork.OutboundRulePropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.SubResource{
{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/public-lb-ip-v4"),
},
{
ID: to.StringPtr("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clusterRG/providers/Microsoft.Network/loadBalancers/infraID/frontendIPConfigurations/uuid1-outbound-pip-v4"),
},
},
},
},
},
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
@ -339,7 +455,7 @@ func TestRemoveOutboundIPsFromLB(t *testing.T) {
name: "remove all outbound-rule-v4 fip config except api server",
currentLB: fakeLoadBalancersGet(1, api.VisibilityPublic),
expectedLB: mgmtnetwork.LoadBalancer{
Name: &infraID,
Name: to.StringPtr("infraID"),
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
@ -392,7 +508,7 @@ func TestRemoveOutboundIPsFromLB(t *testing.T) {
name: "remove all outbound-rule-v4 fip config",
currentLB: fakeLoadBalancersGet(1, api.VisibilityPrivate),
expectedLB: mgmtnetwork.LoadBalancer{
Name: &infraID,
Name: to.StringPtr("infraID"),
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{
@ -955,8 +1071,6 @@ func TestReconcileLoadBalancerProfile(t *testing.T) {
loadBalancersClient.EXPECT().
Get(gomock.Any(), clusterRGName, infraID, "").
Return(fakeLoadBalancersGet(0, api.VisibilityPublic), nil)
// loadBalancersClient.EXPECT().
// CreateOrUpdateAndWait(ctx, clusterRGName, infraID, fakeUpdatedLoadBalancer(0)).Return(nil)
publicIPAddressClient.EXPECT().
List(gomock.Any(), clusterRGName).
Return(getFakePublicIPList(1), nil)
@ -975,7 +1089,7 @@ func TestReconcileLoadBalancerProfile(t *testing.T) {
},
},
},
expectedErr: []error{fmt.Errorf("multiple errors occurred while updating outbound-rule-v4\nfailed to create ip\nfailed to cleanup unused managed ips\ndeletion of unused managed ip uuid1-outbound-pip-v4 failed with error: error")},
expectedErr: []error{fmt.Errorf("multiple errors occurred while updating outbound-rule-v4\nfailed to create required IPs\ncreation of ip address uuid2-outbound-pip-v4 failed with error: failed to create ip\nfailed to cleanup unused managed ips\ndeletion of unused managed ip uuid1-outbound-pip-v4 failed with error: error")},
},
} {
t.Run(tt.name, func(t *testing.T) {
@ -1070,7 +1184,7 @@ func fakeLoadBalancersGet(additionalIPCount int, apiServerVisibility api.Visibil
}
}
lb := mgmtnetwork.LoadBalancer{
Name: &infraID,
Name: to.StringPtr("infraID"),
LoadBalancerPropertiesFormat: &mgmtnetwork.LoadBalancerPropertiesFormat{
FrontendIPConfigurations: &[]mgmtnetwork.FrontendIPConfiguration{
{

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -346,8 +346,7 @@ func (g *generator) gatewayVMSS() *arm.Resource {
},
DiagnosticsProfile: &mgmtcompute.DiagnosticsProfile{
BootDiagnostics: &mgmtcompute.BootDiagnostics{
Enabled: to.BoolPtr(true),
StorageURI: to.StringPtr("[concat('https://', parameters('gatewayStorageAccountDomain'), '/')]"),
Enabled: to.BoolPtr(true),
},
},
},

Просмотреть файл

@ -634,8 +634,7 @@ func (g *generator) rpVMSS() *arm.Resource {
},
DiagnosticsProfile: &mgmtcompute.DiagnosticsProfile{
BootDiagnostics: &mgmtcompute.BootDiagnostics{
Enabled: to.BoolPtr(true),
StorageURI: to.StringPtr("[concat('https://', parameters('storageAccountDomain'), '/')]"),
Enabled: to.BoolPtr(true),
},
},
},

Просмотреть файл

@ -150,7 +150,7 @@ touch /etc/containers/nodocker
mkdir -p /root/.docker
REGISTRY_AUTH_FILE=/root/.docker/config.json az acr login --name "$(sed -e 's|.*/||' <<<"$ACRRESOURCEID")"
MDMIMAGE="${RPIMAGE%%/*}/${MDMIMAGE##*/}"
MDMIMAGE="${RPIMAGE%%/*}/${MDMIMAGE#*/}"
docker pull "$MDMIMAGE"
docker pull "$RPIMAGE"
docker pull "$FLUENTBITIMAGE"

Просмотреть файл

@ -129,7 +129,7 @@ touch /etc/containers/nodocker
mkdir -p /root/.docker
REGISTRY_AUTH_FILE=/root/.docker/config.json az acr login --name "$(sed -e 's|.*/||' <<<"$ACRRESOURCEID")"
MDMIMAGE="${RPIMAGE%%/*}/${MDMIMAGE##*/}"
MDMIMAGE="${RPIMAGE%%/*}/${MDMIMAGE#*/}"
docker pull "$MDMIMAGE"
docker pull "$RPIMAGE"
docker pull "$FLUENTBITIMAGE"

Просмотреть файл

@ -90,10 +90,10 @@ func Test_getAdminHiveClusterDeployment(t *testing.T) {
clusterManager := mock_hive.NewMockClusterManager(controller)
clusterManager.EXPECT().GetClusterDeployment(gomock.Any(), gomock.Any()).Return(&clusterDeployment, nil).Times(tt.expectedGetClusterDeploymentCallCount)
f, err = NewFrontend(ctx, ti.audit, ti.log, _env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase,
ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, clusterManager, nil, nil, nil)
ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, clusterManager, nil, nil, nil)
} else {
f, err = NewFrontend(ctx, ti.audit, ti.log, _env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase,
ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
}
if err != nil {

Просмотреть файл

@ -91,7 +91,7 @@ func TestAdminApproveCSR(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
return k, nil
}, nil, nil)

Просмотреть файл

@ -152,7 +152,7 @@ func TestAdminCordonUncordonNode(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
return k, nil
}, nil, nil)

Просмотреть файл

@ -113,7 +113,7 @@ func TestAdminDeleteManagedResource(t *testing.T) {
a := mock_adminactions.NewMockAzureActions(ti.controller)
tt.mocks(tt, a)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -84,7 +84,7 @@ func TestAdminDrainNode(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
return k, nil
}, nil, nil)

Просмотреть файл

@ -536,6 +536,7 @@ func TestAdminEtcdCertificateRenew(t *testing.T) {
ti.openShiftClustersDatabase,
ti.subscriptionsDatabase,
nil,
nil,
api.APIs,
&noop.Noop{},
&noop.Noop{},
@ -753,6 +754,7 @@ func TestAdminEtcdCertificateRecovery(t *testing.T) {
ti.openShiftClustersDatabase,
ti.subscriptionsDatabase,
nil,
nil,
api.APIs,
&noop.Noop{},
&noop.Noop{},

Просмотреть файл

@ -167,6 +167,7 @@ func TestAdminEtcdRecovery(t *testing.T) {
ti.openShiftClustersDatabase,
ti.subscriptionsDatabase,
nil,
nil,
api.APIs,
&noop.Noop{},
&noop.Noop{},

Просмотреть файл

@ -262,7 +262,7 @@ func TestAdminKubernetesObjectsGetAndDelete(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
return k, nil
}, nil, nil)
if err != nil {
@ -411,7 +411,7 @@ func TestAdminPostKubernetesObjects(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
return k, nil
}, nil, nil)
if err != nil {

Просмотреть файл

@ -125,7 +125,7 @@ func TestAdminKubernetesGetPodLogs(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster) (adminactions.KubeActions, error) {
return k, nil
}, nil, nil)
if err != nil {

Просмотреть файл

@ -124,7 +124,7 @@ func TestAdminListOpenShiftCluster(t *testing.T) {
ti.openShiftClustersClient.SetError(tt.throwsError)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, aead, nil, nil, nil, ti.enricher)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, aead, nil, nil, nil, ti.enricher)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -84,7 +84,7 @@ func TestAdminRedeployVM(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -93,7 +93,7 @@ func TestAdminListResourcesList(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)
mockResponder := mock_frontend.NewMockStreamResponder(ti.controller)

Просмотреть файл

@ -84,7 +84,7 @@ func TestAdminStartVM(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -86,7 +86,7 @@ func TestAdminStopVM(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -202,7 +202,7 @@ func TestAdminVMResize(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil,
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil,
func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -136,7 +136,7 @@ func TestAdminListVMSizeList(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -110,7 +110,7 @@ func TestOpenShiftVersionList(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, ti.openShiftVersionsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, ti.openShiftVersionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)

Просмотреть файл

@ -266,7 +266,7 @@ func TestOpenShiftVersionPut(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, ti.openShiftVersionsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, ti.openShiftVersionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -0,0 +1,47 @@
package frontend
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"encoding/json"
"net/http"
"path/filepath"
"sort"
"github.com/sirupsen/logrus"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/admin"
"github.com/Azure/ARO-RP/pkg/frontend/middleware"
"github.com/Azure/ARO-RP/pkg/util/version"
)
func (f *frontend) getAdminPlatformWorkloadIdentityRoleSets(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
r.URL.Path = filepath.Dir(r.URL.Path)
converter := f.apis[admin.APIVersion].PlatformWorkloadIdentityRoleSetConverter
docs, err := f.dbPlatformWorkloadIdentityRoleSets.ListAll(ctx)
if err != nil {
log.Error(err)
api.WriteError(w, http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "Internal server error.")
return
}
var roleSets []*api.PlatformWorkloadIdentityRoleSet
if docs != nil {
for _, doc := range docs.PlatformWorkloadIdentityRoleSetDocuments {
roleSets = append(roleSets, doc.PlatformWorkloadIdentityRoleSet)
}
}
sort.Slice(roleSets, func(i, j int) bool {
return version.CreateSemverFromMinorVersionString(roleSets[i].Properties.OpenShiftVersion).LessThan(*version.CreateSemverFromMinorVersionString(roleSets[j].Properties.OpenShiftVersion))
})
b, err := json.MarshalIndent(converter.ToExternalList(roleSets), "", " ")
adminReply(log, w, nil, b, err)
}

Просмотреть файл

@ -0,0 +1,281 @@
package frontend
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"errors"
"net/http"
"sort"
"testing"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/admin"
"github.com/Azure/ARO-RP/pkg/database/cosmosdb"
"github.com/Azure/ARO-RP/pkg/metrics/noop"
"github.com/Azure/ARO-RP/pkg/util/version"
testdatabase "github.com/Azure/ARO-RP/test/database"
)
func TestPlatformWorkloadIdentityRoleSetList(t *testing.T) {
ctx := context.Background()
type test struct {
name string
fixture func(f *testdatabase.Fixture)
cosmosdb func(c *cosmosdb.FakePlatformWorkloadIdentityRoleSetDocumentClient)
wantStatusCode int
wantResponse *admin.PlatformWorkloadIdentityRoleSetList
wantError string
}
for _, tt := range []*test{
{
name: "GET request returns empty result with StatusOK",
fixture: func(f *testdatabase.Fixture) {},
wantStatusCode: http.StatusOK,
wantResponse: &admin.PlatformWorkloadIdentityRoleSetList{
PlatformWorkloadIdentityRoleSets: []*admin.PlatformWorkloadIdentityRoleSet{},
},
},
{
name: "GET request returns non-empty result with StatusOK",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
)
},
wantStatusCode: http.StatusOK,
wantResponse: &admin.PlatformWorkloadIdentityRoleSetList{
PlatformWorkloadIdentityRoleSets: []*admin.PlatformWorkloadIdentityRoleSet{
{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
},
{
name: "GET request with StatusOK returns results in correct order even if Cosmos DB returns them in a different order",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
)
},
cosmosdb: func(c *cosmosdb.FakePlatformWorkloadIdentityRoleSetDocumentClient) {
// Sort the documents in descending order rather than ascending order, which
// is the order we expect to see in the response.
c.SetSorter(func(roleSets []*api.PlatformWorkloadIdentityRoleSetDocument) {
sort.Slice(roleSets, func(i, j int) bool {
return version.CreateSemverFromMinorVersionString(roleSets[j].PlatformWorkloadIdentityRoleSet.Properties.OpenShiftVersion).LessThan(*version.CreateSemverFromMinorVersionString(roleSets[i].PlatformWorkloadIdentityRoleSet.Properties.OpenShiftVersion))
})
})
},
wantStatusCode: http.StatusOK,
wantResponse: &admin.PlatformWorkloadIdentityRoleSetList{
PlatformWorkloadIdentityRoleSets: []*admin.PlatformWorkloadIdentityRoleSet{
{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
},
{
name: "GET request results in StatusInternalServerError due to issues with Cosmos DB",
fixture: func(f *testdatabase.Fixture) {},
cosmosdb: func(c *cosmosdb.FakePlatformWorkloadIdentityRoleSetDocumentClient) {
c.SetError(errors.New("Well shoot, Cosmos DB isn't working!"))
},
wantStatusCode: http.StatusInternalServerError,
wantResponse: &admin.PlatformWorkloadIdentityRoleSetList{
PlatformWorkloadIdentityRoleSets: []*admin.PlatformWorkloadIdentityRoleSet{},
},
wantError: api.NewCloudError(http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "Internal server error.").Error(),
},
} {
t.Run(tt.name, func(t *testing.T) {
ti := newTestInfra(t).WithPlatformWorkloadIdentityRoleSets()
defer ti.done()
if tt.cosmosdb != nil {
tt.cosmosdb(ti.platformWorkloadIdentityRoleSetsClient)
}
err := ti.buildFixtures(tt.fixture)
if err != nil {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, nil, ti.platformWorkloadIdentityRoleSetsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
go f.Run(ctx, nil, nil)
resp, b, err := ti.request(http.MethodGet, "https://server/admin/platformworkloadidentityrolesets",
nil, nil)
if err != nil {
t.Fatal(err)
}
err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, tt.wantResponse)
if err != nil {
t.Error(err)
}
})
}
}

Просмотреть файл

@ -0,0 +1,96 @@
package frontend
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"encoding/json"
"net/http"
"path/filepath"
"github.com/sirupsen/logrus"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/admin"
"github.com/Azure/ARO-RP/pkg/frontend/middleware"
)
func (f *frontend) putAdminPlatformWorkloadIdentityRoleSet(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
r.URL.Path = filepath.Dir(r.URL.Path)
converter := f.apis[admin.APIVersion].PlatformWorkloadIdentityRoleSetConverter
staticValidator := f.apis[admin.APIVersion].PlatformWorkloadIdentityRoleSetStaticValidator
body := r.Context().Value(middleware.ContextKeyBody).([]byte)
if len(body) == 0 || !json.Valid(body) {
api.WriteError(w, http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized.")
return
}
var ext *admin.PlatformWorkloadIdentityRoleSet
err := json.Unmarshal(body, &ext)
if err != nil {
api.WriteError(w, http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content could not be deserialized: "+err.Error())
return
}
docs, err := f.dbPlatformWorkloadIdentityRoleSets.ListAll(ctx)
if err != nil {
log.Error(err)
api.WriteError(w, http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "Internal server error.")
return
}
var roleSetDoc *api.PlatformWorkloadIdentityRoleSetDocument
if docs != nil {
for _, doc := range docs.PlatformWorkloadIdentityRoleSetDocuments {
if doc.PlatformWorkloadIdentityRoleSet.Properties.OpenShiftVersion == ext.Properties.OpenShiftVersion {
roleSetDoc = doc
break
}
}
}
isCreate := roleSetDoc == nil
if isCreate {
err = staticValidator.Static(ext, nil)
roleSetDoc = &api.PlatformWorkloadIdentityRoleSetDocument{
ID: f.dbPlatformWorkloadIdentityRoleSets.NewUUID(),
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{},
}
} else {
err = staticValidator.Static(ext, roleSetDoc.PlatformWorkloadIdentityRoleSet)
}
if err != nil {
adminReply(log, w, nil, []byte{}, err)
return
}
converter.ToInternal(ext, roleSetDoc.PlatformWorkloadIdentityRoleSet)
if isCreate {
roleSetDoc, err = f.dbPlatformWorkloadIdentityRoleSets.Create(ctx, roleSetDoc)
if err != nil {
log.Error(err)
api.WriteError(w, http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "Internal server error.")
return
}
} else {
roleSetDoc, err = f.dbPlatformWorkloadIdentityRoleSets.Update(ctx, roleSetDoc)
if err != nil {
log.Error(err)
api.WriteError(w, http.StatusInternalServerError, api.CloudErrorCodeInternalServerError, "", "Internal server error.")
return
}
}
b, err := json.MarshalIndent(converter.ToExternal(roleSetDoc.PlatformWorkloadIdentityRoleSet), "", " ")
if err == nil {
if isCreate {
err = statusCodeError(http.StatusCreated)
}
}
adminReply(log, w, nil, b, err)
}

Просмотреть файл

@ -0,0 +1,788 @@
package frontend
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"net/http"
"testing"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/admin"
"github.com/Azure/ARO-RP/pkg/metrics/noop"
testdatabase "github.com/Azure/ARO-RP/test/database"
)
func TestPlatformWorkloadIdentityRoleSetPut(t *testing.T) {
ctx := context.Background()
type test struct {
name string
fixture func(f *testdatabase.Fixture)
body *admin.PlatformWorkloadIdentityRoleSet
wantStatusCode int
wantResponse *admin.PlatformWorkloadIdentityRoleSet
wantError string
wantDocuments []*api.PlatformWorkloadIdentityRoleSetDocument
}
for _, tt := range []*test{
{
name: "PUT to update an existing entry updates it in-place and results in StatusOK",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
wantStatusCode: http.StatusOK,
wantResponse: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
},
{
name: "PUT to add a new entry creates it successfully and results in StatusOK",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
wantStatusCode: http.StatusCreated,
wantResponse: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
{
ID: "08080808-0808-0808-0808-080808080002",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing request body results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {},
body: &admin.PlatformWorkloadIdentityRoleSet{},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.openShiftVersion: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{},
},
{
name: "PUT with missing OpenShiftVersion results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.openShiftVersion: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing PlatformWorkloadIdentityRoles results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.platformWorkloadIdentityRoles: Must be provided and must be non-empty",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing PlatformWorkloadIdentityRole.OperatorName results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.platformWorkloadIdentityRoles[0].operatorName: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing PlatformWorkloadIdentityRole.RoleDefinitionName results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.platformWorkloadIdentityRoles[0].roleDefinitionName: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing PlatformWorkloadIdentityRole.RoleDefinitionID results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.platformWorkloadIdentityRoles[0].roleDefinitionId: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing PlatformWorkloadIdentityRole.ServiceAccounts results in StatusBadRequest",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
},
},
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.platformWorkloadIdentityRoles[0].serviceAccounts: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
{
name: "PUT with missing PlatformWorkloadIdentityRole.RoleDefinitionId and PlatformWorkloadIdentityRole.ServiceAccounts results in StatusBadRequest - tests the case where multiple attributes are missing and error message consists of messages about multiple missing properties joined together",
fixture: func(f *testdatabase.Fixture) {
f.AddPlatformWorkloadIdentityRoleSetDocuments(
&api.PlatformWorkloadIdentityRoleSetDocument{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
)
},
body: &admin.PlatformWorkloadIdentityRoleSet{
Properties: admin.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []admin.PlatformWorkloadIdentityRole{
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
},
},
},
},
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidParameter: properties.platformWorkloadIdentityRoles[0].roleDefinitionId, properties.platformWorkloadIdentityRoles[0].serviceAccounts: Must be provided",
wantDocuments: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
ID: "08080808-0808-0808-0808-080808080001",
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
ti := newTestInfra(t).WithPlatformWorkloadIdentityRoleSets()
defer ti.done()
err := ti.buildFixtures(tt.fixture)
if err != nil {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, nil, ti.platformWorkloadIdentityRoleSetsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
go f.Run(ctx, nil, nil)
resp, b, err := ti.request(http.MethodPut, "https://server/admin/platformworkloadidentityrolesets",
http.Header{
"Content-Type": []string{"application/json"},
}, tt.body)
if err != nil {
t.Fatal(err)
}
err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, tt.wantResponse)
if err != nil {
t.Error(err)
}
if tt.wantDocuments != nil {
ti.checker.AddPlatformWorkloadIdentityRoleSetDocuments(tt.wantDocuments...)
for _, err := range ti.checker.CheckPlatformWorkloadIdentityRoleSets(ti.platformWorkloadIdentityRoleSetsClient) {
t.Error(err)
}
}
})
}
}

Просмотреть файл

@ -136,7 +136,7 @@ func TestGetAsyncOperationResult(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -183,7 +183,7 @@ func TestGetAsyncOperationsStatus(t *testing.T) {
ti.asyncOperationsClient.SetError(tt.dbError)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -12,7 +12,7 @@ import (
"github.com/Azure/ARO-RP/pkg/util/recover"
)
func (f *frontend) changefeed(ctx context.Context) {
func (f *frontend) changefeedOcpVersions(ctx context.Context) {
defer recover.Panic(f.baseLog)
// f.dbOpenShiftVersions will be nil when running unit tests. Return here to avoid nil pointer panic
@ -20,15 +20,30 @@ func (f *frontend) changefeed(ctx context.Context) {
return
}
frontendIterator := f.dbOpenShiftVersions.ChangeFeed()
ocpVersionsIterator := f.dbOpenShiftVersions.ChangeFeed()
t := time.NewTicker(10 * time.Second)
defer t.Stop()
f.updateFromIterator(ctx, t, frontendIterator)
f.updateFromIteratorOcpVersions(ctx, t, ocpVersionsIterator)
}
func (f *frontend) updateFromIterator(ctx context.Context, ticker *time.Ticker, frontendIterator cosmosdb.OpenShiftVersionDocumentIterator) {
func (f *frontend) changefeedRoleSets(ctx context.Context) {
defer recover.Panic(f.baseLog)
if f.dbPlatformWorkloadIdentityRoleSets == nil {
return
}
roleSetsIterator := f.dbPlatformWorkloadIdentityRoleSets.ChangeFeed()
t := time.NewTicker(10 * time.Second)
defer t.Stop()
f.updateFromIteratorRoleSets(ctx, t, roleSetsIterator)
}
func (f *frontend) updateFromIteratorOcpVersions(ctx context.Context, ticker *time.Ticker, frontendIterator cosmosdb.OpenShiftVersionDocumentIterator) {
for {
successful := true
@ -47,7 +62,7 @@ func (f *frontend) updateFromIterator(ctx context.Context, ticker *time.Ticker,
}
if successful {
f.lastChangefeed.Store(time.Now())
f.lastOcpVersionsChangefeed.Store(time.Now())
}
select {
@ -60,8 +75,8 @@ func (f *frontend) updateFromIterator(ctx context.Context, ticker *time.Ticker,
// updateOcpVersions adds enabled versions to the frontend cache
func (f *frontend) updateOcpVersions(docs []*api.OpenShiftVersionDocument) {
f.mu.Lock()
defer f.mu.Unlock()
f.ocpVersionsMu.Lock()
defer f.ocpVersionsMu.Unlock()
for _, doc := range docs {
if doc.OpenShiftVersion.Deleting || !doc.OpenShiftVersion.Properties.Enabled {
@ -75,3 +90,47 @@ func (f *frontend) updateOcpVersions(docs []*api.OpenShiftVersionDocument) {
}
}
}
func (f *frontend) updateFromIteratorRoleSets(ctx context.Context, ticker *time.Ticker, frontendIterator cosmosdb.PlatformWorkloadIdentityRoleSetDocumentIterator) {
for {
successful := true
for {
docs, err := frontendIterator.Next(ctx, -1)
if err != nil {
successful = false
f.baseLog.Error(err)
break
}
if docs == nil {
break
}
f.updatePlatformWorkloadIdentityRoleSets(docs.PlatformWorkloadIdentityRoleSetDocuments)
}
if successful {
f.lastPlatformWorkloadIdentityRoleSetsChangefeed.Store(time.Now())
}
select {
case <-ticker.C:
case <-ctx.Done():
return
}
}
}
func (f *frontend) updatePlatformWorkloadIdentityRoleSets(docs []*api.PlatformWorkloadIdentityRoleSetDocument) {
f.platformWorkloadIdentityRoleSetsMu.Lock()
defer f.platformWorkloadIdentityRoleSetsMu.Unlock()
for _, doc := range docs {
if doc.PlatformWorkloadIdentityRoleSet.Deleting {
// https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed-design-patterns#deletes
delete(f.availablePlatformWorkloadIdentityRoleSets, doc.PlatformWorkloadIdentityRoleSet.Properties.OpenShiftVersion)
} else {
f.availablePlatformWorkloadIdentityRoleSets[doc.PlatformWorkloadIdentityRoleSet.Properties.OpenShiftVersion] = doc.PlatformWorkloadIdentityRoleSet
}
}
}

Просмотреть файл

@ -14,7 +14,7 @@ import (
"github.com/Azure/ARO-RP/pkg/util/cmp"
)
func TestUpdateFromIterator(t *testing.T) {
func TestUpdateFromIteratorOcpVersions(t *testing.T) {
for _, tt := range []struct {
name string
docsInIterator []*api.OpenShiftVersionDocument
@ -22,7 +22,7 @@ func TestUpdateFromIterator(t *testing.T) {
wantVersions map[string]*api.OpenShiftVersion
}{
{
name: "add to empty",
name: "Add a new doc from the changefeed to an empty frontend cache",
docsInIterator: []*api.OpenShiftVersionDocument{
{
OpenShiftVersion: &api.OpenShiftVersion{
@ -44,7 +44,7 @@ func TestUpdateFromIterator(t *testing.T) {
},
},
{
name: "do nothing",
name: "Docs in changefeed match docs in frontend cache - no changes needed",
docsInIterator: []*api.OpenShiftVersionDocument{
{
OpenShiftVersion: &api.OpenShiftVersion{
@ -73,7 +73,7 @@ func TestUpdateFromIterator(t *testing.T) {
},
},
{
name: "add to not empty",
name: "Add a new doc from the iterator to a non-empty frontend cache",
docsInIterator: []*api.OpenShiftVersionDocument{
{
OpenShiftVersion: &api.OpenShiftVersion{
@ -108,7 +108,7 @@ func TestUpdateFromIterator(t *testing.T) {
},
},
{
name: "remove existing",
name: "A doc present in the frontend cache is marked deleting in the changefeed - remove it from the cache",
docsInIterator: []*api.OpenShiftVersionDocument{
{
OpenShiftVersion: &api.OpenShiftVersion{
@ -152,7 +152,7 @@ func TestUpdateFromIterator(t *testing.T) {
},
},
{
name: "remove disabled versions",
name: "A doc present in the frontend cache is marked disabled in the changefeed - remove it from the cache",
docsInIterator: []*api.OpenShiftVersionDocument{
{
OpenShiftVersion: &api.OpenShiftVersion{
@ -184,7 +184,7 @@ func TestUpdateFromIterator(t *testing.T) {
fakeIterator := cosmosdb.NewFakeOpenShiftVersionDocumentIterator(tt.docsInIterator, 0)
go frontend.updateFromIterator(ctx, ticker, fakeIterator)
go frontend.updateFromIteratorOcpVersions(ctx, ticker, fakeIterator)
time.Sleep(time.Second)
cancel()
@ -194,3 +194,345 @@ func TestUpdateFromIterator(t *testing.T) {
})
}
}
func TestUpdateFromIteratorRoleSets(t *testing.T) {
for _, tt := range []struct {
name string
docsInIterator []*api.PlatformWorkloadIdentityRoleSetDocument
roleSets map[string]*api.PlatformWorkloadIdentityRoleSet
wantRoleSets map[string]*api.PlatformWorkloadIdentityRoleSet
}{
{
name: "add to empty",
docsInIterator: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
roleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{},
wantRoleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
{
name: "do nothing",
docsInIterator: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
roleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
wantRoleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
},
{
name: "add to not empty",
docsInIterator: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
roleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
},
wantRoleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
"4.15": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
{
name: "remove existing",
docsInIterator: []*api.PlatformWorkloadIdentityRoleSetDocument{
{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
Deleting: true,
},
},
{
PlatformWorkloadIdentityRoleSet: &api.PlatformWorkloadIdentityRoleSet{
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
roleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
"4.15": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
wantRoleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.15": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
ticker := time.NewTicker(1)
ctx, cancel := context.WithCancel(context.TODO())
frontend := frontend{
availablePlatformWorkloadIdentityRoleSets: tt.roleSets,
}
fakeIterator := cosmosdb.NewFakePlatformWorkloadIdentityRoleSetDocumentIterator(tt.docsInIterator, 0)
go frontend.updateFromIteratorRoleSets(ctx, ticker, fakeIterator)
time.Sleep(time.Second)
cancel()
if !reflect.DeepEqual(frontend.availablePlatformWorkloadIdentityRoleSets, tt.wantRoleSets) {
t.Error(cmp.Diff(frontend.availablePlatformWorkloadIdentityRoleSets, tt.wantRoleSets))
}
})
}
}

Просмотреть файл

@ -120,7 +120,7 @@ func TestDeleteClusterManagerConfiguration(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, nil, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, nil, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -123,7 +123,7 @@ func TestGetClusterManagerConfiguration(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, nil, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, nil, nil, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -201,7 +201,7 @@ func TestPutOrPatchClusterManagerConfiguration(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -523,6 +523,7 @@ func TestFixEtcd(t *testing.T) {
ti.openShiftClustersDatabase,
ti.subscriptionsDatabase,
nil,
nil,
api.APIs,
&noop.Noop{},
&noop.Noop{},

Просмотреть файл

@ -57,18 +57,22 @@ type frontend struct {
apiVersionMiddleware middleware.ApiVersionValidator
maintenanceMiddleware middleware.MaintenanceMiddleware
dbAsyncOperations database.AsyncOperations
dbClusterManagerConfiguration database.ClusterManagerConfigurations
dbOpenShiftClusters database.OpenShiftClusters
dbSubscriptions database.Subscriptions
dbOpenShiftVersions database.OpenShiftVersions
dbAsyncOperations database.AsyncOperations
dbClusterManagerConfiguration database.ClusterManagerConfigurations
dbOpenShiftClusters database.OpenShiftClusters
dbSubscriptions database.Subscriptions
dbOpenShiftVersions database.OpenShiftVersions
dbPlatformWorkloadIdentityRoleSets database.PlatformWorkloadIdentityRoleSets
defaultOcpVersion string // always enabled
enabledOcpVersions map[string]*api.OpenShiftVersion
apis map[string]*api.Version
defaultOcpVersion string // always enabled
enabledOcpVersions map[string]*api.OpenShiftVersion
availablePlatformWorkloadIdentityRoleSets map[string]*api.PlatformWorkloadIdentityRoleSet
apis map[string]*api.Version
lastChangefeed atomic.Value //time.Time
mu sync.RWMutex
lastOcpVersionsChangefeed atomic.Value //time.Time
lastPlatformWorkloadIdentityRoleSetsChangefeed atomic.Value
ocpVersionsMu sync.RWMutex
platformWorkloadIdentityRoleSetsMu sync.RWMutex
aead encryption.AEAD
@ -107,6 +111,7 @@ type Runnable interface {
Run(context.Context, <-chan struct{}, chan<- struct{})
}
// TODO: Get the number of function parameters under control :D
// NewFrontend returns a new runnable frontend
func NewFrontend(ctx context.Context,
auditLog *logrus.Entry,
@ -117,6 +122,7 @@ func NewFrontend(ctx context.Context,
dbOpenShiftClusters database.OpenShiftClusters,
dbSubscriptions database.Subscriptions,
dbOpenShiftVersions database.OpenShiftVersions,
dbPlatformWorkloadIdentityRoleSets database.PlatformWorkloadIdentityRoleSets,
apis map[string]*api.Version,
m metrics.Emitter,
clusterm metrics.Emitter,
@ -148,18 +154,19 @@ func NewFrontend(ctx context.Context,
AdminAuth: _env.AdminClientAuthorizer(),
ArmAuth: _env.ArmClientAuthorizer(),
},
dbAsyncOperations: dbAsyncOperations,
dbClusterManagerConfiguration: dbClusterManagerConfiguration,
dbOpenShiftClusters: dbOpenShiftClusters,
dbSubscriptions: dbSubscriptions,
dbOpenShiftVersions: dbOpenShiftVersions,
apis: apis,
m: middleware.MetricsMiddleware{Emitter: m},
maintenanceMiddleware: middleware.MaintenanceMiddleware{Emitter: clusterm},
aead: aead,
hiveClusterManager: hiveClusterManager,
kubeActionsFactory: kubeActionsFactory,
azureActionsFactory: azureActionsFactory,
dbAsyncOperations: dbAsyncOperations,
dbClusterManagerConfiguration: dbClusterManagerConfiguration,
dbOpenShiftClusters: dbOpenShiftClusters,
dbSubscriptions: dbSubscriptions,
dbOpenShiftVersions: dbOpenShiftVersions,
dbPlatformWorkloadIdentityRoleSets: dbPlatformWorkloadIdentityRoleSets,
apis: apis,
m: middleware.MetricsMiddleware{Emitter: m},
maintenanceMiddleware: middleware.MaintenanceMiddleware{Emitter: clusterm},
aead: aead,
hiveClusterManager: hiveClusterManager,
kubeActionsFactory: kubeActionsFactory,
azureActionsFactory: azureActionsFactory,
quotaValidator: quotaValidator{},
skuValidator: skuValidator{},
@ -167,7 +174,8 @@ func NewFrontend(ctx context.Context,
clusterEnricher: enricher,
enabledOcpVersions: map[string]*api.OpenShiftVersion{},
enabledOcpVersions: map[string]*api.OpenShiftVersion{},
availablePlatformWorkloadIdentityRoleSets: map[string]*api.PlatformWorkloadIdentityRoleSet{},
bucketAllocator: &bucket.Random{},
@ -277,6 +285,8 @@ func (f *frontend) chiAuthenticatedRoutes(router chi.Router) {
r.Get("/operationresults/{operationId}", f.getAsyncOperationResult)
r.Get("/openshiftversions", f.listInstallVersions)
r.Get("/platformworkloadidentityrolesets", f.listPlatformWorkloadIdentityRoleSets)
})
})
})
@ -288,6 +298,10 @@ func (f *frontend) chiAuthenticatedRoutes(router chi.Router) {
r.Get("/", f.getAdminOpenShiftVersions)
r.Put("/", f.putAdminOpenShiftVersion)
})
r.Route("/platformworkloadidentityrolesets", func(r chi.Router) {
r.Get("/", f.getAdminPlatformWorkloadIdentityRoleSets)
r.Put("/", f.putAdminPlatformWorkloadIdentityRoleSet)
})
r.Get("/supportedvmsizes", f.supportedvmsizes)
r.Route("/subscriptions/{subscriptionId}", func(r chi.Router) {
@ -372,7 +386,8 @@ func (f *frontend) setupRouter() chi.Router {
func (f *frontend) Run(ctx context.Context, stop <-chan struct{}, done chan<- struct{}) {
defer recover.Panic(f.baseLog)
go f.changefeed(ctx)
go f.changefeedOcpVersions(ctx)
go f.changefeedRoleSets(ctx)
if stop != nil {
go func() {

Просмотреть файл

@ -97,7 +97,7 @@ func TestAppLensDetectors(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, func(*logrus.Entry, env.Interface, *api.OpenShiftCluster, *api.SubscriptionDocument) (adminactions.AzureActions, error) {
return a, nil
}, nil)

Просмотреть файл

@ -114,7 +114,7 @@ func TestDeleteOpenShiftCluster(t *testing.T) {
ti.subscriptionsClient.SetError(tt.dbError)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -95,7 +95,7 @@ func TestGetOpenShiftCluster(t *testing.T) {
ti.openShiftClustersClient.SetError(tt.dbError)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -204,7 +204,7 @@ func TestListOpenShiftCluster(t *testing.T) {
aead := testdatabase.NewFakeAEAD()
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, aead, nil, nil, nil, ti.enricher)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, aead, nil, nil, nil, ti.enricher)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -158,14 +158,14 @@ func TestPreflightValidation(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, ti.platformWorkloadIdentityRoleSetsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
oc := tt.preflightRequest()
go f.Run(ctx, nil, nil)
f.mu.Lock()
f.ocpVersionsMu.Lock()
f.defaultOcpVersion = "4.10.0"
f.enabledOcpVersions = map[string]*api.OpenShiftVersion{
f.defaultOcpVersion: {
@ -174,7 +174,7 @@ func TestPreflightValidation(t *testing.T) {
},
},
}
f.mu.Unlock()
f.ocpVersionsMu.Unlock()
headers := http.Header{
"Content-Type": []string{"application/json"},

Просмотреть файл

@ -1727,7 +1727,7 @@ func TestPutOrPatchOpenShiftClusterAdminAPI(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
if err != nil {
t.Fatal(err)
}
@ -2800,7 +2800,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, ti.platformWorkloadIdentityRoleSetsDatabase, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
if err != nil {
t.Fatal(err)
}
@ -2817,14 +2817,14 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
}
go f.Run(ctx, nil, nil)
f.mu.Lock()
f.ocpVersionsMu.Lock()
f.enabledOcpVersions = tt.changeFeed
for key, doc := range tt.changeFeed {
if doc.Properties.Default {
f.defaultOcpVersion = key
}
}
f.mu.Unlock()
f.ocpVersionsMu.Unlock()
oc := &v20200430.OpenShiftCluster{}
if tt.request != nil {
@ -3133,7 +3133,7 @@ func TestPutOrPatchOpenShiftClusterValidated(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, ti.openShiftVersionsDatabase, ti.platformWorkloadIdentityRoleSetsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, ti.enricher)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -267,7 +267,7 @@ func TestPostOpenShiftClusterCredentials(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -242,7 +242,7 @@ func TestPostOpenShiftClusterKubeConfigCredentials(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, apis, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -35,11 +35,11 @@ func (f *frontend) listInstallVersions(w http.ResponseWriter, r *http.Request) {
func (f *frontend) getEnabledInstallVersions(ctx context.Context) []*api.OpenShiftVersion {
versions := make([]*api.OpenShiftVersion, 0)
f.mu.RLock()
f.ocpVersionsMu.RLock()
for _, v := range f.enabledOcpVersions {
versions = append(versions, v)
}
f.mu.RUnlock()
f.ocpVersionsMu.RUnlock()
return versions
}

Просмотреть файл

@ -78,21 +78,21 @@ func TestListInstallVersions(t *testing.T) {
ti := newTestInfra(t).WithSubscriptions().WithOpenShiftVersions()
defer ti.done()
frontend, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, ti.openShiftVersionsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
frontend, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, ti.openShiftVersionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
go frontend.Run(ctx, nil, nil)
frontend.mu.Lock()
frontend.ocpVersionsMu.Lock()
frontend.enabledOcpVersions = tt.changeFeed
for key, doc := range tt.changeFeed {
if doc.Properties.Enabled {
frontend.defaultOcpVersion = key
}
}
frontend.mu.Unlock()
frontend.ocpVersionsMu.Unlock()
resp, b, err := ti.request(method,
fmt.Sprintf("https://server/subscriptions/%s/providers/Microsoft.RedHatOpenShift/locations/%s/openshiftversions?api-version=%s", mockSubID, ti.env.Location(), tt.apiVersion),

Просмотреть файл

@ -0,0 +1,45 @@
package frontend
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/sirupsen/logrus"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/frontend/middleware"
)
func (f *frontend) listPlatformWorkloadIdentityRoleSets(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := ctx.Value(middleware.ContextKeyLog).(*logrus.Entry)
apiVersion := r.URL.Query().Get(api.APIVersionKey)
resourceProviderNamespace := chi.URLParam(r, "resourceProviderNamespace")
if f.apis[apiVersion].PlatformWorkloadIdentityRoleSetConverter == nil {
api.WriteError(w, http.StatusBadRequest, api.CloudErrorCodeInvalidResourceType, "", "The endpoint could not be found in the namespace '%s' for api version '%s'.", resourceProviderNamespace, apiVersion)
return
}
roleSets := f.getAvailablePlatformWorkloadIdentityRoleSets(ctx)
converter := f.apis[apiVersion].PlatformWorkloadIdentityRoleSetConverter
b, err := json.MarshalIndent(converter.ToExternalList(roleSets), "", " ")
reply(log, w, nil, b, err)
}
func (f *frontend) getAvailablePlatformWorkloadIdentityRoleSets(ctx context.Context) []*api.PlatformWorkloadIdentityRoleSet {
roleSets := make([]*api.PlatformWorkloadIdentityRoleSet, 0)
f.platformWorkloadIdentityRoleSetsMu.RLock()
for _, pwirs := range f.availablePlatformWorkloadIdentityRoleSets {
roleSets = append(roleSets, pwirs)
}
f.platformWorkloadIdentityRoleSetsMu.RUnlock()
return roleSets
}

Просмотреть файл

@ -0,0 +1,176 @@
package frontend
import (
"context"
"encoding/json"
"fmt"
"net/http"
"sort"
"testing"
"github.com/Azure/ARO-RP/pkg/api"
"github.com/Azure/ARO-RP/pkg/api/v20240812preview"
"github.com/Azure/ARO-RP/pkg/metrics/noop"
"github.com/Azure/ARO-RP/pkg/util/version"
)
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
func TestListPlatformWorkloadIdentityRoleSets(t *testing.T) {
mockSubID := "00000000-0000-0000-0000-000000000000"
method := http.MethodGet
ctx := context.Background()
for _, tt := range []struct {
name string
changeFeed map[string]*api.PlatformWorkloadIdentityRoleSet
apiVersion string
wantStatusCode int
wantResponse v20240812preview.PlatformWorkloadIdentityRoleSetList
wantError string
}{
{
name: "GET request results in StatusOK",
changeFeed: map[string]*api.PlatformWorkloadIdentityRoleSet{
"4.14": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
},
},
},
"4.15": {
Properties: api.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []api.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
ServiceAccounts: []string{
"openshift-cloud-controller-manager:cloud-controller-manager",
},
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
ServiceAccounts: []string{
"openshift-ingress-operator:ingress-operator",
},
},
},
},
},
},
apiVersion: "2024-08-12-preview",
wantStatusCode: 200,
wantResponse: v20240812preview.PlatformWorkloadIdentityRoleSetList{
PlatformWorkloadIdentityRoleSets: []*v20240812preview.PlatformWorkloadIdentityRoleSet{
{
Properties: v20240812preview.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.14",
PlatformWorkloadIdentityRoles: []v20240812preview.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
},
},
},
},
{
Properties: v20240812preview.PlatformWorkloadIdentityRoleSetProperties{
OpenShiftVersion: "4.15",
PlatformWorkloadIdentityRoles: []v20240812preview.PlatformWorkloadIdentityRole{
{
OperatorName: "CloudControllerManager",
RoleDefinitionName: "Azure RedHat OpenShift Cloud Controller Manager Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/a1f96423-95ce-4224-ab27-4e3dc72facd4",
},
{
OperatorName: "ClusterIngressOperator",
RoleDefinitionName: "Azure RedHat OpenShift Cluster Ingress Operator Role",
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/0336e1d3-7a87-462b-b6db-342b63f7802c",
},
},
},
},
},
},
},
{
name: "GET request with non-existent API version results in StatusBadRequest",
apiVersion: "invalid",
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidResourceType: : The resource type '' could not be found in the namespace 'microsoft.redhatopenshift' for api version 'invalid'.",
},
{
name: "GET request with old API version that doesn't support MIWI results in StatusBadRequest",
apiVersion: "2022-09-04",
wantStatusCode: http.StatusBadRequest,
wantError: "400: InvalidResourceType: : The endpoint could not be found in the namespace 'microsoft.redhatopenshift' for api version '2022-09-04'.",
},
} {
t.Run(tt.name, func(t *testing.T) {
ti := newTestInfra(t).WithSubscriptions().WithPlatformWorkloadIdentityRoleSets()
defer ti.done()
frontend, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, nil, nil, nil, nil, nil, ti.platformWorkloadIdentityRoleSetsDatabase, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
go frontend.Run(ctx, nil, nil)
frontend.platformWorkloadIdentityRoleSetsMu.Lock()
frontend.availablePlatformWorkloadIdentityRoleSets = tt.changeFeed
frontend.platformWorkloadIdentityRoleSetsMu.Unlock()
resp, b, err := ti.request(method,
fmt.Sprintf("https://server/subscriptions/%s/providers/Microsoft.RedHatOpenShift/locations/%s/platformworkloadidentityrolesets?api-version=%s", mockSubID, ti.env.Location(), tt.apiVersion),
nil, nil)
if err != nil {
t.Fatal(err)
}
// sort the response as the version order might be changed
if b != nil && resp.StatusCode == http.StatusOK {
var r v20240812preview.PlatformWorkloadIdentityRoleSetList
if err = json.Unmarshal(b, &r); err != nil {
t.Error(err)
}
sort.Slice(r.PlatformWorkloadIdentityRoleSets, func(i, j int) bool {
return version.CreateSemverFromMinorVersionString(r.PlatformWorkloadIdentityRoleSets[i].Properties.OpenShiftVersion).LessThan(*version.CreateSemverFromMinorVersionString(r.PlatformWorkloadIdentityRoleSets[j].Properties.OpenShiftVersion))
})
b, err = json.Marshal(r)
if err != nil {
t.Error(err)
}
}
// marshal the expected response into a []byte otherwise
// it will compare zero values to omitempty json tags
want, err := json.Marshal(tt.wantResponse)
if err != nil {
t.Error(err)
}
err = validateResponse(resp, b, tt.wantStatusCode, tt.wantError, want)
if err != nil {
t.Error(err)
}
})
}
}

Просмотреть файл

@ -21,9 +21,10 @@ func (f *frontend) checkReady() bool {
return false
}
_, ok := f.lastChangefeed.Load().(time.Time)
_, okOcpVersions := f.lastOcpVersionsChangefeed.Load().(time.Time)
_, okPlatformWorkloadIdentityRoleSets := f.lastPlatformWorkloadIdentityRoleSetsChangefeed.Load().(time.Time)
return ok &&
return okOcpVersions && okPlatformWorkloadIdentityRoleSets &&
f.ready.Load().(bool) &&
f.env.ArmClientAuthorizer().IsReady() &&
f.env.AdminClientAuthorizer().IsReady()

Просмотреть файл

@ -77,14 +77,15 @@ func TestSecurity(t *testing.T) {
log := logrus.NewEntry(logrus.StandardLogger())
auditHook, auditEntry := testlog.NewAudit()
f, err := NewFrontend(ctx, auditEntry, log, _env, nil, nil, nil, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, auditEntry, log, _env, nil, nil, nil, nil, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
// enable /healthz to return 200
f.startTime = time.Time{}
f.lastChangefeed.Store(time.Time{})
f.lastOcpVersionsChangefeed.Store(time.Time{})
f.lastPlatformWorkloadIdentityRoleSetsChangefeed.Store(time.Time{})
go f.Run(ctx, nil, nil)

Просмотреть файл

@ -68,18 +68,20 @@ type testInfra struct {
fixture *testdatabase.Fixture
checker *testdatabase.Checker
openShiftClustersClient *cosmosdb.FakeOpenShiftClusterDocumentClient
openShiftClustersDatabase database.OpenShiftClusters
asyncOperationsClient *cosmosdb.FakeAsyncOperationDocumentClient
asyncOperationsDatabase database.AsyncOperations
billingClient *cosmosdb.FakeBillingDocumentClient
billingDatabase database.Billing
clusterManagerClient *cosmosdb.FakeClusterManagerConfigurationDocumentClient
clusterManagerDatabase database.ClusterManagerConfigurations
subscriptionsClient *cosmosdb.FakeSubscriptionDocumentClient
subscriptionsDatabase database.Subscriptions
openShiftVersionsClient *cosmosdb.FakeOpenShiftVersionDocumentClient
openShiftVersionsDatabase database.OpenShiftVersions
openShiftClustersClient *cosmosdb.FakeOpenShiftClusterDocumentClient
openShiftClustersDatabase database.OpenShiftClusters
asyncOperationsClient *cosmosdb.FakeAsyncOperationDocumentClient
asyncOperationsDatabase database.AsyncOperations
billingClient *cosmosdb.FakeBillingDocumentClient
billingDatabase database.Billing
clusterManagerClient *cosmosdb.FakeClusterManagerConfigurationDocumentClient
clusterManagerDatabase database.ClusterManagerConfigurations
subscriptionsClient *cosmosdb.FakeSubscriptionDocumentClient
subscriptionsDatabase database.Subscriptions
openShiftVersionsClient *cosmosdb.FakeOpenShiftVersionDocumentClient
openShiftVersionsDatabase database.OpenShiftVersions
platformWorkloadIdentityRoleSetsClient *cosmosdb.FakePlatformWorkloadIdentityRoleSetDocumentClient
platformWorkloadIdentityRoleSetsDatabase database.PlatformWorkloadIdentityRoleSets
}
func newTestInfra(t *testing.T) *testInfra {
@ -179,6 +181,13 @@ func (ti *testInfra) WithOpenShiftVersions() *testInfra {
return ti
}
func (ti *testInfra) WithPlatformWorkloadIdentityRoleSets() *testInfra {
uuid := deterministicuuid.NewTestUUIDGenerator(8)
ti.platformWorkloadIdentityRoleSetsDatabase, ti.platformWorkloadIdentityRoleSetsClient = testdatabase.NewFakePlatformWorkloadIdentityRoleSets(uuid)
ti.fixture.WithPlatformWorkloadIdentityRoleSets(ti.platformWorkloadIdentityRoleSetsDatabase, uuid)
return ti
}
func (ti *testInfra) WithClusterManagerConfigurations() *testInfra {
ti.clusterManagerDatabase, ti.clusterManagerClient = testdatabase.NewFakeClusterManager()
ti.fixture.WithClusterManagerConfigurations(ti.clusterManagerDatabase)

Просмотреть файл

@ -244,7 +244,7 @@ func TestPutSubscription(t *testing.T) {
t.Fatal(err)
}
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
f, err := NewFrontend(ctx, ti.audit, ti.log, ti.env, ti.asyncOperationsDatabase, ti.clusterManagerDatabase, ti.openShiftClustersDatabase, ti.subscriptionsDatabase, nil, nil, api.APIs, &noop.Noop{}, &noop.Noop{}, nil, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@ -203,14 +203,14 @@ func validateAdminMasterVMSize(vmSize string) error {
// validateInstallVersion validates the install version set in the clusterprofile.version
// TODO convert this into static validation instead of this receiver function in the validation for frontend.
func (f *frontend) validateInstallVersion(ctx context.Context, oc *api.OpenShiftCluster) error {
f.mu.RLock()
f.ocpVersionsMu.RLock()
// If this request is from an older API or the user did not specify
// the version to install, use the default version.
if oc.Properties.ClusterProfile.Version == "" {
oc.Properties.ClusterProfile.Version = f.defaultOcpVersion
}
_, ok := f.enabledOcpVersions[oc.Properties.ClusterProfile.Version]
f.mu.RUnlock()
f.ocpVersionsMu.RUnlock()
if !ok || !validate.RxInstallVersion.MatchString(oc.Properties.ClusterProfile.Version) {
return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "properties.clusterProfile.version", "The requested OpenShift version '%s' is invalid.", oc.Properties.ClusterProfile.Version)

Просмотреть файл

@ -85,7 +85,7 @@ func TestGuardRailsReconciler(t *testing.T) {
},
mocks: func(md *mock_deployer.MockDeployer, cluster *arov1alpha1.Cluster) {
expectedConfig := &config.GuardRailsDeploymentConfig{
Pullspec: "acrtest.example.com/gatekeeper:v3.11.1",
Pullspec: "acrtest.example.com/gatekeeper:v3.15.1",
Namespace: "openshift-azure-guardrails",
ManagerRequestsCPU: "100m",
ManagerLimitCPU: "1000m",

Просмотреть файл

@ -39,7 +39,7 @@ spec:
excludedNamespaces:
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
processes:

Просмотреть файл

@ -17,6 +17,101 @@ spec:
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: ExpansionTemplate is the Schema for the ExpansionTemplate API.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
properties:
name:
maxLength: 63
type: string
type: object
spec:
description: ExpansionTemplateSpec defines the desired state of ExpansionTemplate.
properties:
applyTo:
description: ApplyTo lists the specific groups, versions and kinds of generator resources which will be expanded.
items:
description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
properties:
groups:
items:
type: string
type: array
kinds:
items:
type: string
type: array
versions:
items:
type: string
type: array
type: object
type: array
enforcementAction:
description: EnforcementAction specifies the enforcement action to be used for resources matching the ExpansionTemplate. Specifying an empty value will use the enforcement action specified by the Constraint in violation.
type: string
generatedGVK:
description: GeneratedGVK specifies the GVK of the resources which the generator resource creates.
properties:
group:
type: string
kind:
type: string
version:
type: string
type: object
templateSource:
description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
type: string
type: object
status:
description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
properties:
byPod:
items:
description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
properties:
errors:
items:
properties:
message:
type: string
type:
type: string
required:
- message
type: object
type: array
id:
description: 'Important: Run "make" to regenerate code after modifying this file'
type: string
observedGeneration:
format: int64
type: integer
operations:
items:
type: string
type: array
templateUID:
description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
type: string
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}
- name: v1beta1
schema:
openAPIV3Schema:
description: ExpansionTemplate is the Schema for the ExpansionTemplate API.
@ -68,6 +163,42 @@ spec:
description: TemplateSource specifies the source field on the generator resource to use as the base for expanded resource. For Pod-creating generators, this is usually spec.template
type: string
type: object
status:
description: ExpansionTemplateStatus defines the observed state of ExpansionTemplate.
properties:
byPod:
items:
description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
properties:
errors:
items:
properties:
message:
type: string
type:
type: string
required:
- message
type: object
type: array
id:
description: 'Important: Run "make" to regenerate code after modifying this file'
type: string
observedGeneration:
format: int64
type: integer
operations:
items:
type: string
type: array
templateUID:
description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
type: string
type: object
type: array
type: object
type: object
served: true
storage: true
storage: false
subresources:
status: {}

Просмотреть файл

@ -41,12 +41,12 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
description: URL is the url for the provider. URL is prefixed with http:// or https://.
description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
storage: true
storage: false
- name: v1beta1
schema:
openAPIV3Schema:
@ -70,9 +70,9 @@ spec:
description: Timeout is the timeout when querying the provider.
type: integer
url:
description: URL is the url for the provider. URL is prefixed with http:// or https://.
description: URL is the url for the provider. URL is prefixed with https://.
type: string
type: object
type: object
served: true
storage: false
storage: true

Просмотреть файл

@ -65,7 +65,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -115,7 +115,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -151,7 +151,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@ -310,7 +310,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -360,7 +360,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -396,7 +396,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@ -555,7 +555,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -605,7 +605,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -641,7 +641,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:

Просмотреть файл

@ -0,0 +1,237 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
labels:
gatekeeper.sh/system: "yes"
name: assignimage.mutations.gatekeeper.sh
spec:
group: mutations.gatekeeper.sh
names:
kind: AssignImage
listKind: AssignImageList
plural: assignimage
singular: assignimage
preserveUnknownFields: false
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: AssignImage is the Schema for the assignimage API.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
properties:
name:
maxLength: 63
type: string
type: object
spec:
description: AssignImageSpec defines the desired state of AssignImage.
properties:
applyTo:
description: ApplyTo lists the specific groups, versions and kinds a mutation will be applied to. This is necessary because every mutation implies part of an object schema and object schemas are associated with specific GVKs.
items:
description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
properties:
groups:
items:
type: string
type: array
kinds:
items:
type: string
type: array
versions:
items:
type: string
type: array
type: object
type: array
location:
description: 'Location describes the path to be mutated, for example: `spec.containers[name: main].image`.'
type: string
match:
description: Match allows the user to limit which resources get mutated. Individual match criteria are AND-ed together. An undefined match criteria matches everything.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
items:
description: Kinds accepts a list of objects with apiGroups and kinds fields that list the groups/kinds of objects to which the mutation will apply. If multiple groups/kinds objects are specified, only one match is needed for the resource to be in scope.
properties:
apiGroups:
description: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required.
items:
type: string
type: array
kinds:
items:
type: string
type: array
type: object
type: array
labelSelector:
description: 'LabelSelector is the combination of two optional fields: `matchLabels` and `matchExpressions`. These two fields provide different methods of selecting or excluding k8s objects based on the label keys and values included in object metadata. All selection expressions from both sections are ANDed to determine if an object meets the cumulative requirements of the selector.'
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
properties:
key:
description: key is the label key that the selector applies to.
type: string
operator:
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
properties:
key:
description: key is the label key that the selector applies to.
type: string
operator:
description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
namespaces:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
description: Scope determines if cluster-scoped and/or namespaced-scoped resources are matched. Accepts `*`, `Cluster`, or `Namespaced`. (defaults to `*`)
type: string
source:
description: Source determines whether generated or original resources are matched. Accepts `Generated`|`Original`|`All` (defaults to `All`). A value of `Generated` will only match generated resources, while `Original` will only match regular resources.
enum:
- All
- Generated
- Original
type: string
type: object
parameters:
description: Parameters define the behavior of the mutator.
properties:
assignDomain:
description: AssignDomain sets the domain component on an image string. The trailing slash should not be included.
type: string
assignPath:
description: AssignPath sets the domain component on an image string.
type: string
assignTag:
description: AssignImage sets the image component on an image string. It must start with a `:` or `@`.
type: string
pathTests:
items:
description: "PathTest allows the user to customize how the mutation works if parent paths are missing. It traverses the list in order. All sub paths are tested against the provided condition, if the test fails, the mutation is not applied. All `subPath` entries must be a prefix of `location`. Any glob characters will take on the same value as was used to expand the matching glob in `location`. \n Available Tests: * MustExist - the path must exist or do not mutate * MustNotExist - the path must not exist or do not mutate."
properties:
condition:
description: Condition describes whether the path either MustExist or MustNotExist in the original object
enum:
- MustExist
- MustNotExist
type: string
subPath:
type: string
type: object
type: array
type: object
type: object
status:
description: AssignImageStatus defines the observed state of AssignImage.
properties:
byPod:
items:
description: MutatorPodStatusStatus defines the observed state of MutatorPodStatus.
properties:
enforced:
type: boolean
errors:
items:
description: MutatorError represents a single error caught while adding a mutator to a system.
properties:
message:
type: string
type:
description: Type indicates a specific class of error for use by controller code. If not present, the error should be treated as not matching any known type.
type: string
required:
- message
type: object
type: array
id:
type: string
mutatorUID:
description: Storing the mutator UID allows us to detect drift, such as when a mutator has been recreated after its CRD was deleted out from under it, interrupting the watch
type: string
observedGeneration:
format: int64
type: integer
operations:
items:
type: string
type: array
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}

Просмотреть файл

@ -39,13 +39,13 @@ spec:
location:
type: string
match:
description: Match selects objects to apply mutations to.
description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -95,7 +95,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -131,7 +131,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@ -250,13 +250,13 @@ spec:
location:
type: string
match:
description: Match selects objects to apply mutations to.
description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -306,7 +306,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -342,7 +342,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@ -461,13 +461,13 @@ spec:
location:
type: string
match:
description: Match selects objects to apply mutations to.
description: Match selects which objects are in scope.
properties:
excludedNamespaces:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -517,7 +517,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -553,7 +553,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:

Просмотреть файл

@ -65,7 +65,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -115,7 +115,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -151,7 +151,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@ -283,7 +283,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -333,7 +333,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -369,7 +369,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:
@ -501,7 +501,7 @@ spec:
description: 'ExcludedNamespaces is a list of namespace names. If defined, a constraint only applies to resources not in a listed namespace. ExcludedNamespaces also supports a prefix or suffix based glob. For example, `excludedNamespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `excludedNamespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
kinds:
@ -551,7 +551,7 @@ spec:
type: object
name:
description: 'Name is the name of an object. If defined, it will match against objects with the specified name. Name also supports a prefix or suffix glob. For example, `name: pod-*` would match both `pod-a` and `pod-b`, and `name: *-pod` would match both `a-pod` and `b-pod`.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
namespaceSelector:
description: NamespaceSelector is a label selector against an object's containing namespace or the object itself, if the object is a namespace.
@ -587,7 +587,7 @@ spec:
description: 'Namespaces is a list of namespace names. If defined, a constraint only applies to resources in a listed namespace. Namespaces also supports a prefix or suffix based glob. For example, `namespaces: [kube-*]` matches both `kube-system` and `kube-public`, and `namespaces: [*-system]` matches both `kube-system` and `gatekeeper-system`.'
items:
description: 'A string that supports globbing at its front or end. Ex: "kube-*" will match "kube-system" or "kube-public", "*-system" will match "kube-system" or "gatekeeper-system". The asterisk is required for wildcard matching.'
pattern: ^(\*|\*-)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\*|-\*)?$
pattern: ^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$
type: string
type: array
scope:

Просмотреть файл

@ -0,0 +1,62 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
labels:
gatekeeper.sh/system: "yes"
name: expansiontemplatepodstatuses.status.gatekeeper.sh
spec:
group: status.gatekeeper.sh
names:
kind: ExpansionTemplatePodStatus
listKind: ExpansionTemplatePodStatusList
plural: expansiontemplatepodstatuses
singular: expansiontemplatepodstatus
preserveUnknownFields: false
scope: Namespaced
versions:
- name: v1beta1
schema:
openAPIV3Schema:
description: ExpansionTemplatePodStatus is the Schema for the expansiontemplatepodstatuses API.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
status:
description: ExpansionTemplatePodStatusStatus defines the observed state of ExpansionTemplatePodStatus.
properties:
errors:
items:
properties:
message:
type: string
type:
type: string
required:
- message
type: object
type: array
id:
description: 'Important: Run "make" to regenerate code after modifying this file'
type: string
observedGeneration:
format: int64
type: integer
operations:
items:
type: string
type: array
templateUID:
description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated.
type: string
type: object
type: object
served: true
storage: true

Просмотреть файл

@ -0,0 +1,52 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
labels:
gatekeeper.sh/system: "yes"
name: syncsets.syncset.gatekeeper.sh
spec:
group: syncset.gatekeeper.sh
names:
kind: SyncSet
listKind: SyncSetList
plural: syncsets
singular: syncset
preserveUnknownFields: false
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: SyncSet defines which resources Gatekeeper will cache. The union of all SyncSets plus the syncOnly field of Gatekeeper's Config resource defines the sets of resources that will be synced.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
properties:
name:
maxLength: 63
type: string
type: object
spec:
properties:
gvks:
items:
properties:
group:
type: string
kind:
type: string
version:
type: string
type: object
type: array
type: object
type: object
served: true
storage: true

Просмотреть файл

@ -61,6 +61,24 @@ spec:
targets:
items:
properties:
code:
description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
items:
properties:
engine:
description: 'The engine used to evaluate the code. Example: "Rego". Required.'
type: string
source:
description: The source code for the template. Required.
x-kubernetes-preserve-unknown-fields: true
required:
- engine
- source
type: object
type: array
x-kubernetes-list-map-keys:
- engine
x-kubernetes-list-type: map
libs:
items:
type: string
@ -156,6 +174,24 @@ spec:
targets:
items:
properties:
code:
description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
items:
properties:
engine:
description: 'The engine used to evaluate the code. Example: "Rego". Required.'
type: string
source:
description: The source code for the template. Required.
x-kubernetes-preserve-unknown-fields: true
required:
- engine
- source
type: object
type: array
x-kubernetes-list-map-keys:
- engine
x-kubernetes-list-type: map
libs:
items:
type: string
@ -251,6 +287,24 @@ spec:
targets:
items:
properties:
code:
description: The source code options for the constraint template. "Rego" can only be specified in one place (either here or in the "rego" field)
items:
properties:
engine:
description: 'The engine used to evaluate the code. Example: "Rego". Required.'
type: string
source:
description: The source code for the template. Required.
x-kubernetes-preserve-unknown-fields: true
required:
- engine
- source
type: object
type: array
x-kubernetes-list-map-keys:
- engine
x-kubernetes-list-type: map
libs:
items:
type: string

Просмотреть файл

@ -69,6 +69,8 @@ spec:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: manager
- name: OTEL_RESOURCE_ATTRIBUTES
value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE),k8s.container.name=$(CONTAINER_NAME)
image: {{.Pullspec}}
imagePullPolicy: Always
livenessProbe:

Просмотреть файл

@ -6,6 +6,13 @@ metadata:
gatekeeper.sh/system: "yes"
name: gatekeeper-manager-role
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- '*'
resources:
@ -70,6 +77,18 @@ rules:
- patch
- update
- watch
- apiGroups:
- expansion.gatekeeper.sh
resources:
- '*'
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- externaldata.gatekeeper.sh
resources:

Просмотреть файл

@ -78,6 +78,8 @@ spec:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: manager
- name: OTEL_RESOURCE_ATTRIBUTES
value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE),k8s.container.name=$(CONTAINER_NAME)
image: {{.Pullspec}}
imagePullPolicy: Always
livenessProbe:

Просмотреть файл

@ -66,7 +66,7 @@ func TestDeployCreateOrUpdateCorrectKinds(t *testing.T) {
expectedKinds := map[string]int{
"ClusterRole": 1,
"ClusterRoleBinding": 1,
"CustomResourceDefinition": 10,
"CustomResourceDefinition": 13,
"Deployment": 2,
"Namespace": 1,
"Role": 1,

Просмотреть файл

@ -1,10 +1,10 @@
{
"files": {
"main.js": "/static/js/main.662aea13.js",
"main.js": "/static/js/main.cef1fecf.js",
"index.html": "/index.html",
"main.662aea13.js.map": "/static/js/main.662aea13.js.map"
"main.cef1fecf.js.map": "/static/js/main.cef1fecf.js.map"
},
"entrypoints": [
"static/js/main.662aea13.js"
"static/js/main.cef1fecf.js"
]
}

Просмотреть файл

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>ARO Portal</title><script defer="defer" src="/static/js/main.662aea13.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>ARO Portal</title><script defer="defer" src="/static/js/main.cef1fecf.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -4,5 +4,5 @@ package armnetwork
// Licensed under the Apache License 2.0.
//go:generate rm -rf ../../../../util/mocks/$GOPACKAGE
//go:generate go run ../../../../../vendor/github.com/golang/mock/mockgen -destination=../../../../util/mocks/azureclient/azuresdk/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/$GOPACKAGE InterfacesClient,LoadBalancersClient,LoadBalancerBackendAddressPoolsClient
//go:generate go run ../../../../../vendor/github.com/golang/mock/mockgen -destination=../../../../util/mocks/azureclient/azuresdk/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/$GOPACKAGE InterfacesClient,LoadBalancersClient,LoadBalancerBackendAddressPoolsClient,PublicIPAddressesClient
//go:generate go run ../../../../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../../../../util/mocks/azureclient/azuresdk/$GOPACKAGE/$GOPACKAGE.go

Просмотреть файл

@ -9,8 +9,6 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2"
"github.com/Azure/ARO-RP/pkg/util/azureclient"
)
// InterfacesClient is a minimal interface for azure InterfacesClient
@ -26,16 +24,10 @@ type interfacesClient struct {
var _ InterfacesClient = &interfacesClient{}
// NewInterfacesClient creates a new InterfacesClient
func NewInterfacesClient(environment *azureclient.AROEnvironment, subscriptionID string, credential azcore.TokenCredential) (InterfacesClient, error) {
options := arm.ClientOptions{
ClientOptions: azcore.ClientOptions{
Cloud: environment.Cloud,
},
}
clientFactory, err := armnetwork.NewClientFactory(subscriptionID, credential, &options)
func NewInterfacesClient(subscriptionID string, credential azcore.TokenCredential, options *arm.ClientOptions) (InterfacesClient, error) {
clientFactory, err := armnetwork.NewClientFactory(subscriptionID, credential, options)
if err != nil {
return nil, err
}
return &interfacesClient{InterfacesClient: clientFactory.NewInterfacesClient()}, nil
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше