diff --git a/cmd/initializer.go b/cmd/initializer.go index 33fb3e83..b93cc182 100644 --- a/cmd/initializer.go +++ b/cmd/initializer.go @@ -7,7 +7,6 @@ import ( helmv2 "github.com/fluxcd/helm-controller/api/v2" sourcev1 "github.com/fluxcd/source-controller/api/v1" - "github.com/kcp-dev/logicalcluster/v3" "github.com/kcp-dev/multicluster-provider/initializingworkspaces" pmcontext "github.com/platform-mesh/golang-commons/context" "github.com/spf13/cobra" @@ -37,10 +36,13 @@ var initializerCmd = &cobra.Command{ os.Exit(1) } + k8sCfg := ctrl.GetConfigOrDie() + mgrOpts := ctrl.Options{ Scheme: scheme, LeaderElection: defaultCfg.LeaderElection.Enabled, LeaderElectionID: "security-operator-initializer.platform-mesh.io", + LeaderElectionConfig: k8sCfg, HealthProbeBindAddress: defaultCfg.HealthProbeBindAddress, Metrics: server.Options{ BindAddress: defaultCfg.Metrics.BindAddress, @@ -80,14 +82,12 @@ var initializerCmd = &cobra.Command{ utilruntime.Must(sourcev1.AddToScheme(runtimeScheme)) utilruntime.Must(helmv2.AddToScheme(runtimeScheme)) - orgClient, err := logicalClusterClientFromKey(mgr.GetLocalManager(), log)(logicalcluster.Name("root:orgs")) + orgClient, err := logicalClusterClientFromKey(mgr.GetLocalManager(), log)("root:orgs") if err != nil { setupLog.Error(err, "Failed to create org client") os.Exit(1) } - k8sCfg := ctrl.GetConfigOrDie() - runtimeClient, err := client.New(k8sCfg, client.Options{Scheme: scheme}) if err != nil { log.Error().Err(err).Msg("Failed to create in cluster client") diff --git a/cmd/model_generator.go b/cmd/model_generator.go index 657ec870..bb269fc0 100644 --- a/cmd/model_generator.go +++ b/cmd/model_generator.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/kcp-dev/multicluster-provider/apiexport" + kcpv1alpha2 "github.com/kcp-dev/sdk/apis/apis/v1alpha2" platformeshcontext "github.com/platform-mesh/golang-commons/context" appsv1 "k8s.io/api/apps/v1" @@ -71,7 +72,8 @@ var modelGeneratorCmd = &cobra.Command{ } provider, err := apiexport.New(restCfg, apiexport.Options{ - Scheme: mgrOpts.Scheme, + Scheme: mgrOpts.Scheme, + ObjectToWatch: &kcpv1alpha2.APIBinding{}, }) if err != nil { log.Error().Err(err).Msg("Failed to create apiexport provider") diff --git a/cmd/operator.go b/cmd/operator.go index 7b8fe99c..ac90cf71 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -6,12 +6,13 @@ import ( "fmt" "net/url" - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1" kcpcorev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" + "github.com/kcp-dev/logicalcluster/v3" "github.com/kcp-dev/multicluster-provider/apiexport" + kcpapisv1alpha1 "github.com/kcp-dev/sdk/apis/apis/v1alpha1" + kcpapisv1alpha2 "github.com/kcp-dev/sdk/apis/apis/v1alpha2" + kcptenancyv1alpha1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1" openfgav1 "github.com/openfga/api/proto/openfga/v1" accountsv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1" "google.golang.org/grpc" @@ -34,8 +35,6 @@ import ( "github.com/platform-mesh/golang-commons/sentry" "github.com/spf13/cobra" - kcptenancyv1alphav1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1" - corev1alpha1 "github.com/platform-mesh/security-operator/api/v1alpha1" "github.com/platform-mesh/security-operator/internal/controller" // +kubebuilder:scaffold:imports @@ -126,7 +125,8 @@ var operatorCmd = &cobra.Command{ } provider, err := apiexport.New(restCfg, apiexport.Options{ - Scheme: mgrOpts.Scheme, + Scheme: mgrOpts.Scheme, + ObjectToWatch: &kcpapisv1alpha2.APIBinding{}, }) if err != nil { setupLog.Error(err, "unable to construct cluster provider") @@ -191,10 +191,12 @@ var operatorCmd = &cobra.Command{ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(kcptenancyv1alphav1.AddToScheme(scheme)) - utilruntime.Must(corev1alpha1.AddToScheme(scheme)) - utilruntime.Must(apisv1alpha1.AddToScheme(scheme)) + utilruntime.Must(kcpapisv1alpha1.AddToScheme(scheme)) + utilruntime.Must(kcpapisv1alpha2.AddToScheme(scheme)) + utilruntime.Must(kcptenancyv1alpha1.AddToScheme(scheme)) utilruntime.Must(kcpcorev1alpha1.AddToScheme(scheme)) + utilruntime.Must(accountsv1alpha1.AddToScheme(scheme)) + utilruntime.Must(corev1alpha1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } diff --git a/go.mod b/go.mod index 16c20c71..af7a6c86 100644 --- a/go.mod +++ b/go.mod @@ -2,21 +2,20 @@ module github.com/platform-mesh/security-operator go 1.25.0 -replace github.com/kcp-dev/multicluster-provider v0.2.0 => github.com/kcp-dev/multicluster-provider v0.0.0-20250827085327-2b5ca378b7b4 - require ( github.com/coreos/go-oidc v2.4.0+incompatible github.com/fluxcd/helm-controller/api v1.4.5 github.com/fluxcd/source-controller/api v1.7.4 github.com/go-logr/logr v1.4.3 - github.com/google/gnostic-models v0.7.1 - github.com/kcp-dev/kcp/sdk v0.28.1-0.20250926104223-cec2e15f24c6 + github.com/google/gnostic-models v0.7.0 + github.com/kcp-dev/kcp/sdk v0.28.3 github.com/kcp-dev/logicalcluster/v3 v3.0.5 - github.com/kcp-dev/multicluster-provider v0.2.0 + github.com/kcp-dev/multicluster-provider v0.2.1 + github.com/kcp-dev/sdk v0.29.0 github.com/openfga/api/proto v0.0.0-20251105142303-feed3db3d69d github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20251027165255-0f8f255e5f6c - github.com/platform-mesh/account-operator v0.5.31 - github.com/platform-mesh/golang-commons v0.8.2 + github.com/platform-mesh/account-operator v0.5.32 + github.com/platform-mesh/golang-commons v0.9.0 github.com/rs/zerolog v1.34.0 github.com/spf13/cobra v1.10.1 github.com/spf13/viper v1.21.0 @@ -30,7 +29,7 @@ require ( k8s.io/client-go v0.34.2 k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 sigs.k8s.io/controller-runtime v0.22.4 - sigs.k8s.io/multicluster-runtime v0.21.0-alpha.9 + sigs.k8s.io/multicluster-runtime v0.22.0-beta.0 sigs.k8s.io/yaml v1.6.0 ) @@ -68,7 +67,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20250728122101-adbf20db3e51 // indirect + github.com/kcp-dev/apimachinery/v2 v2.29.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 358ac0d2..f067989e 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= -github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= -github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -110,14 +110,16 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20250728122101-adbf20db3e51 h1:l38RDS+VUMx9etvyaCgJIZa4nM7FaNevNubWN0kDZY4= -github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20250728122101-adbf20db3e51/go.mod h1:rF1jfvUfPjFXs+HV/LN1BtPzAz1bfjJOwVa+hAVfroQ= -github.com/kcp-dev/kcp/sdk v0.28.1-0.20250926104223-cec2e15f24c6 h1:bOR4mdLD24VCJRrHxmtTh21AdbbzkBBKkEh0ngL+XTc= -github.com/kcp-dev/kcp/sdk v0.28.1-0.20250926104223-cec2e15f24c6/go.mod h1:aC2BPGPvy8QtkI2gQNH9NfW6xpfGIKZkR93gy9O02BE= +github.com/kcp-dev/apimachinery/v2 v2.29.0 h1:hoIomHs0v8N9+kvKYfjM/tVh5l27NH1zCDUV0kRLxn4= +github.com/kcp-dev/apimachinery/v2 v2.29.0/go.mod h1:KizREtsxF5malriCj+Cr87TghwHQIMZYXbVycNBbGHs= +github.com/kcp-dev/kcp/sdk v0.28.3 h1:TS2nJOVBjenBd3fz1+y3aNrqZWqmakalNAIcQM9SukQ= +github.com/kcp-dev/kcp/sdk v0.28.3/go.mod h1:8oZpWxkoMu2TDpx5DgdIGDigByKHKkeqVMA4GiWneoI= github.com/kcp-dev/logicalcluster/v3 v3.0.5 h1:JbYakokb+5Uinz09oTXomSUJVQsqfxEvU4RyHUYxHOU= github.com/kcp-dev/logicalcluster/v3 v3.0.5/go.mod h1:EWBUBxdr49fUB1cLMO4nOdBWmYifLbP1LfoL20KkXYY= -github.com/kcp-dev/multicluster-provider v0.0.0-20250827085327-2b5ca378b7b4 h1:GUihV22j2J/cGF5Svr/zGVvfqTJepIO+sOnYTn9o4Vc= -github.com/kcp-dev/multicluster-provider v0.0.0-20250827085327-2b5ca378b7b4/go.mod h1:E/NxN2SMtC7b6iXgFMlQYWA7lJIfDPqRkPdvpxOEQLA= +github.com/kcp-dev/multicluster-provider v0.2.1 h1:viYs6wks/yCGnLsrQq8zu/jVlCuyyJT2VRjpMAI/PH8= +github.com/kcp-dev/multicluster-provider v0.2.1/go.mod h1:dm7L8PEB2ovbJY+G9E0zalH0qQj01QwQrrNOssG5sbw= +github.com/kcp-dev/sdk v0.29.0 h1:zXJjtcKNduy8MntSdf2CoXSMVWybptPJwq0zKBkf0Iw= +github.com/kcp-dev/sdk v0.29.0/go.mod h1:iOA3cEMbI7jeLHbfc0GlHSXRHfyhOWC0NDEJRdNcBY8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= @@ -159,10 +161,10 @@ github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4 github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/platform-mesh/account-operator v0.5.31 h1:NWAs5nAS/afrIuZFDhu8A5O37Xkn5mFIGR+q2ZTYIko= -github.com/platform-mesh/account-operator v0.5.31/go.mod h1:LoJBFsEKJJqSFBf8k7MW1NGC/ZRhG8BrYevexpKqYUg= -github.com/platform-mesh/golang-commons v0.8.2 h1:FwXFusbVrRm7mx0vUg9Ya0x5mb7rKAJxi99mZcmz9lc= -github.com/platform-mesh/golang-commons v0.8.2/go.mod h1:yelLTXhu6JUUpMYLH+QyT1FwAp1SB2kRrfxtQ1sqiyg= +github.com/platform-mesh/account-operator v0.5.32 h1:ignUxAlRUFOqQtqpol2P/40h18qN5OUkN6E0dKEZjx8= +github.com/platform-mesh/account-operator v0.5.32/go.mod h1:Zk2wmY6pFx4MFh5RNpjYQD5d6wR77YZOBfuz2F2Dd6k= +github.com/platform-mesh/golang-commons v0.9.0 h1:vqqwYLq8U3Mm9vFTbgcp5fhE/79UbQY5H0yIZBVMYMc= +github.com/platform-mesh/golang-commons v0.9.0/go.mod h1:yelLTXhu6JUUpMYLH+QyT1FwAp1SB2kRrfxtQ1sqiyg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -342,8 +344,8 @@ sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327U sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/multicluster-runtime v0.21.0-alpha.9 h1:baonM4f081WWct3U7O4EfqrxcUGtmCrFDbsT1FQ8xlo= -sigs.k8s.io/multicluster-runtime v0.21.0-alpha.9/go.mod h1:CpBzLMLQKdm+UCchd2FiGPiDdCxM5dgCCPKuaQ6Fsv0= +sigs.k8s.io/multicluster-runtime v0.22.0-beta.0 h1:9NbjTISwohf5oLNWV96cWVISm/G4CzR8v5zOvnC/7nY= +sigs.k8s.io/multicluster-runtime v0.22.0-beta.0/go.mod h1:4e/q1PCYE75S76Fd4nrPY3cbnj1TXjnjYfJ5ysQyaMw= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= diff --git a/hack/update-kubeconfig.sh b/hack/update-kubeconfig.sh new file mode 100755 index 00000000..3209d323 --- /dev/null +++ b/hack/update-kubeconfig.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +SECRET_DIR="$PROJECT_ROOT/.secret" +KCP_KUBECONFIG="$PROJECT_ROOT/../helm-charts/.secret/kcp/admin.kubeconfig" +KCP_SERVER="https://kcp.api.portal.dev.local:8443/clusters/root:platform-mesh-system" + +OPERATOR_YAML="$SECRET_DIR/operator.yaml" +INITIALIZER_YAML="$SECRET_DIR/initializer.yaml" +RUNTIME_YAML="$SECRET_DIR/runtime.yaml" + +echo "Retrieving kind kubeconfig and saving as runtime.yaml..." + +if ! kind get clusters | grep -q "^platform-mesh$"; then + echo "Error: Kind cluster 'platform-mesh' not found" + echo "Available clusters:" + kind get clusters + exit 1 +fi + +kind export kubeconfig --name platform-mesh --kubeconfig="$RUNTIME_YAML" +echo "Saved kind kubeconfig to $RUNTIME_YAML" + +echo "" +echo "Retrieving credentials from KCP kubeconfig..." + +if [ ! -f "$KCP_KUBECONFIG" ]; then + echo "Error: KCP kubeconfig not found at $KCP_KUBECONFIG" + exit 1 +fi + +CA_DATA=$(yq eval '.clusters[] | select(.name == "workspace.kcp.io/current") | .cluster.certificate-authority-data' "$KCP_KUBECONFIG") +CLIENT_CERT_DATA=$(yq eval '.users[] | select(.name == "kcp-admin") | .user.client-certificate-data' "$KCP_KUBECONFIG") +CLIENT_KEY_DATA=$(yq eval '.users[] | select(.name == "kcp-admin") | .user.client-key-data' "$KCP_KUBECONFIG") + +if [ "$CA_DATA" == "null" ] || [ -z "$CA_DATA" ]; then + echo "Error: Failed to extract certificate-authority-data from kubeconfig" + exit 1 +fi + +if [ "$CLIENT_CERT_DATA" == "null" ] || [ -z "$CLIENT_CERT_DATA" ]; then + echo "Error: Failed to extract client-certificate-data from kubeconfig" + exit 1 +fi + +if [ "$CLIENT_KEY_DATA" == "null" ] || [ -z "$CLIENT_KEY_DATA" ]; then + echo "Error: Failed to extract client-key-data from kubeconfig" + exit 1 +fi + +echo "Updating certificate-authority-data and user info in $OPERATOR_YAML" +yq eval ".clusters[0].cluster.certificate-authority-data = \"$CA_DATA\"" -i "$OPERATOR_YAML" +yq eval ".users[0].user.client-certificate-data = \"$CLIENT_CERT_DATA\"" -i "$OPERATOR_YAML" +yq eval ".users[0].user.client-key-data = \"$CLIENT_KEY_DATA\"" -i "$OPERATOR_YAML" + +echo "Updating certificate-authority-data and user info in $INITIALIZER_YAML" +yq eval ".clusters[0].cluster.certificate-authority-data = \"$CA_DATA\"" -i "$INITIALIZER_YAML" +yq eval ".users[0].user.client-certificate-data = \"$CLIENT_CERT_DATA\"" -i "$INITIALIZER_YAML" +yq eval ".users[0].user.client-key-data = \"$CLIENT_KEY_DATA\"" -i "$INITIALIZER_YAML" +yq eval ".clusters[0].cluster.server = \"https://kcp.api.portal.dev.local:8443/services/initializingworkspaces/root:security\"" -i "$INITIALIZER_YAML" + +echo "" +echo "Retrieving KCP APIExport server URL..." + +export KUBECONFIG="$KCP_KUBECONFIG" +SERVER_URL=$(kubectl get apiexportendpointslices.apis.kcp.io core.platform-mesh.io -oyaml --server="$KCP_SERVER" | yq eval '.status.endpoints[0].url' -) +unset KUBECONFIG + +if [ "$SERVER_URL" == "null" ] || [ -z "$SERVER_URL" ]; then + echo "Error: Failed to extract server URL from APIExportEndpointSlice" + exit 1 +fi + +echo "Found KCP server URL: $SERVER_URL" +echo "Updating server URL in $OPERATOR_YAML" +yq eval ".clusters[0].cluster.server = \"$SERVER_URL\"" -i "$OPERATOR_YAML" + +echo "" +echo "Successfully updated kubeconfig data in operator.yaml and initializer.yaml" \ No newline at end of file diff --git a/internal/controller/apibinding_controller.go b/internal/controller/apibinding_controller.go index 3afd184f..41fdcf99 100644 --- a/internal/controller/apibinding_controller.go +++ b/internal/controller/apibinding_controller.go @@ -3,7 +3,7 @@ package controller import ( "context" - kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1" + kcpv1alpha2 "github.com/kcp-dev/sdk/apis/apis/v1alpha2" platformeshconfig "github.com/platform-mesh/golang-commons/config" "github.com/platform-mesh/golang-commons/controller/lifecycle/builder" lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" @@ -35,9 +35,9 @@ type APIBindingReconciler struct { func (r *APIBindingReconciler) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) { ctxWithCluster := mccontext.WithCluster(ctx, req.ClusterName) - return r.mclifecycle.Reconcile(ctxWithCluster, req, &kcpv1alpha1.APIBinding{}) + return r.mclifecycle.Reconcile(ctxWithCluster, req, &kcpv1alpha2.APIBinding{}) } func (r *APIBindingReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platformeshconfig.CommonServiceConfig, evp ...predicate.Predicate) error { - return r.mclifecycle.SetupWithManager(mgr, cfg.MaxConcurrentReconciles, "apibinding-controller", &kcpv1alpha1.APIBinding{}, cfg.DebugLabelValue, r, r.log, evp...) + return r.mclifecycle.SetupWithManager(mgr, cfg.MaxConcurrentReconciles, "apibinding-controller", &kcpv1alpha2.APIBinding{}, cfg.DebugLabelValue, r, r.log, evp...) } diff --git a/internal/controller/initializer_controller.go b/internal/controller/initializer_controller.go index 8aa3d5ae..96997a88 100644 --- a/internal/controller/initializer_controller.go +++ b/internal/controller/initializer_controller.go @@ -26,15 +26,15 @@ type LogicalClusterReconciler struct { mclifecycle *multicluster.LifecycleManager } -func NewLogicalClusterReconciler(log *logger.Logger, orgClient client.Client, cfg config.Config, inClusterClient client.Client, mgr mcmanager.Manager) *LogicalClusterReconciler { +func NewLogicalClusterReconciler(log *logger.Logger, orgClient client.Client, cfg config.Config, runtimeClient client.Client, mgr mcmanager.Manager) *LogicalClusterReconciler { return &LogicalClusterReconciler{ log: log, mclifecycle: builder.NewBuilder("logicalcluster", "LogicalClusterReconciler", []lifecyclesubroutine.Subroutine{ subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr), - subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, cfg), - subroutine.NewRealmSubroutine(inClusterClient, &cfg, cfg.BaseDomain), + subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, runtimeClient, cfg), + subroutine.NewRealmSubroutine(runtimeClient, &cfg, cfg.BaseDomain), subroutine.NewInviteSubroutine(orgClient, mgr), - subroutine.NewRemoveInitializer(mgr, cfg, inClusterClient), + subroutine.NewRemoveInitializer(mgr, cfg, runtimeClient), }, log). WithReadOnly(). BuildMultiCluster(mgr), diff --git a/internal/controller/store_controller.go b/internal/controller/store_controller.go index c2f55f7a..9c12d2fb 100644 --- a/internal/controller/store_controller.go +++ b/internal/controller/store_controller.go @@ -7,11 +7,9 @@ import ( "github.com/kcp-dev/logicalcluster/v3" "github.com/platform-mesh/golang-commons/controller/lifecycle/builder" - "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/discovery" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" - mcbuilder "sigs.k8s.io/multicluster-runtime/pkg/builder" mccontext "sigs.k8s.io/multicluster-runtime/pkg/context" mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager" mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile" @@ -21,12 +19,11 @@ import ( "github.com/platform-mesh/golang-commons/controller/lifecycle/multicluster" lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" "github.com/platform-mesh/golang-commons/logger" - corev1alpha1 "github.com/platform-mesh/security-operator/api/v1alpha1" - "github.com/platform-mesh/security-operator/internal/subroutine" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/multicluster-runtime/pkg/handler" + + corev1alpha1 "github.com/platform-mesh/security-operator/api/v1alpha1" + "github.com/platform-mesh/security-operator/internal/subroutine" ) // StoreReconciler reconciles a Store object @@ -88,26 +85,27 @@ func (r *StoreReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platforme if err != nil { return err } - return builder. - Watches( - &corev1alpha1.AuthorizationModel{}, - handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []mcreconcile.Request { - model, ok := obj.(*corev1alpha1.AuthorizationModel) - if !ok { - return nil - } - - return []mcreconcile.Request{ - { - Request: reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: model.Spec.StoreRef.Name, - }, - }, - ClusterName: model.Spec.StoreRef.Path, - }, - } - }), - mcbuilder.WithPredicates(predicate.GenerationChangedPredicate{}), - ).Complete(r) + return builder.Complete(r) + ///FIXME: this Enqueueing does not work as it seems right now we can only requeue in the current cluster. + //Watches( + // &corev1alpha1.AuthorizationModel{}, + // handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []mcreconcile.Request { + // model, ok := obj.(*corev1alpha1.AuthorizationModel) + // if !ok { + // return nil + // } + // + // return []mcreconcile.Request{ + // { + // Request: reconcile.Request{ + // NamespacedName: types.NamespacedName{ + // Name: model.Spec.StoreRef.Name, + // }, + // }, + // ClusterName: model.Spec.StoreRef.Path, + // }, + // } + // }), + // mcbuilder.WithPredicates(predicate.GenerationChangedPredicate{}), + //) } diff --git a/internal/subroutine/authorization_model_generation.go b/internal/subroutine/authorization_model_generation.go index 4f872005..717aaf47 100644 --- a/internal/subroutine/authorization_model_generation.go +++ b/internal/subroutine/authorization_model_generation.go @@ -7,8 +7,9 @@ import ( "strings" "text/template" - kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1" "github.com/kcp-dev/logicalcluster/v3" + kcpv1alpha1 "github.com/kcp-dev/sdk/apis/apis/v1alpha1" + kcpv1alpha2 "github.com/kcp-dev/sdk/apis/apis/v1alpha2" accountv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1" lifecyclecontrollerruntime "github.com/platform-mesh/golang-commons/controller/lifecycle/runtimeobject" lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" @@ -84,14 +85,14 @@ type modelInput struct { func (a *AuthorizationModelGenerationSubroutine) Finalize(ctx context.Context, instance lifecyclecontrollerruntime.RuntimeObject) (ctrl.Result, errors.OperatorError) { log := logger.LoadLoggerFromContext(ctx) - bindingToDelete := instance.(*kcpv1alpha1.APIBinding) + bindingToDelete := instance.(*kcpv1alpha2.APIBinding) cluster, err := a.mgr.ClusterFromContext(ctx) if err != nil { return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("unable to get cluster from context: %w", err), true, false) } - var bindings kcpv1alpha1.APIBindingList + var bindings kcpv1alpha2.APIBindingList err = cluster.GetClient().List(ctx, &bindings) if err != nil { return ctrl.Result{}, errors.NewOperatorError(err, true, true) @@ -169,7 +170,7 @@ func (a *AuthorizationModelGenerationSubroutine) GetName() string { // Process implements lifecycle.Subroutine. func (a *AuthorizationModelGenerationSubroutine) Process(ctx context.Context, instance lifecyclecontrollerruntime.RuntimeObject) (ctrl.Result, errors.OperatorError) { - binding := instance.(*kcpv1alpha1.APIBinding) + binding := instance.(*kcpv1alpha2.APIBinding) cluster, err := a.mgr.ClusterFromContext(ctx) if err != nil { @@ -196,15 +197,15 @@ func (a *AuthorizationModelGenerationSubroutine) Process(ctx context.Context, in return ctrl.Result{}, errors.NewOperatorError(err, true, true) } - var apiExport kcpv1alpha1.APIExport + var apiExport kcpv1alpha2.APIExport err = apiExportCluster.GetClient().Get(ctx, types.NamespacedName{Name: binding.Spec.Reference.Export.Name}, &apiExport) if err != nil { return ctrl.Result{}, errors.NewOperatorError(err, true, true) } - for _, latestResourceSchema := range apiExport.Spec.LatestResourceSchemas { + for _, latestResourceSchema := range apiExport.Spec.Resources { var resourceSchema kcpv1alpha1.APIResourceSchema - err := apiExportCluster.GetClient().Get(ctx, types.NamespacedName{Name: latestResourceSchema}, &resourceSchema) + err := apiExportCluster.GetClient().Get(ctx, types.NamespacedName{Name: latestResourceSchema.Schema}, &resourceSchema) if err != nil { return ctrl.Result{}, errors.NewOperatorError(err, true, true) } diff --git a/internal/subroutine/authorization_model_generation_test.go b/internal/subroutine/authorization_model_generation_test.go index 6849b579..0f3b1ea9 100644 --- a/internal/subroutine/authorization_model_generation_test.go +++ b/internal/subroutine/authorization_model_generation_test.go @@ -4,18 +4,20 @@ import ( "context" "testing" - kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1" - "github.com/platform-mesh/security-operator/internal/subroutine" - "github.com/platform-mesh/security-operator/internal/subroutine/mocks" + kcpv1alpha1 "github.com/kcp-dev/sdk/apis/apis/v1alpha1" + kcpv1alpha2 "github.com/kcp-dev/sdk/apis/apis/v1alpha2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/platform-mesh/security-operator/internal/subroutine" + "github.com/platform-mesh/security-operator/internal/subroutine/mocks" + accountv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) // Additional helpers for mocking @@ -31,22 +33,22 @@ func mockAccountInfo(cl *mocks.MockClient, orgName, originCluster string) { func TestAuthorizationModelGeneration_Process(t *testing.T) { tests := []struct { name string - binding *kcpv1alpha1.APIBinding + binding *kcpv1alpha2.APIBinding mockSetup func(*mocks.MockClient) expectError bool }{ { name: "error on lcClientFunc for binding workspace client", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}, + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}, }, mockSetup: func(kcpClient *mocks.MockClient) {}, expectError: true, }, { name: "early return when accountInfo not found", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}, + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}, }, mockSetup: func(kcpClient *mocks.MockClient) { // First lcClientFunc returns kcpClient; Get account returns NotFound @@ -57,8 +59,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "error on getting apiExport", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}, + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}, }, mockSetup: func(kcpClient *mocks.MockClient) { // account info exists @@ -70,8 +72,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "error from CreateOrUpdate when creating model", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}, + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}, }, mockSetup: func(kcpClient *mocks.MockClient) { kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { @@ -81,8 +83,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { return nil }).Once() kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { - if ae, ok := o.(*kcpv1alpha1.APIExport); ok { - ae.Spec.LatestResourceSchemas = []string{"schema1"} + if ae, ok := o.(*kcpv1alpha2.APIExport); ok { + ae.Spec.Resources = []kcpv1alpha2.ResourceSchema{{Schema: "schema1"}} return nil } return nil @@ -105,10 +107,10 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "skip core exports in Process", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "core.platform-mesh.io", Path: "root", }, @@ -121,10 +123,10 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "generate model in Process", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, @@ -134,8 +136,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { mockSetup: func(kcpClient *mocks.MockClient) { mockAccountInfo(kcpClient, "org", "origin") kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { - apiExport := o.(*kcpv1alpha1.APIExport) - apiExport.Spec.LatestResourceSchemas = []string{"schema1"} + apiExport := o.(*kcpv1alpha2.APIExport) + apiExport.Spec.Resources = []kcpv1alpha2.ResourceSchema{{Schema: "schema1"}} return nil }).Once() kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { @@ -152,10 +154,10 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "generate model in Process with namespaced scope", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, @@ -165,8 +167,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { mockSetup: func(kcpClient *mocks.MockClient) { mockAccountInfo(kcpClient, "org", "origin") kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { - apiExport := o.(*kcpv1alpha1.APIExport) - apiExport.Spec.LatestResourceSchemas = []string{"schema1"} + apiExport := o.(*kcpv1alpha2.APIExport) + apiExport.Spec.Resources = []kcpv1alpha2.ResourceSchema{{Schema: "schema1"}} return nil }).Once() kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { @@ -184,10 +186,10 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "error on apiExportClient.Get in Process", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, @@ -202,10 +204,10 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "error on apiExportClient.Get resource schema in Process", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, @@ -216,8 +218,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { mockAccountInfo(kcpClient, "org", "origin") // First Get returns APIExport with one resource schema kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { - apiExport := o.(*kcpv1alpha1.APIExport) - apiExport.Spec.LatestResourceSchemas = []string{"schema1"} + apiExport := o.(*kcpv1alpha2.APIExport) + apiExport.Spec.Resources = []kcpv1alpha2.ResourceSchema{{Schema: "schema1"}} return nil }).Once() // Second Get returns error for resource schema @@ -227,10 +229,10 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { }, { name: "generate model in Process with longestRelationName > 50", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, @@ -240,8 +242,8 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { mockSetup: func(kcpClient *mocks.MockClient) { mockAccountInfo(kcpClient, "org", "origin") kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { - apiExport := o.(*kcpv1alpha1.APIExport) - apiExport.Spec.LatestResourceSchemas = []string{"schema1"} + apiExport := o.(*kcpv1alpha2.APIExport) + apiExport.Spec.Resources = []kcpv1alpha2.ResourceSchema{{Schema: "schema1"}} return nil }).Once() kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { @@ -288,20 +290,20 @@ func TestAuthorizationModelGeneration_Process(t *testing.T) { func TestAuthorizationModelGeneration_Finalize(t *testing.T) { tests := []struct { name string - binding *kcpv1alpha1.APIBinding - mockSetup func(*mocks.MockClient, *kcpv1alpha1.APIBinding) + binding *kcpv1alpha2.APIBinding + mockSetup func(*mocks.MockClient, *kcpv1alpha2.APIBinding) expectError bool }{ { name: "bindings with non-matching export are skipped", - binding: &kcpv1alpha1.APIBinding{Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}}, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + binding: &kcpv1alpha2.APIBinding{Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}}, + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) + list := ol.(*kcpv1alpha2.APIBindingList) other := binding.DeepCopy() other.Spec.Reference.Export.Name = "other" other.Spec.Reference.Export.Path = "other" - list.Items = []kcpv1alpha1.APIBinding{*binding, *other} + list.Items = []kcpv1alpha2.APIBinding{*binding, *other} return nil }) kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, nn types.NamespacedName, o client.Object, opts ...client.GetOption) error { @@ -316,11 +318,11 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "error on lcClientFunc for binding in Finalize", - binding: &kcpv1alpha1.APIBinding{Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}}, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + binding: &kcpv1alpha2.APIBinding{Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}}, + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding} return nil }) kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).Return(nil) // toDeleteAccountInfo @@ -329,11 +331,11 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "early return when accountInfo missing in Finalize", - binding: &kcpv1alpha1.APIBinding{Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}}, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + binding: &kcpv1alpha2.APIBinding{Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}}, + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding} return nil }) // First Get: toDeleteAccountInfo OK; Second Get: binding workspace account info NotFound -> early return @@ -354,11 +356,11 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "delete returns error in Finalize", - binding: &kcpv1alpha1.APIBinding{Spec: kcpv1alpha1.APIBindingSpec{Reference: kcpv1alpha1.BindingReference{Export: &kcpv1alpha1.ExportBindingReference{Name: "foo", Path: "bar"}}}}, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + binding: &kcpv1alpha2.APIBinding{Spec: kcpv1alpha2.APIBindingSpec{Reference: kcpv1alpha2.BindingReference{Export: &kcpv1alpha2.ExportBindingReference{Name: "foo", Path: "bar"}}}}, + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{} return nil }) kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).Return(nil) @@ -368,20 +370,20 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "skip Finalize if other bindings exist", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, }, }, }, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding, *binding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding, *binding} return nil }) // Add this mock to avoid missing lcClientFunc call @@ -390,20 +392,20 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "delete model in Finalize if last binding", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, }, }, }, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding} return nil }) kcpClient.EXPECT().Get(mock.Anything, mock.Anything, mock.Anything).Return(nil) @@ -412,21 +414,21 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "delete model in Finalize but model is not found", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, }, }, }, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { // List returns a single binding kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding} return nil }) // Get returns account info @@ -443,38 +445,38 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "error on List in Finalize", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, }, }, }, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { kcpClient.EXPECT().List(mock.Anything, mock.Anything).Return(assert.AnError) }, expectError: true, }, { name: "error on getRelatedAuthorizationModels in Finalize", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, }, }, }, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { // List returns a single binding, so Finalize will call Get next kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding} return nil }) // Simulate error in getRelatedAuthorizationModels @@ -484,22 +486,22 @@ func TestAuthorizationModelGeneration_Finalize(t *testing.T) { }, { name: "only bindings for same org are counted; delete called if only one, not called if none", - binding: &kcpv1alpha1.APIBinding{ - Spec: kcpv1alpha1.APIBindingSpec{ - Reference: kcpv1alpha1.BindingReference{ - Export: &kcpv1alpha1.ExportBindingReference{ + binding: &kcpv1alpha2.APIBinding{ + Spec: kcpv1alpha2.APIBindingSpec{ + Reference: kcpv1alpha2.BindingReference{ + Export: &kcpv1alpha2.ExportBindingReference{ Name: "foo", Path: "bar", }, }, }, }, - mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha1.APIBinding) { + mockSetup: func(kcpClient *mocks.MockClient, binding *kcpv1alpha2.APIBinding) { otherBinding := *binding.DeepCopy() // List returns two bindings: one for same org, one for different org kcpClient.EXPECT().List(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ol client.ObjectList, lo ...client.ListOption) error { - list := ol.(*kcpv1alpha1.APIBindingList) - list.Items = []kcpv1alpha1.APIBinding{*binding, otherBinding} + list := ol.(*kcpv1alpha2.APIBindingList) + list.Items = []kcpv1alpha2.APIBinding{*binding, otherBinding} return nil }) // toDeleteAccountInfo (for bindingToDelete) - org1 diff --git a/internal/subroutine/remove_initializer.go b/internal/subroutine/remove_initializer.go index 1810a193..bbb7e785 100644 --- a/internal/subroutine/remove_initializer.go +++ b/internal/subroutine/remove_initializer.go @@ -6,12 +6,10 @@ import ( "slices" "time" - "github.com/kcp-dev/kcp/sdk/apis/cache/initialization" kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" "github.com/platform-mesh/golang-commons/controller/lifecycle/runtimeobject" "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" "github.com/platform-mesh/golang-commons/errors" - "github.com/platform-mesh/security-operator/internal/config" "github.com/rs/zerolog/log" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -19,6 +17,8 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager" + + "github.com/platform-mesh/security-operator/internal/config" ) const ( @@ -83,7 +83,7 @@ func (r *removeInitializer) Process(ctx context.Context, instance runtimeobject. patch := client.MergeFrom(lc.DeepCopy()) - lc.Status.Initializers = initialization.EnsureInitializerAbsent(initializer, lc.Status.Initializers) + lc.Status.Initializers = EnsureInitializerAbsent(initializer, lc.Status.Initializers) if err := cluster.GetClient().Status().Patch(ctx, lc, patch); err != nil { return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("unable to patch out initializers: %w", err), true, true) } @@ -93,6 +93,20 @@ func (r *removeInitializer) Process(ctx context.Context, instance runtimeobject. return ctrl.Result{}, nil } +func EnsureInitializerAbsent(initializer kcpv1alpha1.LogicalClusterInitializer, initializers []kcpv1alpha1.LogicalClusterInitializer) []kcpv1alpha1.LogicalClusterInitializer { + removeAt := -1 + for i := range initializers { + if initializers[i] == initializer { + removeAt = i + break + } + } + if removeAt != -1 { + initializers = append(initializers[:removeAt], initializers[removeAt+1:]...) + } + return initializers +} + func NewRemoveInitializer(mgr mcmanager.Manager, cfg config.Config, runtimeClient client.Client) *removeInitializer { return &removeInitializer{ initializerName: cfg.InitializerName, diff --git a/internal/subroutine/worksapce_authorization.go b/internal/subroutine/workspace_authorization.go similarity index 97% rename from internal/subroutine/worksapce_authorization.go rename to internal/subroutine/workspace_authorization.go index 8194da7b..0f0b0fab 100644 --- a/internal/subroutine/worksapce_authorization.go +++ b/internal/subroutine/workspace_authorization.go @@ -5,11 +5,10 @@ import ( "fmt" kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" - kcptenancyv1alphav1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1" + kcptenancyv1alphav1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1" "github.com/platform-mesh/golang-commons/controller/lifecycle/runtimeobject" lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" "github.com/platform-mesh/golang-commons/errors" - "github.com/platform-mesh/security-operator/internal/config" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" @@ -17,6 +16,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/platform-mesh/security-operator/internal/config" ) type workspaceAuthSubroutine struct { diff --git a/internal/subroutine/workspace_authorization_test.go b/internal/subroutine/workspace_authorization_test.go index b32a6640..06160073 100644 --- a/internal/subroutine/workspace_authorization_test.go +++ b/internal/subroutine/workspace_authorization_test.go @@ -6,7 +6,7 @@ import ( "testing" kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" - kcptenancyv1alphav1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1" + kcptenancyv1alphav1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1" "github.com/platform-mesh/security-operator/internal/config" "github.com/platform-mesh/security-operator/internal/subroutine/mocks" "github.com/stretchr/testify/assert" diff --git a/internal/subroutine/workspace_initializer.go b/internal/subroutine/workspace_initializer.go index 7ae591bb..83a7ee21 100644 --- a/internal/subroutine/workspace_initializer.go +++ b/internal/subroutine/workspace_initializer.go @@ -7,6 +7,7 @@ import ( "strings" kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" + accountsv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1" "github.com/platform-mesh/golang-commons/controller/lifecycle/runtimeobject" lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine"