diff --git a/agent/pkg/controllers/cert_controller.go b/agent/pkg/controllers/cert_controller.go index ed4577c06..c8cfcc6b5 100644 --- a/agent/pkg/controllers/cert_controller.go +++ b/agent/pkg/controllers/cert_controller.go @@ -38,7 +38,7 @@ func (c *certController) Reconcile(ctx context.Context, request ctrl.Request) (c } func AddCertController(mgr ctrl.Manager, kubeClient kubernetes.Interface) error { - return ctrl.NewControllerManagedBy(mgr). + return ctrl.NewControllerManagedBy(mgr).Named("cert-controller"). For(&corev1.Secret{}, builder.WithPredicates(predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { return false diff --git a/agent/pkg/controllers/hub_clusterclaim_controller.go b/agent/pkg/controllers/hub_clusterclaim_controller.go index 4b901b20a..7d6e74873 100644 --- a/agent/pkg/controllers/hub_clusterclaim_controller.go +++ b/agent/pkg/controllers/hub_clusterclaim_controller.go @@ -47,7 +47,7 @@ func AddHubClusterClaimController(mgr ctrl.Manager) error { clusterClaim, _ := getClusterClaim(context.Background(), mgr.GetClient(), constants.HubClusterClaimName) return clusterClaim == nil }) - return ctrl.NewControllerManagedBy(mgr). + return ctrl.NewControllerManagedBy(mgr).Named("hubclusterclaim-controller"). For(&clustersv1alpha1.ClusterClaim{}, builder.WithPredicates(clusterClaimPredicate)). Complete(&hubClusterClaimController{ client: mgr.GetClient(), diff --git a/agent/pkg/controllers/version_clusterclaim_controller.go b/agent/pkg/controllers/version_clusterclaim_controller.go index 0e59704a9..93704cd8a 100644 --- a/agent/pkg/controllers/version_clusterclaim_controller.go +++ b/agent/pkg/controllers/version_clusterclaim_controller.go @@ -51,7 +51,7 @@ func AddVersionClusterClaimController(mgr ctrl.Manager) error { constants.GlobalHubOwnerLabelKey: constants.GHAgentOwnerLabelValue, }, }) - return ctrl.NewControllerManagedBy(mgr). + return ctrl.NewControllerManagedBy(mgr).Named("clusterclaim-controller"). For(&clustersv1alpha1.ClusterClaim{}, builder.WithPredicates(clusterClaimPredicate)). Watches(&mchv1.MultiClusterHub{}, &handler.EnqueueRequestForObject{}). Complete(&versionClusterClaimController{ diff --git a/doc/reserved_names/README.md b/doc/reserved_names/README.md index 6400e0ea3..47dad934c 100644 --- a/doc/reserved_names/README.md +++ b/doc/reserved_names/README.md @@ -19,7 +19,7 @@ List all annotations are used by multicluster global hub. | global-hub.open-cluster-management.io/managed-by= | This annotation is used to identify which managed cluster is managed by which managed hub cluster. | | global-hub.open-cluster-management.io/origin-ownerreference-uid= | This annotation is used to identify that the resource is from the global hub cluster. The global hub agent is only handled with the resource which has this annotation. | | mgh-image-repository= | This annotation is used on the MCGH/MGH custom resource to identify a custom image repository. | - +|import-cluster-in-hosted=true\|false | This annotation is used to identify if managedhub cluster should be imported in hosted mode | # Finalizer diff --git a/go.mod b/go.mod index 114c4faab..bedb7f17d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.4 require ( github.com/RedHatInsights/strimzi-client-go v0.34.2 github.com/Shopify/sarama v1.38.1 - github.com/cenkalti/backoff/v4 v4.2.1 + github.com/cenkalti/backoff/v4 v4.3.0 github.com/cloudevents/sdk-go/protocol/kafka_confluent/v2 v2.0.0-20240413090539-7fef29478991 github.com/cloudevents/sdk-go/v2 v2.15.3-0.20240422145248-9a61fcad9967 github.com/cloudflare/cfssl v1.6.5 @@ -16,14 +16,14 @@ require ( github.com/fergusstrange/embedded-postgres v1.17.0 github.com/gin-gonic/gin v1.9.1 github.com/go-co-op/gocron v1.23.0 - github.com/go-logr/logr v1.4.1 + github.com/go-logr/logr v1.4.2 github.com/gonvenience/ytbx v1.4.4 github.com/google/uuid v1.6.0 github.com/homeport/dyff v1.5.5 github.com/jackc/pgx/v4 v4.18.2 github.com/lib/pq v1.10.9 - github.com/onsi/ginkgo/v2 v2.17.1 - github.com/onsi/gomega v1.32.0 + github.com/onsi/ginkgo/v2 v2.19.0 + github.com/onsi/gomega v1.33.1 github.com/openshift/api v0.0.0-20240527133614-ba11c1587003 github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 github.com/openshift/library-go v0.0.0-20240723172506-8bb8fe6cc56d @@ -41,34 +41,37 @@ require ( gorm.io/datatypes v1.2.0 gorm.io/driver/postgres v1.5.2 gorm.io/gorm v1.25.4 - k8s.io/api v0.30.1 - k8s.io/apiextensions-apiserver v0.30.1 - k8s.io/apimachinery v0.30.1 - k8s.io/client-go v0.30.1 + k8s.io/api v0.31.0 + k8s.io/apiextensions-apiserver v0.31.0 + k8s.io/apimachinery v0.31.0 + k8s.io/client-go v0.31.0 k8s.io/klog v1.0.0 - k8s.io/kube-aggregator v0.30.1 - k8s.io/utils v0.0.0-20240102154912-e7106e64919e + k8s.io/kube-aggregator v0.31.0 + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 open-cluster-management.io/addon-framework v0.9.0 open-cluster-management.io/api v0.13.0 open-cluster-management.io/governance-policy-propagator v0.11.1-0.20230815182526-b4ee1b24b1d0 open-cluster-management.io/multicloud-operators-channel v0.11.0 open-cluster-management.io/multicloud-operators-subscription v0.11.0 sigs.k8s.io/application v0.8.3 - sigs.k8s.io/controller-runtime v0.18.4 - sigs.k8s.io/kustomize/api v0.16.0 - sigs.k8s.io/kustomize/kyaml v0.16.0 + sigs.k8s.io/controller-runtime v0.19.0 + sigs.k8s.io/kustomize/api v0.17.2 + sigs.k8s.io/kustomize/kyaml v0.17.2 sigs.k8s.io/yaml v1.4.0 ) require ( + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/certificate-transparency-go v1.1.7 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/weppos/publicsuffix-go v0.30.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 // indirect github.com/zmap/zlint/v3 v3.5.0 // indirect - gopkg.in/evanphx/json-patch.v5 v5.6.0 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect helm.sh/helm/v3 v3.14.2 // indirect ) @@ -81,11 +84,11 @@ require ( github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bytedance/sonic v1.9.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cloudevents/sdk-go/protocol/kafka_sarama/v2 v2.13.0 github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/eapache/go-resiliency v1.3.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect github.com/eapache/queue v1.1.0 // indirect @@ -99,12 +102,11 @@ require ( github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -119,7 +121,7 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 // indirect + github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/h2non/filetype v1.1.1 // indirect github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect @@ -166,11 +168,11 @@ require ( github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sergi/go-diff v1.3.1 // indirect @@ -192,7 +194,7 @@ require ( golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.22.0 // indirect @@ -200,16 +202,15 @@ require ( golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.62.1 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.4.7 // indirect - k8s.io/apiserver v0.30.1 // indirect - k8s.io/component-base v0.30.1 // indirect - k8s.io/klog/v2 v2.120.1 + k8s.io/apiserver v0.31.0 // indirect + k8s.io/component-base v0.31.0 // indirect + k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect open-cluster-management.io/sdk-go v0.13.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect diff --git a/go.sum b/go.sum index 4c09daca4..1909edce0 100644 --- a/go.sum +++ b/go.sum @@ -164,13 +164,13 @@ github.com/bugsnag/panicwrap v1.3.4/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywR github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= @@ -259,8 +259,9 @@ github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0 github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= @@ -364,6 +365,8 @@ github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7R github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= @@ -406,8 +409,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -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 v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= @@ -460,8 +463,9 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/ github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= @@ -481,8 +485,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= @@ -541,8 +545,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -578,7 +580,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -595,8 +596,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 h1:2XF1Vzq06X+inNqgJ9tRnGuw+ZVCB3FazXODD6JE1R8= -github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -641,8 +642,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/grpc-ecosystem/grpc-health-probe v0.3.2/go.mod h1:izVOQ4RWbjUR6lm4nn+VLJyQ+FyaiGmprEYgI04Gs7U= github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= @@ -927,8 +928,8 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g= github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -981,8 +982,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -992,8 +993,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1046,8 +1047,9 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= @@ -1061,15 +1063,15 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1077,8 +1079,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1089,8 +1091,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc h1:zAsgcP8MhzAbhMnB1QQ2O7ZhWYVGYSR2iVcjzQuPV+o= github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc/go.mod h1:S8xSOnV3CgpNrWd0GQ/OoQfMtlg2uPRSuTzcSGrzwK8= @@ -1105,8 +1107,8 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -1163,8 +1165,8 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -1246,6 +1248,8 @@ github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8L github.com/weppos/publicsuffix-go v0.30.0 h1:QHPZ2GRu/YE7cvejH9iyavPOkVCB4dNxp2ZvtT+vQLY= github.com/weppos/publicsuffix-go v0.30.0/go.mod h1:kBi8zwYnR0zrbm8RcuN1o9Fzgpnnn+btVN8uWPMyXAY= github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220927085643-dc0d00c92642/go.mod h1:GHfoeIdZLdZmLjMlzBftbTDntahTttUMWjxZwQJhULE= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -1292,8 +1296,8 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= -go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -1308,14 +1312,14 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib v1.3.0 h1:p9Gd+3dD7yB+AIph2Ltg11QDX6Y+yWMH0YQVTpTTP2c= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 h1:gbhw/u49SS3gkPWiYweQNJGm/uJN5GkI/FrosxSHT7A= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1/go.mod h1:GnOaBaFQ2we3b9AGWJpsBa7v1S5RlQzlC3O7dRMxZhM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= @@ -1323,24 +1327,24 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:Nmn go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= go.opentelemetry.io/otel/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA= go.opentelemetry.io/otel/exporters/prometheus v0.42.0/go.mod h1:f3bYiqNqhoPxkvI2LrXqQVC546K7BuRDL/kKuxkujhA= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1516,8 +1520,8 @@ golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1639,7 +1643,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -1749,8 +1752,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1776,10 +1777,10 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240325203815-454cdb8f5daa h1:ePqxpG3LVx+feAUOx8YmR5T7rc0rdzK8DyxM8cQ9zq0= google.golang.org/genproto v0.0.0-20240325203815-454cdb8f5daa/go.mod h1:CnZenrTdRJb7jc+jOm0Rkywq+9wh0QC4U8tyiRbEPPM= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1793,8 +1794,8 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1806,10 +1807,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= @@ -1822,8 +1821,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/evanphx/json-patch.v5 v5.6.0 h1:BMT6KIwBD9CaU91PJCZIe46bDmBWa9ynTQgJIOpfQBk= -gopkg.in/evanphx/json-patch.v5 v5.6.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= @@ -1891,38 +1890,38 @@ k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY= -k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY= k8s.io/apiextensions-apiserver v0.17.0/go.mod h1:XiIFUakZywkUl54fVXa7QTEHcqQz9HG55nHd1DCoHj8= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= k8s.io/apiextensions-apiserver v0.20.6/go.mod h1:qO8YMqeMmZH+lV21LUNzV41vfpoE9QVAJRA+MNqj0mo= -k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= -k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U= -k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= -k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8= -k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo= +k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= +k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= k8s.io/cli-runtime v0.20.6/go.mod h1:JVERW478qcxWrUjJuWQSqyJeiz9QC4T6jmBznHFBC8w= k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= -k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q= -k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= @@ -1933,8 +1932,8 @@ k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1 k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= -k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ= -k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI= +k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= +k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= k8s.io/component-helpers v0.20.6/go.mod h1:d4rFhZS/wxrZCxRiJJiWf1mVGVeMB5/ey3Yv8/rOp78= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= @@ -1949,10 +1948,10 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-aggregator v0.30.1 h1:ymR2BsxDacTKwzKTuNhGZttuk009c+oZbSeD+IPX5q4= -k8s.io/kube-aggregator v0.30.1/go.mod h1:SFbqWsM6ea8dHd3mPLsZFzJHbjBOS5ykIgJh4znZ5iQ= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-aggregator v0.31.0 h1:3DqSpmqHF8rey7fY+qYXLJms0tYPhxrgWvjpnKVnS0Y= +k8s.io/kube-aggregator v0.31.0/go.mod h1:Fa+OVSpMQC7zbTTz7/QG7FXe9jZ8usuJQej5sMdCrkM= k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= @@ -1965,8 +1964,8 @@ k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= -k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -1997,8 +1996,8 @@ sigs.k8s.io/application v0.8.3 h1:5UETobiVhxTkKn3pIESImXiMNmSg3VkM5+JvmYGDPko= sigs.k8s.io/application v0.8.3/go.mod h1:Mv+ht9RE/QNtITYCzRbt3XTIN6t6so6cInmiyg6wOIg= sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= sigs.k8s.io/controller-runtime v0.8.0/go.mod h1:v9Lbj5oX443uR7GXYY46E0EE2o7k2YxQ58GxVNeXSW4= -sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= -sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= @@ -2006,10 +2005,10 @@ sigs.k8s.io/kind v0.11.1/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA= sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek= sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96/go.mod h1:EOBQyBowOUsd7U4CJnMHNE0ri+zCXyouGdLwC/jZU+I= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/kustomize/api v0.16.0 h1:/zAR4FOQDCkgSDmVzV2uiFbuy9bhu3jEzthrHCuvm1g= -sigs.k8s.io/kustomize/api v0.16.0/go.mod h1:MnFZ7IP2YqVyVwMWoRxPtgl/5hpA+eCCrQR/866cm5c= -sigs.k8s.io/kustomize/kyaml v0.16.0 h1:6J33uKSoATlKZH16unr2XOhDI+otoe2sR3M8PDzW3K0= -sigs.k8s.io/kustomize/kyaml v0.16.0/go.mod h1:xOK/7i+vmE14N2FdFyugIshB8eF6ALpy7jI87Q2nRh4= +sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g= +sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0= +sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0= +sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= diff --git a/manager/cmd/manager/main.go b/manager/cmd/manager/main.go index 78014eaac..578e1e7ed 100644 --- a/manager/cmd/manager/main.go +++ b/manager/cmd/manager/main.go @@ -339,7 +339,7 @@ func doMain(ctx context.Context, restConfig *rest.Config) int { hookServer := mgr.GetWebhookServer() setupLog.Info("registering webhooks to the webhook server") hookServer.Register("/mutating", &webhook.Admission{ - Handler: mgrwebhook.NewAdmissionHandler(mgr.GetClient(), mgr.GetScheme()), + Handler: mgrwebhook.NewAdmissionHandler(mgr.GetScheme()), }) } diff --git a/manager/pkg/webhook/admission_handler.go b/manager/pkg/webhook/admission_handler.go index afd45a9f8..fe0d7fd1c 100644 --- a/manager/pkg/webhook/admission_handler.go +++ b/manager/pkg/webhook/admission_handler.go @@ -9,35 +9,30 @@ import ( "net/http" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1" placementrulesv1 "open-cluster-management.io/multicloud-operators-subscription/pkg/apis/apps/placementrule/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "github.com/stolostron/multicluster-global-hub/pkg/constants" ) // NewAdmissionHandler is to handle the admission webhook for placementrule and placement -func NewAdmissionHandler(c client.Client, s *runtime.Scheme) admission.Handler { +func NewAdmissionHandler(s *runtime.Scheme) admission.Handler { return &admissionHandler{ - client: c, decoder: admission.NewDecoder(s), } } -var log = logf.Log.WithName("admission-handler") - type admissionHandler struct { - client client.Client decoder admission.Decoder } func (a *admissionHandler) Handle(ctx context.Context, req admission.Request) admission.Response { - log.V(2).Info("admission webhook is called", "name", req.Name, "namespace", - req.Namespace, "kind", req.Kind.Kind, "operation", req.Operation) - - if req.Kind.Kind == "Placement" { + klog.V(2).Infof("admission webhook is called, name:%v, namespace:%v, kind:%v, operation:%v", req.Name, + req.Namespace, req.Kind.Kind, req.Operation) + switch req.Kind.Kind { + case "Placement": placement := &clusterv1beta1.Placement{} err := a.decoder.Decode(req, placement) if err != nil { @@ -57,7 +52,8 @@ func (a *admissionHandler) Handle(ctx context.Context, req admission.Request) ad } return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPlacement) } - } else if req.Kind.Kind == "PlacementRule" { + return admission.Allowed("") + case "PlacementRule": placementrule := &placementrulesv1.PlacementRule{} err := a.decoder.Decode(req, placementrule) if err != nil { @@ -73,9 +69,10 @@ func (a *admissionHandler) Handle(ctx context.Context, req admission.Request) ad } return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPlacementRule) } + return admission.Allowed("") + default: + return admission.Allowed("") } - - return admission.Allowed("") } // AdmissionHandler implements admission.DecoderInjector. diff --git a/operator/Makefile b/operator/Makefile index f37439f2b..1d4273f31 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -183,7 +183,7 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest ## Tool Versions KUSTOMIZE_VERSION ?= v5.2.1 -CONTROLLER_TOOLS_VERSION ?= v0.13.0 +CONTROLLER_TOOLS_VERSION ?= v0.16.0 .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. diff --git a/operator/bundle/manifests/multicluster-global-hub-operator.clusterserviceversion.yaml b/operator/bundle/manifests/multicluster-global-hub-operator.clusterserviceversion.yaml index 0e5357d48..7ae0750db 100644 --- a/operator/bundle/manifests/multicluster-global-hub-operator.clusterserviceversion.yaml +++ b/operator/bundle/manifests/multicluster-global-hub-operator.clusterserviceversion.yaml @@ -23,7 +23,7 @@ metadata: categories: Integration & Delivery,OpenShift Optional certified: "false" containerImage: quay.io/stolostron/multicluster-global-hub-operator:latest - createdAt: "2024-08-08T01:35:13Z" + createdAt: "2024-08-19T10:24:47Z" description: Manages the installation and upgrade of the Multicluster Global Hub. olm.skipRange: '>=1.2.0 <1.3.0' operatorframework.io/initialization-resource: '{"apiVersion":"operator.open-cluster-management.io/v1alpha4", @@ -258,18 +258,6 @@ spec: - "" resources: - configmaps - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - events verbs: - create @@ -284,6 +272,9 @@ spec: - "" resources: - namespaces + - secrets + - serviceaccounts + - services verbs: - create - delete @@ -304,31 +295,9 @@ spec: - update - watch - apiGroups: - - "" - resources: - - secrets - verbs: - - create - - delete - - get - - list - - update - - watch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - delete - - get - - list - - update - - watch - - apiGroups: - - "" + - addon.open-cluster-management.io resources: - - services + - addondeploymentconfigs verbs: - create - delete @@ -336,14 +305,6 @@ spec: - list - update - watch - - apiGroups: - - addon.open-cluster-management.io - resources: - - addondeploymentconfigs - verbs: - - get - - list - - watch - apiGroups: - addon.open-cluster-management.io resources: @@ -353,12 +314,14 @@ spec: - delete - get - list + - patch - update - watch - apiGroups: - addon.open-cluster-management.io resources: - clustermanagementaddons/finalizers + - managedclusteraddons/finalizers verbs: - update - apiGroups: @@ -374,12 +337,6 @@ spec: - patch - update - watch - - apiGroups: - - addon.open-cluster-management.io - resources: - - managedclusteraddons/finalizers - verbs: - - update - apiGroups: - addon.open-cluster-management.io resources: @@ -420,16 +377,6 @@ spec: - apps resources: - deployments - verbs: - - create - - delete - - get - - list - - update - - watch - - apiGroups: - - apps - resources: - statefulsets verbs: - create @@ -442,23 +389,7 @@ spec: - apps.open-cluster-management.io resources: - channels - verbs: - - get - - list - - patch - - update - - apiGroups: - - apps.open-cluster-management.io - resources: - placementrules - verbs: - - get - - list - - patch - - update - - apiGroups: - - apps.open-cluster-management.io - resources: - subscriptions verbs: - get @@ -476,16 +407,6 @@ spec: - certificates.k8s.io resources: - certificatesigningrequests - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - certificates.k8s.io - resources: - certificatesigningrequests/approval verbs: - create @@ -531,6 +452,7 @@ spec: - cluster.open-cluster-management.io resources: - managedclustersets + - placements verbs: - get - list @@ -540,25 +462,10 @@ spec: - cluster.open-cluster-management.io resources: - managedclustersets/bind - verbs: - - create - - delete - - apiGroups: - - cluster.open-cluster-management.io - resources: - managedclustersets/join verbs: - create - delete - - apiGroups: - - cluster.open-cluster-management.io - resources: - - placements - verbs: - - get - - list - - patch - - update - apiGroups: - coordination.k8s.io resources: @@ -679,14 +586,6 @@ spec: - policy.open-cluster-management.io resources: - placementbindings - verbs: - - get - - list - - patch - - update - - apiGroups: - - policy.open-cluster-management.io - resources: - policies verbs: - get @@ -706,38 +605,8 @@ spec: - rbac.authorization.k8s.io resources: - clusterrolebindings - verbs: - - create - - delete - - get - - list - - update - - watch - - apiGroups: - - rbac.authorization.k8s.io - resources: - clusterroles - verbs: - - create - - delete - - get - - list - - update - - watch - - apiGroups: - - rbac.authorization.k8s.io - resources: - rolebindings - verbs: - - create - - delete - - get - - list - - update - - watch - - apiGroups: - - rbac.authorization.k8s.io - resources: - roles verbs: - create @@ -816,6 +685,10 @@ spec: initialDelaySeconds: 15 periodSeconds: 20 name: multicluster-global-hub-operator + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP readinessProbe: httpGet: path: /readyz @@ -830,10 +703,19 @@ spec: memory: 100Mi securityContext: allowPrivilegeEscalation: false + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: webhook-certs + readOnly: true securityContext: runAsNonRoot: true serviceAccountName: multicluster-global-hub-operator terminationGracePeriodSeconds: 10 + volumes: + - name: webhook-certs + secret: + defaultMode: 420 + secretName: multicluster-global-hub-webhook-certs permissions: - rules: - apiGroups: diff --git a/operator/bundle/manifests/multicluster-global-hub-webhook_v1_service.yaml b/operator/bundle/manifests/multicluster-global-hub-webhook_v1_service.yaml new file mode 100644 index 000000000..2bf8aa270 --- /dev/null +++ b/operator/bundle/manifests/multicluster-global-hub-webhook_v1_service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + service.beta.openshift.io/serving-cert-secret-name: multicluster-global-hub-webhook-certs + creationTimestamp: null + labels: + name: multicluster-global-hub-webhook + service: multicluster-global-hub-webhook + name: multicluster-global-hub-webhook +spec: + ports: + - name: webhook-server + port: 443 + protocol: TCP + targetPort: 9443 + selector: + name: multicluster-global-hub-operator +status: + loadBalancer: {} diff --git a/operator/bundle/manifests/operator.open-cluster-management.io_multiclusterglobalhubs.yaml b/operator/bundle/manifests/operator.open-cluster-management.io_multiclusterglobalhubs.yaml index d901b8f5e..bb8f97551 100644 --- a/operator/bundle/manifests/operator.open-cluster-management.io_multiclusterglobalhubs.yaml +++ b/operator/bundle/manifests/operator.open-cluster-management.io_multiclusterglobalhubs.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.16.0 creationTimestamp: null name: multiclusterglobalhubs.operator.open-cluster-management.io spec: @@ -24,14 +24,19 @@ spec: of the multiCluster global hub 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' + 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' + 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 @@ -60,8 +65,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -70,12 +76,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -92,8 +97,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -102,12 +108,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -124,8 +129,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -134,12 +140,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -157,8 +162,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -167,12 +173,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -189,8 +194,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -199,12 +205,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -221,8 +226,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -231,12 +237,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -276,15 +281,12 @@ spec: type: string statusTopic: default: gh-event.* - description: 'StatusTopic specifies the topic where an - agent reports events and status updates to a manager. - Specifically, the topic can end up with an asterisk - (*), indicating topics for individual managed hubs. - For example: the default value is "gh-event.*" for the - global hub built-in kafka. Therefore, the topic for - the hub cluster named "hub1" would be "gh-event.hub1"; - In the BYO case, the default value for all managed hubs - is "gh-event"' + description: |- + StatusTopic specifies the topic where an agent reports events and status updates to a manager. + Specifically, the topic can end up with an asterisk (*), indicating topics for individual managed hubs. + For example: the default value is "gh-event.*" for the global hub built-in kafka. Therefore, the topic + for the hub cluster named "hub1" would be "gh-event.hub1"; In the BYO case, the default value for all + managed hubs is "gh-event" type: string type: object type: object @@ -295,12 +297,12 @@ spec: properties: retention: default: 18m - description: Retention is a duration string, defining how - long to keep the data in the database. The recommended minimum - value is 1 month, and the default value is 18 months. A - duration string is a signed sequence of decimal numbers, - each with an optional fraction and a unit suffix, such as - "1y6m". Valid time units are "m" and "y" + description: |- + Retention is a duration string, defining how long to keep the data in the database. + The recommended minimum value is 1 month, and the default value is 18 months. + A duration string is a signed sequence of decimal numbers, + each with an optional fraction and a unit suffix, such as "1y6m". + Valid time units are "m" and "y" type: string storageSize: description: StorageSize specifies the size for storage @@ -312,9 +314,9 @@ spec: type: object enableMetrics: default: true - description: EnableMetrics enables the metrics for the global hub - created kafka and postgres components. If the user provides the - kafka and postgres, then the enablemetrics variable is useless. + description: |- + EnableMetrics enables the metrics for the global hub created kafka and postgres components. + If the user provides the kafka and postgres, then the enablemetrics variable is useless. type: boolean imagePullPolicy: description: ImagePullPolicy specifies the pull policy of the multicluster @@ -332,40 +334,39 @@ spec: tolerations: description: Tolerations causes all components to tolerate any taints items: - description: The pod this Toleration is attached to tolerates any - taint that matches the triple using the matching - operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: effect: - description: Effect indicates the taint effect to match. Empty - means match all taint effects. When specified, allowed values - are NoSchedule, PreferNoSchedule and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: Key is the taint key that the toleration applies - to. Empty means match all taint keys. If the key is empty, - operator must be Exists; this combination means to match all - values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship to the - value. Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod - can tolerate all taints of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: TolerationSeconds represents the period of time - the toleration (which must be of effect NoExecute, otherwise - this field is ignored) tolerates the taint. By default, it - is not set, which means tolerate the taint forever (do not - evict). Zero and negative values will be treated as 0 (evict - immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: Value is the taint value the toleration matches - to. If the operator is Exists, the value should be empty, - otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array @@ -380,43 +381,35 @@ spec: description: Conditions represents the latest available observations of the current state items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -431,10 +424,6 @@ spec: type: string type: description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/operator/config/crd/bases/operator.open-cluster-management.io_multiclusterglobalhubs.yaml b/operator/config/crd/bases/operator.open-cluster-management.io_multiclusterglobalhubs.yaml index ad4ac74b6..cf9665693 100644 --- a/operator/config/crd/bases/operator.open-cluster-management.io_multiclusterglobalhubs.yaml +++ b/operator/config/crd/bases/operator.open-cluster-management.io_multiclusterglobalhubs.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.16.0 name: multiclusterglobalhubs.operator.open-cluster-management.io spec: group: operator.open-cluster-management.io @@ -24,14 +24,19 @@ spec: of the multiCluster global hub 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' + 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' + 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 @@ -60,8 +65,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -70,12 +76,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -92,8 +97,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -102,12 +108,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -124,8 +129,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -134,12 +140,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -157,8 +162,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -167,12 +173,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -189,8 +194,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -199,12 +205,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -221,8 +226,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -231,12 +237,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of - compute resources required. If requests are omitted - for a container, it defaults to the specified limits. - If there are no specified limits, it defaults to an - implementation-defined value. For more information, - see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Requests describes the minimum amount of compute resources required. + If requests are omitted for a container, it defaults to the specified limits. + If there are no specified limits, it defaults to an implementation-defined value. + For more information, see: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object @@ -276,15 +281,12 @@ spec: type: string statusTopic: default: gh-event.* - description: 'StatusTopic specifies the topic where an - agent reports events and status updates to a manager. - Specifically, the topic can end up with an asterisk - (*), indicating topics for individual managed hubs. - For example: the default value is "gh-event.*" for the - global hub built-in kafka. Therefore, the topic for - the hub cluster named "hub1" would be "gh-event.hub1"; - In the BYO case, the default value for all managed hubs - is "gh-event"' + description: |- + StatusTopic specifies the topic where an agent reports events and status updates to a manager. + Specifically, the topic can end up with an asterisk (*), indicating topics for individual managed hubs. + For example: the default value is "gh-event.*" for the global hub built-in kafka. Therefore, the topic + for the hub cluster named "hub1" would be "gh-event.hub1"; In the BYO case, the default value for all + managed hubs is "gh-event" type: string type: object type: object @@ -295,12 +297,12 @@ spec: properties: retention: default: 18m - description: Retention is a duration string, defining how - long to keep the data in the database. The recommended minimum - value is 1 month, and the default value is 18 months. A - duration string is a signed sequence of decimal numbers, - each with an optional fraction and a unit suffix, such as - "1y6m". Valid time units are "m" and "y" + description: |- + Retention is a duration string, defining how long to keep the data in the database. + The recommended minimum value is 1 month, and the default value is 18 months. + A duration string is a signed sequence of decimal numbers, + each with an optional fraction and a unit suffix, such as "1y6m". + Valid time units are "m" and "y" type: string storageSize: description: StorageSize specifies the size for storage @@ -312,9 +314,9 @@ spec: type: object enableMetrics: default: true - description: EnableMetrics enables the metrics for the global hub - created kafka and postgres components. If the user provides the - kafka and postgres, then the enablemetrics variable is useless. + description: |- + EnableMetrics enables the metrics for the global hub created kafka and postgres components. + If the user provides the kafka and postgres, then the enablemetrics variable is useless. type: boolean imagePullPolicy: description: ImagePullPolicy specifies the pull policy of the multicluster @@ -332,40 +334,39 @@ spec: tolerations: description: Tolerations causes all components to tolerate any taints items: - description: The pod this Toleration is attached to tolerates any - taint that matches the triple using the matching - operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: effect: - description: Effect indicates the taint effect to match. Empty - means match all taint effects. When specified, allowed values - are NoSchedule, PreferNoSchedule and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: Key is the taint key that the toleration applies - to. Empty means match all taint keys. If the key is empty, - operator must be Exists; this combination means to match all - values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship to the - value. Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod - can tolerate all taints of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: TolerationSeconds represents the period of time - the toleration (which must be of effect NoExecute, otherwise - this field is ignored) tolerates the taint. By default, it - is not set, which means tolerate the taint forever (do not - evict). Zero and negative values will be treated as 0 (evict - immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: Value is the taint value the toleration matches - to. If the operator is Exists, the value should be empty, - otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array @@ -380,43 +381,35 @@ spec: description: Conditions represents the latest available observations of the current state items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -431,10 +424,6 @@ spec: type: string type: description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/operator/config/default/kustomization.yaml b/operator/config/default/kustomization.yaml index 6e340aa83..ecd09d505 100644 --- a/operator/config/default/kustomization.yaml +++ b/operator/config/default/kustomization.yaml @@ -18,7 +18,7 @@ resources: - ../manager # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml -#- ../webhook +- ../webhook # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. #- ../certmanager # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. diff --git a/operator/config/manager/kustomization.yaml b/operator/config/manager/kustomization.yaml index 03974a8f4..f4905ed85 100644 --- a/operator/config/manager/kustomization.yaml +++ b/operator/config/manager/kustomization.yaml @@ -15,3 +15,5 @@ images: - name: quay.io/stolostron/multicluster-global-hub-operator newName: quay.io/stolostron/multicluster-global-hub-operator newTag: latest +patches: +- path: manager_webhook_patch.yaml diff --git a/operator/config/manager/manager_webhook_patch.yaml b/operator/config/manager/manager_webhook_patch.yaml new file mode 100644 index 000000000..24b67a739 --- /dev/null +++ b/operator/config/manager/manager_webhook_patch.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: multicluster-global-hub-operator + namespace: multicluster-global-hub +spec: + template: + spec: + containers: + - name: multicluster-global-hub-operator + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: webhook-certs + readOnly: true + volumes: + - name: webhook-certs + secret: + defaultMode: 420 + secretName: multicluster-global-hub-webhook-certs diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml index aedfebf78..d4720ef8f 100644 --- a/operator/config/rbac/role.yaml +++ b/operator/config/rbac/role.yaml @@ -8,18 +8,6 @@ rules: - "" resources: - configmaps - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - events verbs: - create @@ -34,6 +22,9 @@ rules: - "" resources: - namespaces + - secrets + - serviceaccounts + - services verbs: - create - delete @@ -54,31 +45,9 @@ rules: - update - watch - apiGroups: - - "" - resources: - - secrets - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - "" + - addon.open-cluster-management.io resources: - - services + - addondeploymentconfigs verbs: - create - delete @@ -86,14 +55,6 @@ rules: - list - update - watch -- apiGroups: - - addon.open-cluster-management.io - resources: - - addondeploymentconfigs - verbs: - - get - - list - - watch - apiGroups: - addon.open-cluster-management.io resources: @@ -103,12 +64,14 @@ rules: - delete - get - list + - patch - update - watch - apiGroups: - addon.open-cluster-management.io resources: - clustermanagementaddons/finalizers + - managedclusteraddons/finalizers verbs: - update - apiGroups: @@ -124,12 +87,6 @@ rules: - patch - update - watch -- apiGroups: - - addon.open-cluster-management.io - resources: - - managedclusteraddons/finalizers - verbs: - - update - apiGroups: - addon.open-cluster-management.io resources: @@ -170,16 +127,6 @@ rules: - apps resources: - deployments - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - apps - resources: - statefulsets verbs: - create @@ -192,23 +139,7 @@ rules: - apps.open-cluster-management.io resources: - channels - verbs: - - get - - list - - patch - - update -- apiGroups: - - apps.open-cluster-management.io - resources: - placementrules - verbs: - - get - - list - - patch - - update -- apiGroups: - - apps.open-cluster-management.io - resources: - subscriptions verbs: - get @@ -226,16 +157,6 @@ rules: - certificates.k8s.io resources: - certificatesigningrequests - verbs: - - create - - get - - list - - patch - - update - - watch -- apiGroups: - - certificates.k8s.io - resources: - certificatesigningrequests/approval verbs: - create @@ -281,6 +202,7 @@ rules: - cluster.open-cluster-management.io resources: - managedclustersets + - placements verbs: - get - list @@ -290,25 +212,10 @@ rules: - cluster.open-cluster-management.io resources: - managedclustersets/bind - verbs: - - create - - delete -- apiGroups: - - cluster.open-cluster-management.io - resources: - managedclustersets/join verbs: - create - delete -- apiGroups: - - cluster.open-cluster-management.io - resources: - - placements - verbs: - - get - - list - - patch - - update - apiGroups: - coordination.k8s.io resources: @@ -429,14 +336,6 @@ rules: - policy.open-cluster-management.io resources: - placementbindings - verbs: - - get - - list - - patch - - update -- apiGroups: - - policy.open-cluster-management.io - resources: - policies verbs: - get @@ -456,38 +355,8 @@ rules: - rbac.authorization.k8s.io resources: - clusterrolebindings - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - clusterroles - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - rolebindings - verbs: - - create - - delete - - get - - list - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - roles verbs: - create diff --git a/operator/config/webhook/kustomization.yaml b/operator/config/webhook/kustomization.yaml new file mode 100644 index 000000000..2da258822 --- /dev/null +++ b/operator/config/webhook/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- service.yaml diff --git a/operator/config/webhook/service.yaml b/operator/config/webhook/service.yaml new file mode 100644 index 000000000..2be02351f --- /dev/null +++ b/operator/config/webhook/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: multicluster-global-hub-webhook + namespace: multicluster-global-hub + labels: + name: multicluster-global-hub-webhook + service: multicluster-global-hub-webhook + annotations: + service.beta.openshift.io/serving-cert-secret-name: multicluster-global-hub-webhook-certs +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + name: webhook-server + selector: + name: multicluster-global-hub-operator diff --git a/operator/main.go b/operator/main.go index 5ea3ebfef..35b7b1a68 100644 --- a/operator/main.go +++ b/operator/main.go @@ -18,6 +18,7 @@ package main import ( "context" + "crypto/tls" "flag" "os" "time" @@ -31,15 +32,22 @@ import ( "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/crd" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs" + globalhubwebhook "github.com/stolostron/multicluster-global-hub/operator/pkg/webhook" "github.com/stolostron/multicluster-global-hub/pkg/utils" ) var setupLog = ctrl.Log.WithName("setup") +const ( + webhookPort = 9443 + webhookCertDir = "/webhook-certs" +) + func main() { os.Exit(doMain(ctrl.SetupSignalHandler(), ctrl.GetConfigOrDie())) } @@ -98,6 +106,12 @@ func doMain(ctx context.Context, cfg *rest.Config) int { return 1 } + hookServer := mgr.GetWebhookServer() + setupLog.Info("registering webhooks to the webhook server") + hookServer.Register("/mutating", &webhook.Admission{ + Handler: globalhubwebhook.NewAdmissionHandler(mgr.GetClient(), mgr.GetScheme()), + }) + setupLog.Info("starting manager") if err := mgr.Start(ctx); err != nil { setupLog.Error(err, "problem running manager") @@ -152,6 +166,16 @@ func getManager(restConfig *rest.Config, operatorConfig *config.OperatorConfig) Metrics: metricsserver.Options{ BindAddress: operatorConfig.MetricsAddress, }, + WebhookServer: &webhook.DefaultServer{ + Options: webhook.Options{ + Port: webhookPort, + TLSOpts: []func(*tls.Config){ + func(config *tls.Config) { + config.MinVersion = tls.VersionTLS12 + }, + }, + }, + }, HealthProbeBindAddress: operatorConfig.ProbeAddress, LeaderElection: operatorConfig.LeaderElection, LeaderElectionID: "multicluster-global-hub-operator-lock", diff --git a/operator/pkg/config/multiclusterglobalhub_config.go b/operator/pkg/config/multiclusterglobalhub_config.go index 3847833b6..bab4adf94 100644 --- a/operator/pkg/config/multiclusterglobalhub_config.go +++ b/operator/pkg/config/multiclusterglobalhub_config.go @@ -82,6 +82,7 @@ var ( metricsScrapeInterval = "1m" imagePullSecretName = "" addonMgr addonmanager.AddonManager + importClusterInHosted = false ) func SetAddonManager(addonManager addonmanager.AddonManager) { @@ -188,6 +189,20 @@ func SetImageOverrides(mgh *v1alpha4.MulticlusterGlobalHub) error { return nil } +func SetImportClusterInHosted(mgh *v1alpha4.MulticlusterGlobalHub) { + importClusterInHostedValue := getAnnotation(mgh, operatorconstants.AnnotationImportClusterInHosted) + + if importClusterInHostedValue == "true" || importClusterInHostedValue == "True" { + importClusterInHosted = true + return + } + importClusterInHosted = false +} + +func GetImportClusterInHosted() bool { + return importClusterInHosted +} + func SetOauthProxyImage(image string) { imageOverrides[OauthProxyImageKey] = image } diff --git a/operator/pkg/constants/constants.go b/operator/pkg/constants/constants.go index a9810735c..21baa883f 100644 --- a/operator/pkg/constants/constants.go +++ b/operator/pkg/constants/constants.go @@ -56,6 +56,9 @@ const ( AnnotationMGHSchedulerInterval = "mgh-scheduler-interval" // MGHOperandImagePrefix ... MGHOperandImagePrefix = "RELATED_IMAGE_" + // AnnotationImportClusterInHosted will import a managedhub cluster in hosted mode, + // will disable application and policy related addons + AnnotationImportClusterInHosted = "import-cluster-in-hosted" // AnnotationStatisticInterval to log the interval of statistic log AnnotationStatisticInterval = "mgh-statistic-interval" // AnnotationMetricsScrapeInterval to set the scrape interval for metrics @@ -68,8 +71,6 @@ const ( // hub installation constants const ( - LocalClusterName = "local-cluster" - OpenshiftMarketPlaceNamespace = "openshift-marketplace" ACMSubscriptionPublicSource = "redhat-operators" ACMSubscriptionPrivateSource = "acm-custom-registry" @@ -90,14 +91,6 @@ const ( ) const ( - // AnnotationAddonHostingClusterName is the annotation for indicating the hosting cluster name in the addon - AnnotationAddonHostingClusterName = "addon.open-cluster-management.io/hosting-cluster-name" - // AnnotationClusterHostingClusterName is the annotation for indicating the hosting cluster name in the cluster - AnnotationClusterHostingClusterName = "import.open-cluster-management.io/hosting-cluster-name" - AnnotationClusterDeployMode = "import.open-cluster-management.io/klusterlet-deploy-mode" - AnnotationClusterKlusterletDeployNamespace = "import.open-cluster-management.io/klusterlet-namespace" - ClusterDeployModeHosted = "Hosted" - ClusterDeployModeDefault = "Default" // GHAgentDeployModeLabelKey is to indicate which deploy mode the agent is installed. GHAgentDeployModeLabelKey = "global-hub.open-cluster-management.io/agent-deploy-mode" diff --git a/operator/pkg/controllers/addons/addons_controller.go b/operator/pkg/controllers/addons/addons_controller.go new file mode 100644 index 000000000..252f6597b --- /dev/null +++ b/operator/pkg/controllers/addons/addons_controller.go @@ -0,0 +1,137 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addons + +import ( + "context" + "reflect" + + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog" + "open-cluster-management.io/api/addon/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/stolostron/multicluster-global-hub/operator/pkg/config" + "github.com/stolostron/multicluster-global-hub/pkg/constants" +) + +var addonList = sets.NewString( + "work-manager", + "cluster-proxy", + "managed-serviceaccount", +) + +var newNamespaceConfig = v1alpha1.PlacementStrategy{ + PlacementRef: v1alpha1.PlacementRef{ + Namespace: "open-cluster-management-global-set", + Name: "global", + }, + Configs: []v1alpha1.AddOnConfig{ + { + ConfigReferent: v1alpha1.ConfigReferent{ + Name: "global-hub", + Namespace: constants.GHDefaultNamespace, + }, + ConfigGroupResource: v1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + }, + }, +} + +// BackupReconciler reconciles a MulticlusterGlobalHub object +type AddonsReconciler struct { + manager.Manager + client.Client +} + +func NewAddonsReconciler(mgr manager.Manager) *AddonsReconciler { + return &AddonsReconciler{ + Manager: mgr, + Client: mgr.GetClient(), + } +} + +// SetupWithManager sets up the controller with the Manager. +func (r *AddonsReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr).Named("AddonsController"). + For(&v1alpha1.ClusterManagementAddOn{}, + builder.WithPredicates(addonPred)). + Complete(r) +} + +var addonPred = predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return addonList.Has(e.Object.GetName()) + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return addonList.Has(e.ObjectNew.GetName()) + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return false + }, +} + +func (r *AddonsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + klog.V(2).Infof("Reconcile ClusterManagementAddOn: %v", req.NamespacedName) + if !config.GetImportClusterInHosted() { + return ctrl.Result{}, nil + } + cma := &v1alpha1.ClusterManagementAddOn{} + err := r.Client.Get(ctx, req.NamespacedName, cma) + if err != nil { + return ctrl.Result{}, err + } + + needUpdate := addAddonConfig(cma) + + if !needUpdate { + return ctrl.Result{}, nil + } + err = r.Client.Update(ctx, cma) + if err != nil { + klog.Errorf("Failed to update cma, err:%v", err) + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +// addAddonConfig add the config to cma, will return true if the cma updated +func addAddonConfig(cma *v1alpha1.ClusterManagementAddOn) bool { + if len(cma.Spec.InstallStrategy.Placements) == 0 { + cma.Spec.InstallStrategy.Placements = append(cma.Spec.InstallStrategy.Placements, newNamespaceConfig) + return true + } + for _, pl := range cma.Spec.InstallStrategy.Placements { + if !reflect.DeepEqual(pl.PlacementRef, newNamespaceConfig.PlacementRef) { + continue + } + if reflect.DeepEqual(pl.Configs, newNamespaceConfig.Configs) { + return false + } + pl.Configs = append(pl.Configs, newNamespaceConfig.Configs...) + return true + } + cma.Spec.InstallStrategy.Placements = append(cma.Spec.InstallStrategy.Placements, newNamespaceConfig) + return true +} diff --git a/operator/pkg/controllers/addons/addons_controller_test.go b/operator/pkg/controllers/addons/addons_controller_test.go new file mode 100644 index 000000000..da5527f6b --- /dev/null +++ b/operator/pkg/controllers/addons/addons_controller_test.go @@ -0,0 +1,110 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addons + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "open-cluster-management.io/api/addon/v1alpha1" + + "github.com/stolostron/multicluster-global-hub/pkg/constants" +) + +func Test_addAddonConfig(t *testing.T) { + tests := []struct { + name string + cma *v1alpha1.ClusterManagementAddOn + want bool + }{ + { + name: "empty spec", + cma: &v1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "work-manager", + Namespace: "c1", + }, + }, + want: true, + }, + { + name: "has config in spec", + cma: &v1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "work-manager", + Namespace: "c1", + }, + Spec: v1alpha1.ClusterManagementAddOnSpec{ + InstallStrategy: v1alpha1.InstallStrategy{ + Type: "Manual", + Placements: []v1alpha1.PlacementStrategy{ + { + PlacementRef: v1alpha1.PlacementRef{ + Namespace: "ns", + Name: "pl", + }, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "has needed config in spec", + cma: &v1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "work-manager", + Namespace: "c1", + }, + Spec: v1alpha1.ClusterManagementAddOnSpec{ + InstallStrategy: v1alpha1.InstallStrategy{ + Type: "Manual", + Placements: []v1alpha1.PlacementStrategy{ + { + PlacementRef: v1alpha1.PlacementRef{ + Namespace: "open-cluster-management-global-set", + Name: "global", + }, + Configs: []v1alpha1.AddOnConfig{ + { + ConfigReferent: v1alpha1.ConfigReferent{ + Name: "global-hub", + Namespace: constants.GHDefaultNamespace, + }, + ConfigGroupResource: v1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + }, + }, + }, + }, + }, + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := addAddonConfig(tt.cma); got != tt.want { + t.Errorf("addAddonConfig() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/operator/pkg/controllers/addon/acmpackagemanifest.go b/operator/pkg/controllers/agent/acmpackagemanifest.go similarity index 99% rename from operator/pkg/controllers/addon/acmpackagemanifest.go rename to operator/pkg/controllers/agent/acmpackagemanifest.go index e351e7e61..9af106583 100644 --- a/operator/pkg/controllers/addon/acmpackagemanifest.go +++ b/operator/pkg/controllers/agent/acmpackagemanifest.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "context" diff --git a/operator/pkg/controllers/addon/acmpackagemanifest_test.go b/operator/pkg/controllers/agent/acmpackagemanifest_test.go similarity index 97% rename from operator/pkg/controllers/addon/acmpackagemanifest_test.go rename to operator/pkg/controllers/agent/acmpackagemanifest_test.go index b4cab33ed..3312a5857 100644 --- a/operator/pkg/controllers/addon/acmpackagemanifest_test.go +++ b/operator/pkg/controllers/agent/acmpackagemanifest_test.go @@ -1,4 +1,4 @@ -package addon_test +package agent_test import ( "context" @@ -8,7 +8,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" dynamicfake "k8s.io/client-go/dynamic/fake" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent" ) const acmPackageManifestJson = `{ @@ -104,7 +104,7 @@ func fakeMCEPackageManifests() *unstructured.Unstructured { func TestGetPackageManifestConfig(t *testing.T) { scheme := runtime.NewScheme() dynamicClient := dynamicfake.NewSimpleDynamicClient(scheme, fakeACMPackageManifests(), fakeMCEPackageManifests()) - pm, err := addon.GetPackageManifestConfig(context.TODO(), dynamicClient) + pm, err := agent.GetPackageManifestConfig(context.TODO(), dynamicClient) if err != nil { t.Errorf("failed to get packageManfiestConfig. err = %v", err) } diff --git a/operator/pkg/controllers/addon/addon_controller.go b/operator/pkg/controllers/agent/addon_controller.go similarity index 97% rename from operator/pkg/controllers/addon/addon_controller.go rename to operator/pkg/controllers/agent/addon_controller.go index 20d1b9f4f..7a4369b11 100644 --- a/operator/pkg/controllers/addon/addon_controller.go +++ b/operator/pkg/controllers/agent/addon_controller.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "context" @@ -26,7 +26,7 @@ import ( globalhubv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" operatorconstants "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon/certificates" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent/certificates" "github.com/stolostron/multicluster-global-hub/operator/pkg/utils" "github.com/stolostron/multicluster-global-hub/pkg/transport" ) @@ -116,9 +116,9 @@ func (a *AddonController) Start(ctx context.Context) error { WithAgentHostedModeEnabledOption(). WithGetValuesFuncs(hohAgentAddon.GetValues, addonfactory.GetValuesFromAddonAnnotation, - addonfactory.GetAddOnDeloymentConfigValues( - addonfactory.NewAddOnDeloymentConfigGetter(addonClient), - addonfactory.ToAddOnDeloymentConfigValues, + addonfactory.GetAddOnDeploymentConfigValues( + addonfactory.NewAddOnDeploymentConfigGetter(addonClient), + addonfactory.ToAddOnDeploymentConfigValues, addonfactory.ToAddOnCustomizedVariableValues, )). WithScheme(addonScheme) diff --git a/operator/pkg/controllers/addon/addon_controller_manifests.go b/operator/pkg/controllers/agent/addon_controller_manifests.go similarity index 96% rename from operator/pkg/controllers/addon/addon_controller_manifests.go rename to operator/pkg/controllers/agent/addon_controller_manifests.go index 4b0f0b9c4..2b7b86b14 100644 --- a/operator/pkg/controllers/addon/addon_controller_manifests.go +++ b/operator/pkg/controllers/agent/addon_controller_manifests.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "context" @@ -24,7 +24,7 @@ import ( globalhubv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" operatorconstants "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon/certificates" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent/certificates" "github.com/stolostron/multicluster-global-hub/operator/pkg/utils" "github.com/stolostron/multicluster-global-hub/pkg/constants" "github.com/stolostron/multicluster-global-hub/pkg/transport" @@ -131,8 +131,8 @@ func (a *HohAgentAddon) setInstallHostedMode(cluster *clusterv1.ManagedCluster, ) { annotations := cluster.GetAnnotations() labels := cluster.GetLabels() - if annotations[operatorconstants.AnnotationClusterDeployMode] != - operatorconstants.ClusterDeployModeHosted { + if annotations[constants.AnnotationClusterDeployMode] != + constants.ClusterDeployModeHosted { return } if labels[operatorconstants.GHAgentDeployModeLabelKey] != @@ -141,8 +141,8 @@ func (a *HohAgentAddon) setInstallHostedMode(cluster *clusterv1.ManagedCluster, } manifestsConfig.InstallHostedMode = true - if annotations[operatorconstants.AnnotationClusterKlusterletDeployNamespace] != "" { - manifestsConfig.KlusterletNamespace = annotations[operatorconstants.AnnotationClusterKlusterletDeployNamespace] + if annotations[constants.AnnotationClusterKlusterletDeployNamespace] != "" { + manifestsConfig.KlusterletNamespace = annotations[constants.AnnotationClusterKlusterletDeployNamespace] } manifestsConfig.KlusterletWorkSA = fmt.Sprintf("klusterlet-%s-work-sa", cluster.GetName()) } diff --git a/operator/pkg/controllers/addon/addon_controller_manifests_test.go b/operator/pkg/controllers/agent/addon_controller_manifests_test.go similarity index 99% rename from operator/pkg/controllers/addon/addon_controller_manifests_test.go rename to operator/pkg/controllers/agent/addon_controller_manifests_test.go index 4758ac835..54009243f 100644 --- a/operator/pkg/controllers/addon/addon_controller_manifests_test.go +++ b/operator/pkg/controllers/agent/addon_controller_manifests_test.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "testing" diff --git a/operator/pkg/controllers/addon/addon_installer.go b/operator/pkg/controllers/agent/addon_installer.go similarity index 97% rename from operator/pkg/controllers/addon/addon_installer.go rename to operator/pkg/controllers/agent/addon_installer.go index dbefa191e..d17d3157b 100644 --- a/operator/pkg/controllers/addon/addon_installer.go +++ b/operator/pkg/controllers/agent/addon_installer.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "context" @@ -198,12 +198,12 @@ func expectedManagedClusterAddon(cluster *clusterv1.ManagedCluster) (*v1alpha1.M deployMode := cluster.GetLabels()[operatorconstants.GHAgentDeployModeLabelKey] if deployMode == operatorconstants.GHAgentDeployModeHosted { annotations := cluster.GetAnnotations() - if hostingCluster := annotations[operatorconstants.AnnotationClusterHostingClusterName]; hostingCluster != "" { - expectedAddonAnnotations[operatorconstants.AnnotationAddonHostingClusterName] = hostingCluster + if hostingCluster := annotations[constants.AnnotationClusterHostingClusterName]; hostingCluster != "" { + expectedAddonAnnotations[constants.AnnotationAddonHostingClusterName] = hostingCluster expectedAddon.Spec.InstallNamespace = fmt.Sprintf("klusterlet-%s", cluster.Name) } else { return nil, fmt.Errorf("failed to get %s when addon in %s is installed in hosted mode", - operatorconstants.AnnotationClusterHostingClusterName, cluster.Name) + constants.AnnotationClusterHostingClusterName, cluster.Name) } } @@ -368,5 +368,5 @@ func GetAllManagedHubNames(ctx context.Context, c client.Client) ([]string, erro func filterManagedCluster(obj client.Object) bool { return obj.GetLabels()["vendor"] != "OpenShift" || obj.GetLabels()["openshiftVersion"] == "3" || - obj.GetName() == operatorconstants.LocalClusterName + obj.GetName() == constants.LocalClusterName } diff --git a/operator/pkg/controllers/addon/addon_installer_test.go b/operator/pkg/controllers/agent/addon_installer_test.go similarity index 92% rename from operator/pkg/controllers/addon/addon_installer_test.go rename to operator/pkg/controllers/agent/addon_installer_test.go index dcb60f6bb..675cbc7ca 100644 --- a/operator/pkg/controllers/addon/addon_installer_test.go +++ b/operator/pkg/controllers/agent/addon_installer_test.go @@ -1,4 +1,4 @@ -package addon_test +package agent_test import ( "context" @@ -20,7 +20,7 @@ import ( operatorv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" operatorconstants "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" - hubofhubsaddon "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon" + hubofhubsaddon "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent" operatortrans "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/transporter/protocol" "github.com/stolostron/multicluster-global-hub/pkg/constants" ) @@ -39,8 +39,8 @@ func fakeCluster(name, hostingCluster, addonDeployMode string) *v1.ManagedCluste if hostingCluster != "" { annotations := map[string]string{ - operatorconstants.AnnotationClusterDeployMode: operatorconstants.ClusterDeployModeHosted, - operatorconstants.AnnotationClusterHostingClusterName: hostingCluster, + constants.AnnotationClusterDeployMode: constants.ClusterDeployModeHosted, + constants.AnnotationClusterHostingClusterName: hostingCluster, } cluster.SetAnnotations(annotations) } @@ -87,8 +87,8 @@ func fakeHoHAddon(cluster, installNamespace, addonDeployMode string) *v1alpha1.M }, } - if addonDeployMode == operatorconstants.ClusterDeployModeHosted { - addon.SetAnnotations(map[string]string{operatorconstants.AnnotationAddonHostingClusterName: "hostingcluster"}) + if addonDeployMode == constants.ClusterDeployModeHosted { + addon.SetAnnotations(map[string]string{constants.AnnotationAddonHostingClusterName: "hostingcluster"}) } return addon @@ -186,9 +186,9 @@ func TestAddonInstaller(t *testing.T) { if addon.Spec.InstallNamespace != "klusterlet-cluster1" { t.Errorf("expected installname klusterlet-cluster1, but got %s", addon.Spec.InstallNamespace) } - if addon.Annotations[operatorconstants.AnnotationAddonHostingClusterName] != "cluster2" { + if addon.Annotations[constants.AnnotationAddonHostingClusterName] != "cluster2" { t.Errorf("expected hosting cluster cluster2, but got %s", - addon.Annotations[operatorconstants.AnnotationAddonHostingClusterName]) + addon.Annotations[constants.AnnotationAddonHostingClusterName]) } }, }, @@ -207,9 +207,9 @@ func TestAddonInstaller(t *testing.T) { if addon.Spec.InstallNamespace != "klusterlet-cluster1" { t.Errorf("expected installname klusterlet-cluster1, but got %s", addon.Spec.InstallNamespace) } - if addon.Annotations[operatorconstants.AnnotationAddonHostingClusterName] != "cluster2" { + if addon.Annotations[constants.AnnotationAddonHostingClusterName] != "cluster2" { t.Errorf("expected hosting cluster cluster2, but got %s", - addon.Annotations[operatorconstants.AnnotationAddonHostingClusterName]) + addon.Annotations[constants.AnnotationAddonHostingClusterName]) } }, }, diff --git a/operator/pkg/controllers/addon/certificates/approver.go b/operator/pkg/controllers/agent/certificates/approver.go similarity index 100% rename from operator/pkg/controllers/addon/certificates/approver.go rename to operator/pkg/controllers/agent/certificates/approver.go diff --git a/operator/pkg/controllers/addon/certificates/approver_test.go b/operator/pkg/controllers/agent/certificates/approver_test.go similarity index 100% rename from operator/pkg/controllers/addon/certificates/approver_test.go rename to operator/pkg/controllers/agent/certificates/approver_test.go diff --git a/operator/pkg/controllers/addon/certificates/csr.go b/operator/pkg/controllers/agent/certificates/csr.go similarity index 100% rename from operator/pkg/controllers/addon/certificates/csr.go rename to operator/pkg/controllers/agent/certificates/csr.go diff --git a/operator/pkg/controllers/addon/certificates/signer.go b/operator/pkg/controllers/agent/certificates/signer.go similarity index 100% rename from operator/pkg/controllers/addon/certificates/signer.go rename to operator/pkg/controllers/agent/certificates/signer.go diff --git a/operator/pkg/controllers/addon/certificates/signer_test.go b/operator/pkg/controllers/agent/certificates/signer_test.go similarity index 100% rename from operator/pkg/controllers/addon/certificates/signer_test.go rename to operator/pkg/controllers/agent/certificates/signer_test.go diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-clusterrole.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-clusterrole.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-clusterrole.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-clusterrole.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-clusterrolebinding.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-clusterrolebinding.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-clusterrolebinding.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-clusterrolebinding.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-configmap.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-configmap.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-configmap.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-configmap.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-deployment.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-deployment.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-deployment.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-deployment.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-kafka-certs-secret.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-kafka-certs-secret.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-kafka-certs-secret.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-kafka-certs-secret.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-kafka-cluster-ca-cert.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-kafka-cluster-ca-cert.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-kafka-cluster-ca-cert.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-kafka-cluster-ca-cert.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-namespace.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-namespace.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-namespace.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-namespace.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-pre-delete-job.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-pre-delete-job.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-pre-delete-job.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-pre-delete-job.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-pull-secret.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-pull-secret.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-pull-secret.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-pull-secret.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-serviceaccount.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-serviceaccount.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-serviceaccount.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-serviceaccount.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-transport-config-secret.yaml b/operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-transport-config-secret.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/agent/multicluster-global-hub-agent-transport-config-secret.yaml rename to operator/pkg/controllers/agent/manifests/templates/agent/multicluster-global-hub-agent-transport-config-secret.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-agent-kafka-certs-secret.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-agent-kafka-certs-secret.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-agent-kafka-certs-secret.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-agent-kafka-certs-secret.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-agent-pull-secret.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-agent-pull-secret.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-agent-pull-secret.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-agent-pull-secret.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-deployment.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-deployment.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-deployment.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-deployment.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-pre-delete-job.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-pre-delete-job.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-pre-delete-job.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-pre-delete-job.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-role.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-role.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-role.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-role.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-rolebinding.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-rolebinding.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-rolebinding.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-rolebinding.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-serviceaccount.yaml b/operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-serviceaccount.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-serviceaccount.yaml rename to operator/pkg/controllers/agent/manifests/templates/hostedagent/multicluster-global-hub-hosting-agent-serviceaccount.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-clusterrole.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-clusterrole.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-clusterrole.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-clusterrole.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-clusterrolebinding.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-clusterrolebinding.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-clusterrolebinding.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-clusterrolebinding.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-mch.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-mch.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-mch.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-mch.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-namespace.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-namespace.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-namespace.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-namespace.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-operatorgroup.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-operatorgroup.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-operatorgroup.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-operatorgroup.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-pullsecret.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-pullsecret.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-pullsecret.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-pullsecret.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-subscription.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-subscription.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/hubcluster-subscription.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/hubcluster-subscription.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/klusterlet-work-agent-clusterrole.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/klusterlet-work-agent-clusterrole.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/klusterlet-work-agent-clusterrole.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/klusterlet-work-agent-clusterrole.yaml diff --git a/operator/pkg/controllers/addon/manifests/templates/hubcluster/klusterlet-work-agent-clusterrolebinding.yaml b/operator/pkg/controllers/agent/manifests/templates/hubcluster/klusterlet-work-agent-clusterrolebinding.yaml similarity index 100% rename from operator/pkg/controllers/addon/manifests/templates/hubcluster/klusterlet-work-agent-clusterrolebinding.yaml rename to operator/pkg/controllers/agent/manifests/templates/hubcluster/klusterlet-work-agent-clusterrolebinding.yaml diff --git a/operator/pkg/controllers/crd/crd_controller.go b/operator/pkg/controllers/crd/crd_controller.go index fecac441d..8eb7621cc 100644 --- a/operator/pkg/controllers/crd/crd_controller.go +++ b/operator/pkg/controllers/crd/crd_controller.go @@ -35,7 +35,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/source" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addons" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/backup" "github.com/stolostron/multicluster-global-hub/pkg/constants" ) @@ -64,10 +65,11 @@ type CrdController struct { operatorConfig *config.OperatorConfig resources map[string]bool addonInstallerReady bool - addonController *addon.AddonController + agentController *agent.AddonController globalHubController runtimeController.Controller globalHubControllerReady bool backupControllerReady bool + addonsControllerReady bool mu sync.Mutex } @@ -94,7 +96,7 @@ func (r *CrdController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R // start addon installer if !r.addonInstallerReady { - if err := (&addon.AddonInstaller{ + if err := (&agent.AddonInstaller{ Client: r.GetClient(), Log: ctrl.Log.WithName("addon-reconciler"), }).SetupWithManager(ctx, r.Manager); err != nil { @@ -104,16 +106,16 @@ func (r *CrdController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R } // start addon controller - if r.addonController == nil { - addonController, err := addon.NewAddonController(r.Manager.GetConfig(), r.Manager.GetClient(), r.operatorConfig) + if r.agentController == nil { + agentController, err := agent.NewAddonController(r.Manager.GetConfig(), r.Manager.GetClient(), r.operatorConfig) if err != nil { return ctrl.Result{}, err } - err = r.Manager.Add(addonController) + err = r.Manager.Add(agentController) if err != nil { return ctrl.Result{}, err } - r.addonController = addonController + r.agentController = agentController } // backup controller @@ -125,6 +127,13 @@ func (r *CrdController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R r.backupControllerReady = true } + if !r.addonsControllerReady { + err := addons.NewAddonsReconciler(r.Manager).SetupWithManager(r.Manager) + if err != nil { + return ctrl.Result{}, err + } + r.addonsControllerReady = true + } return ctrl.Result{}, nil } diff --git a/operator/pkg/controllers/hubofhubs/controller.go b/operator/pkg/controllers/hubofhubs/controller.go index a8a34fccb..1eff33184 100644 --- a/operator/pkg/controllers/hubofhubs/controller.go +++ b/operator/pkg/controllers/hubofhubs/controller.go @@ -63,6 +63,7 @@ import ( "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/storage" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/transporter" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/transporter/protocol" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/webhook" "github.com/stolostron/multicluster-global-hub/operator/pkg/utils" "github.com/stolostron/multicluster-global-hub/pkg/constants" ) @@ -82,6 +83,7 @@ type GlobalHubReconciler struct { transportReconciler *transporter.TransportReconciler statusReconciler *status.StatusReconciler managerReconciler *manager.ManagerReconciler + webhookReconciler *webhook.WebhookReconciler grafanaReconciler *grafana.GrafanaReconciler imageClient *imagev1client.ImageV1Client } @@ -102,6 +104,7 @@ func NewGlobalHubReconciler(mgr ctrl.Manager, kubeClient kubernetes.Interface, transportReconciler: transporter.NewTransportReconciler(mgr), statusReconciler: status.NewStatusReconciler(mgr.GetClient()), managerReconciler: manager.NewManagerReconciler(mgr, kubeClient, operatorConfig), + webhookReconciler: webhook.NewWebhookReconciler(mgr), grafanaReconciler: grafana.NewGrafanaReconciler(mgr, kubeClient), imageClient: imageClient, } @@ -570,7 +573,8 @@ func watchMutatingWebhookConfigurationPredicate() predicate.TypedPredicate[*admi // +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles,verbs=get;list;watch;create;update;delete // +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterrolebindings,verbs=get;list;watch;create;update;delete // +kubebuilder:rbac:groups="admissionregistration.k8s.io",resources=mutatingwebhookconfigurations,verbs=get;list;watch;create;update;delete -// +kubebuilder:rbac:groups=addon.open-cluster-management.io,resources=clustermanagementaddons,verbs=create;delete;get;list;update;watch +// +kubebuilder:rbac:groups=addon.open-cluster-management.io,resources=clustermanagementaddons,verbs=create;delete;get;list;patch;update;watch +// +kubebuilder:rbac:groups=addon.open-cluster-management.io,resources=addondeploymentconfigs,verbs=create;delete;get;list;update;watch // +kubebuilder:rbac:groups=addon.open-cluster-management.io,resources=clustermanagementaddons/finalizers,verbs=update // +kubebuilder:rbac:groups=operator.open-cluster-management.io,resources=multiclusterhubs,verbs=get;list;patch;update;watch // +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors;prometheusrules;podmonitors,verbs=get;create;delete;update;list;watch @@ -631,6 +635,8 @@ func (r *GlobalHubReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } }() + config.SetImportClusterInHosted(mgh) + // prune resources if deleting mgh or metrics is disabled if err = r.pruneReconciler.Reconcile(ctx, mgh); err != nil { return ctrl.Result{}, fmt.Errorf("failed to prune Global Hub resources %v", err) @@ -668,6 +674,10 @@ func (r *GlobalHubReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } + if err := r.webhookReconciler.Reconcile(ctx, mgh); err != nil { + return ctrl.Result{}, err + } + if config.IsACMResourceReady() { // Grafana is required for ACM global hub // reconcile grafana diff --git a/operator/pkg/controllers/hubofhubs/manager/manager_reconciler.go b/operator/pkg/controllers/hubofhubs/manager/manager_reconciler.go index 884f17ee3..4fffa670f 100644 --- a/operator/pkg/controllers/hubofhubs/manager/manager_reconciler.go +++ b/operator/pkg/controllers/hubofhubs/manager/manager_reconciler.go @@ -150,6 +150,7 @@ func (r *ManagerReconciler) Reconcile(ctx context.Context, RetentionMonth: months, StatisticLogInterval: config.GetStatisticLogInterval(), EnableGlobalResource: r.operatorConfig.GlobalResourceEnabled, + ImportClusterInHosted: config.GetImportClusterInHosted(), EnablePprof: r.operatorConfig.EnablePprof, LogLevel: r.operatorConfig.LogLevel, Resources: utils.GetResources(operatorconstants.Manager, mgh.Spec.AdvancedConfig), @@ -224,6 +225,7 @@ type ManagerVariables struct { RetentionMonth int StatisticLogInterval string EnableGlobalResource bool + ImportClusterInHosted bool EnablePprof bool LogLevel string Resources *corev1.ResourceRequirements diff --git a/operator/pkg/controllers/hubofhubs/manager/manifests/clusterrole.yaml b/operator/pkg/controllers/hubofhubs/manager/manifests/clusterrole.yaml index e38ab40fc..7bcf11043 100644 --- a/operator/pkg/controllers/hubofhubs/manager/manifests/clusterrole.yaml +++ b/operator/pkg/controllers/hubofhubs/manager/manifests/clusterrole.yaml @@ -53,6 +53,16 @@ rules: - update - patch - delete +- apiGroups: + - "addon.open-cluster-management.io" + resources: + - clustermanagementaddons + verbs: + - get + - list + - watch + - update + - patch - apiGroups: - "cluster.open-cluster-management.io" resources: diff --git a/operator/pkg/controllers/hubofhubs/manager/manifests/deployment.yaml b/operator/pkg/controllers/hubofhubs/manager/manifests/deployment.yaml index 8c3db3365..865f2174d 100644 --- a/operator/pkg/controllers/hubofhubs/manager/manifests/deployment.yaml +++ b/operator/pkg/controllers/hubofhubs/manager/manifests/deployment.yaml @@ -90,7 +90,7 @@ spec: name: metrics protocol: TCP volumeMounts: - {{- if .EnableGlobalResource }} + {{- if .EnableGlobalResource}} - mountPath: /webhook-certs name: webhook-certs readOnly: true @@ -101,7 +101,7 @@ spec: - mountPath: /postgres-credential name: postgres-credential readOnly: true - {{- if .EnableGlobalResource }} + {{- if .EnableGlobalResource}} - name: oauth-proxy image: {{.ProxyImage}} imagePullPolicy: {{.ImagePullPolicy}} @@ -181,5 +181,5 @@ spec: secretName: nonk8s-apiserver-cookie-secret - name: webhook-certs secret: - secretName: multicluster-global-hub-webhook-certs + secretName: multicluster-global-hub-global-webhook-certs {{- end }} diff --git a/operator/pkg/controllers/hubofhubs/manager/manifests/mutatingwebhookconfiguration.yaml b/operator/pkg/controllers/hubofhubs/manager/manifests/mutatingwebhookconfiguration.yaml index 0472d7771..83f7adcc4 100644 --- a/operator/pkg/controllers/hubofhubs/manager/manifests/mutatingwebhookconfiguration.yaml +++ b/operator/pkg/controllers/hubofhubs/manager/manifests/mutatingwebhookconfiguration.yaml @@ -1,4 +1,4 @@ -{{ if .EnableGlobalResource }} +{{- if .EnableGlobalResource}} apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: @@ -11,7 +11,7 @@ webhooks: - v1beta1 clientConfig: service: - name: multicluster-global-hub-webhook + name: multicluster-global-hub-global-webhook namespace: {{.Namespace}} port: 443 path: /mutating diff --git a/operator/pkg/controllers/hubofhubs/manager/manifests/service.yaml b/operator/pkg/controllers/hubofhubs/manager/manifests/service.yaml index 9051267c0..b0e2f371b 100644 --- a/operator/pkg/controllers/hubofhubs/manager/manifests/service.yaml +++ b/operator/pkg/controllers/hubofhubs/manager/manifests/service.yaml @@ -25,17 +25,17 @@ spec: selector: name: multicluster-global-hub-manager --- -{{ if .EnableGlobalResource }} +{{- if .EnableGlobalResource}} apiVersion: v1 kind: Service metadata: - name: multicluster-global-hub-webhook + name: multicluster-global-hub-global-webhook namespace: {{.Namespace}} labels: - name: multicluster-global-hub-webhook - service: multicluster-global-hub-webhook + name: multicluster-global-hub-global-webhook + service: multicluster-global-hub-global-webhook annotations: - service.beta.openshift.io/serving-cert-secret-name: multicluster-global-hub-webhook-certs + service.beta.openshift.io/serving-cert-secret-name: multicluster-global-hub-global-webhook-certs spec: ports: - port: 443 diff --git a/operator/pkg/controllers/hubofhubs/prune/prune_reconciler.go b/operator/pkg/controllers/hubofhubs/prune/prune_reconciler.go index 9ffb41b2d..cda1ee21a 100644 --- a/operator/pkg/controllers/hubofhubs/prune/prune_reconciler.go +++ b/operator/pkg/controllers/hubofhubs/prune/prune_reconciler.go @@ -52,6 +52,9 @@ func (r *PruneReconciler) Reconcile(ctx context.Context, // Deleting the multiclusterglobalhub instance if mgh.GetDeletionTimestamp() != nil && operatorutils.Contains(mgh.GetFinalizers(), constants.GlobalHubCleanupFinalizer) { + if err := r.pruneWebhookResources(ctx); err != nil { + return err + } if err := r.GlobalHubResources(ctx, mgh); err != nil { return fmt.Errorf("failed to prune Global Hub resources %v", err) } @@ -60,6 +63,15 @@ func (r *PruneReconciler) Reconcile(ctx context.Context, } return nil } + // If webhook do not need to enable, should remove the related resources + if !config.GetImportClusterInHosted() { + if err := r.pruneWebhookResources(ctx); err != nil { + return err + } + if err := r.pruneHostedResources(ctx); err != nil { + return err + } + } // reconcile metrics if config.IsBYOKafka() && config.IsBYOPostgres() { @@ -72,6 +84,55 @@ func (r *PruneReconciler) Reconcile(ctx context.Context, return nil } +func (r *PruneReconciler) pruneHostedResources(ctx context.Context) error { + addonDeployConfig := &addonv1alpha1.AddOnDeploymentConfig{} + if err := r.Client.Get(ctx, types.NamespacedName{ + Namespace: utils.GetDefaultNamespace(), + Name: "global-hub", + }, addonDeployConfig); err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + return r.Client.Delete(ctx, addonDeployConfig) +} + +func (r *PruneReconciler) pruneWebhookResources(ctx context.Context) error { + listOpts := []client.ListOption{ + client.MatchingLabels(map[string]string{ + constants.GlobalHubOwnerLabelKey: constants.GHOperatorOwnerLabelVal, + }), + } + webhookList := &admissionregistrationv1.MutatingWebhookConfigurationList{} + if err := r.Client.List(ctx, webhookList, listOpts...); err != nil { + return err + } + + for idx := range webhookList.Items { + if err := r.Client.Delete(ctx, &webhookList.Items[idx]); err != nil && !errors.IsNotFound(err) { + return err + } + } + + webhookServiceListOpts := []client.ListOption{ + client.MatchingLabels(map[string]string{ + constants.GlobalHubOwnerLabelKey: constants.GHOperatorOwnerLabelVal, + "service": "multicluster-global-hub-webhook", + }), + } + webhookServiceList := &corev1.ServiceList{} + if err := r.Client.List(ctx, webhookServiceList, webhookServiceListOpts...); err != nil { + return err + } + for idx := range webhookServiceList.Items { + if err := r.Client.Delete(ctx, &webhookServiceList.Items[idx]); err != nil && !errors.IsNotFound(err) { + return err + } + } + return nil +} + func (r *PruneReconciler) pruneACMResources(ctx context.Context) error { // delete addon.open-cluster-management.io/on-multicluster-hub annotation if err := r.pruneManagedHubs(ctx); err != nil { @@ -293,7 +354,7 @@ func (r *PruneReconciler) pruneManagedHubs(ctx context.Context) error { } for idx, managedHub := range clusters.Items { - if managedHub.Name == operatorconstants.LocalClusterName { + if managedHub.Name == constants.LocalClusterName { continue } orgAnnotations := managedHub.GetAnnotations() diff --git a/operator/pkg/controllers/hubofhubs/prune/prune_reconciler_test.go b/operator/pkg/controllers/hubofhubs/prune/prune_reconciler_test.go index 9fc9fb213..1e9060d43 100644 --- a/operator/pkg/controllers/hubofhubs/prune/prune_reconciler_test.go +++ b/operator/pkg/controllers/hubofhubs/prune/prune_reconciler_test.go @@ -7,14 +7,20 @@ import ( kafkav1beta2 "github.com/RedHatInsights/strimzi-client-go/apis/kafka.strimzi.io/v1beta2" subv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" promv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" + addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + globalhubv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" + "github.com/stolostron/multicluster-global-hub/operator/pkg/config" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/grafana" "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/transporter/protocol" + "github.com/stolostron/multicluster-global-hub/pkg/constants" "github.com/stolostron/multicluster-global-hub/pkg/utils" ) @@ -154,7 +160,6 @@ func TestMulticlusterGlobalHubReconcilerStrimziResources(t *testing.T) { ctx := context.Background() kafkav1beta2.AddToScheme(scheme.Scheme) subv1alpha1.AddToScheme(scheme.Scheme) - fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(tt.initObjects...).Build() r := NewPruneReconciler(fakeClient) if err := r.pruneStrimziResources(ctx); (err != nil) != tt.wantErr { @@ -163,3 +168,158 @@ func TestMulticlusterGlobalHubReconcilerStrimziResources(t *testing.T) { }) } } + +func TestWebhookResources(t *testing.T) { + tests := []struct { + name string + initObjects []runtime.Object + mgh *globalhubv1alpha4.MulticlusterGlobalHub + webhookItem int + }{ + { + name: "remove webhook resources", + mgh: &globalhubv1alpha4.MulticlusterGlobalHub{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: utils.GetDefaultNamespace(), + Name: "mgh", + Annotations: map[string]string{ + "import-cluster-in-hosted": "false", + }, + }, + Spec: globalhubv1alpha4.MulticlusterGlobalHubSpec{}, + }, + webhookItem: 0, + initObjects: []runtime.Object{ + &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-webhook", + Namespace: utils.GetDefaultNamespace(), + Labels: map[string]string{ + "global-hub.open-cluster-management.io/managed-by": "global-hub-operator", + "service": "multicluster-global-hub-webhook", + }, + }, + }, + &admissionregistrationv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-mutator", + Labels: map[string]string{ + "global-hub.open-cluster-management.io/managed-by": "global-hub-operator", + }, + }, + }, + }, + }, + + { + name: "do not remove webhook resources because webhook needed for hosted cluster", + mgh: &globalhubv1alpha4.MulticlusterGlobalHub{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: utils.GetDefaultNamespace(), + Name: "mgh", + Annotations: map[string]string{ + "import-cluster-in-hosted": "true", + }, + }, + Spec: globalhubv1alpha4.MulticlusterGlobalHubSpec{}, + }, + webhookItem: 1, + initObjects: []runtime.Object{ + &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-webhook", + Namespace: utils.GetDefaultNamespace(), + Labels: map[string]string{ + "global-hub.open-cluster-management.io/managed-by": "global-hub-operator", + "service": "multicluster-global-hub-webhook", + }, + }, + }, + &admissionregistrationv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-mutator", + Labels: map[string]string{ + "global-hub.open-cluster-management.io/managed-by": "global-hub-operator", + }, + }, + }, + }, + }, + { + name: "do not remove webhook resources because webhook is needed", + mgh: &globalhubv1alpha4.MulticlusterGlobalHub{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: utils.GetDefaultNamespace(), + Name: "mgh", + Annotations: map[string]string{ + "import-cluster-in-hosted": "true", + }, + }, + Spec: globalhubv1alpha4.MulticlusterGlobalHubSpec{}, + }, + webhookItem: 1, + initObjects: []runtime.Object{ + &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-webhook", + Namespace: utils.GetDefaultNamespace(), + Labels: map[string]string{ + "global-hub.open-cluster-management.io/managed-by": "global-hub-operator", + "service": "multicluster-global-hub-webhook", + }, + }, + }, + &admissionregistrationv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-mutator", + Labels: map[string]string{ + "global-hub.open-cluster-management.io/managed-by": "global-hub-operator", + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + kafkav1beta2.AddToScheme(scheme.Scheme) + subv1alpha1.AddToScheme(scheme.Scheme) + addonv1alpha1.AddToScheme(scheme.Scheme) + + config.SetImportClusterInHosted(tt.mgh) + + fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(tt.initObjects...).Build() + r := NewPruneReconciler(fakeClient) + if err := r.Reconcile(ctx, tt.mgh); err != nil { + t.Errorf("MulticlusterGlobalHubReconciler.reconcile() error = %v", err) + } + listOpts := []client.ListOption{ + client.MatchingLabels(map[string]string{ + constants.GlobalHubOwnerLabelKey: constants.GHOperatorOwnerLabelVal, + }), + } + webhookList := &admissionregistrationv1.MutatingWebhookConfigurationList{} + if err := fakeClient.List(ctx, webhookList, listOpts...); err != nil { + t.Errorf("Failed to list webhook config") + } + if len(webhookList.Items) != tt.webhookItem { + t.Errorf("Name:%v, Existing webhookItems:%v, want webhook items:%v", tt.name, len(webhookList.Items), tt.webhookItem) + } + + webhookServiceListOpts := []client.ListOption{ + client.MatchingLabels(map[string]string{ + constants.GlobalHubOwnerLabelKey: constants.GHOperatorOwnerLabelVal, + "service": "multicluster-global-hub-webhook", + }), + } + webhookServiceList := &corev1.ServiceList{} + if err := fakeClient.List(ctx, webhookServiceList, webhookServiceListOpts...); err != nil { + t.Errorf("Failed to list webhook service") + } + if len(webhookServiceList.Items) != tt.webhookItem { + t.Errorf("Name:%v,Existing webhookServiceList:%v, want webhook items:%v", tt.name, len(webhookServiceList.Items), tt.webhookItem) + } + }) + } +} diff --git a/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_kafka_controller.go b/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_kafka_controller.go index f8530f91d..2c9290cf0 100644 --- a/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_kafka_controller.go +++ b/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_kafka_controller.go @@ -100,7 +100,7 @@ func StartKafkaController(ctx context.Context, mgr ctrl.Manager) (*KafkaControll // even if the following controller will reconcile the transport, but it's asynchoronized err = ctrl.NewControllerManagedBy(mgr). - Named("kafka_controller"). + Named("strimzi_kafka_controller"). For(&v1alpha4.MulticlusterGlobalHub{}, builder.WithPredicates(mghPred)). Watches(&kafkav1beta2.Kafka{}, &handler.EnqueueRequestForObject{}, builder.WithPredicates(kafkaPred)). diff --git a/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_transporter.go b/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_transporter.go index 6c4611301..044ecb8b4 100644 --- a/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_transporter.go +++ b/operator/pkg/controllers/hubofhubs/transporter/protocol/strimzi_transporter.go @@ -31,7 +31,7 @@ import ( operatorv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" operatorconstants "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon/certificates" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent/certificates" "github.com/stolostron/multicluster-global-hub/operator/pkg/deployer" "github.com/stolostron/multicluster-global-hub/operator/pkg/renderer" "github.com/stolostron/multicluster-global-hub/operator/pkg/utils" diff --git a/operator/pkg/controllers/hubofhubs/webhook/manifests/addondeploymentconfig.yaml b/operator/pkg/controllers/hubofhubs/webhook/manifests/addondeploymentconfig.yaml new file mode 100644 index 000000000..9033cc195 --- /dev/null +++ b/operator/pkg/controllers/hubofhubs/webhook/manifests/addondeploymentconfig.yaml @@ -0,0 +1,11 @@ +{{- if .ImportClusterInHosted}} +apiVersion: addon.open-cluster-management.io/v1alpha1 +kind: AddOnDeploymentConfig +metadata: + name: global-hub + namespace: multicluster-global-hub + labels: + cluster.open-cluster-management.io/backup: globalhub +spec: + agentInstallNamespace: open-cluster-management-global-hub-agent-addon +{{ end }} diff --git a/operator/pkg/controllers/hubofhubs/webhook/manifests/mutatingwebhookconfiguration.yaml b/operator/pkg/controllers/hubofhubs/webhook/manifests/mutatingwebhookconfiguration.yaml new file mode 100644 index 000000000..08423b55a --- /dev/null +++ b/operator/pkg/controllers/hubofhubs/webhook/manifests/mutatingwebhookconfiguration.yaml @@ -0,0 +1,42 @@ +{{- if .ImportClusterInHosted}} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: multicluster-global-hub-mutating + annotations: + service.beta.openshift.io/inject-cabundle: "true" +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: multicluster-global-hub-webhook + namespace: multicluster-global-hub + port: 443 + path: /mutating + caBundle: XG4= + failurePolicy: Fail + name: global-hub.open-cluster-management.io + matchPolicy: Equivalent + sideEffects: None + rules: + - apiGroups: + - agent.open-cluster-management.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - klusterletaddonconfigs + - apiGroups: + - cluster.open-cluster-management.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - managedclusters +{{ end }} diff --git a/operator/pkg/controllers/hubofhubs/webhook/webhook_reconciler.go b/operator/pkg/controllers/hubofhubs/webhook/webhook_reconciler.go new file mode 100644 index 000000000..313aad905 --- /dev/null +++ b/operator/pkg/controllers/hubofhubs/webhook/webhook_reconciler.go @@ -0,0 +1,65 @@ +package webhook + +import ( + "context" + "embed" + "fmt" + + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/restmapper" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" + "github.com/stolostron/multicluster-global-hub/operator/pkg/config" + "github.com/stolostron/multicluster-global-hub/operator/pkg/deployer" + "github.com/stolostron/multicluster-global-hub/operator/pkg/renderer" + "github.com/stolostron/multicluster-global-hub/operator/pkg/utils" +) + +//go:embed manifests +var fs embed.FS + +type WebhookReconciler struct { + ctrl.Manager +} + +func NewWebhookReconciler(mgr ctrl.Manager, +) *WebhookReconciler { + return &WebhookReconciler{ + Manager: mgr, + } +} + +func (r *WebhookReconciler) Reconcile(ctx context.Context, + mgh *v1alpha4.MulticlusterGlobalHub, +) error { + // create new HoHRenderer and HoHDeployer + hohRenderer, hohDeployer := renderer.NewHoHRenderer(fs), deployer.NewHoHDeployer(r.GetClient()) + + // create discovery client + dc, err := discovery.NewDiscoveryClientForConfig(r.Manager.GetConfig()) + if err != nil { + return err + } + + // create restmapper for deployer to find GVR + mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc)) + + webhookObjects, err := hohRenderer.Render("manifests", "", func(profile string) (interface{}, error) { + return WebhookVariables{ + ImportClusterInHosted: config.GetImportClusterInHosted(), + }, nil + }) + if err != nil { + return fmt.Errorf("failed to render webhook objects: %v", err) + } + if err = utils.ManipulateGlobalHubObjects(webhookObjects, mgh, hohDeployer, mapper, r.GetScheme()); err != nil { + return fmt.Errorf("failed to create/update webhook objects: %v", err) + } + return nil +} + +type WebhookVariables struct { + ImportClusterInHosted bool +} diff --git a/operator/pkg/utils/utils.go b/operator/pkg/utils/utils.go index 924056f7f..e9a4249fe 100644 --- a/operator/pkg/utils/utils.go +++ b/operator/pkg/utils/utils.go @@ -47,9 +47,9 @@ import ( "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" - "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" + operatorconstants "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" "github.com/stolostron/multicluster-global-hub/operator/pkg/deployer" - commonconstants "github.com/stolostron/multicluster-global-hub/pkg/constants" + "github.com/stolostron/multicluster-global-hub/pkg/constants" ) // MergeObjects merge the desiredObj into the existingObj, then unmarshal to updatedObj @@ -298,48 +298,48 @@ func GetResources(component string, advanced *v1alpha4.AdvancedConfig) *corev1.R limits := corev1.ResourceList{} switch component { - case constants.Grafana: - requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.GrafanaMemoryRequest) - requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.GrafanaCPURequest) - limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.GrafanaMemoryLimit) - limits[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.GrafanaCPULimit) + case operatorconstants.Grafana: + requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.GrafanaMemoryRequest) + requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.GrafanaCPURequest) + limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.GrafanaMemoryLimit) + limits[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.GrafanaCPULimit) if advanced != nil && advanced.Grafana != nil { setResourcesFromCR(advanced.Grafana.Resources, requests, limits) } - case constants.Postgres: - requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.PostgresMemoryRequest) - requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.PostgresCPURequest) - limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.PostgresMemoryLimit) + case operatorconstants.Postgres: + requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.PostgresMemoryRequest) + requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.PostgresCPURequest) + limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.PostgresMemoryLimit) if advanced != nil && advanced.Postgres != nil { setResourcesFromCR(advanced.Postgres.Resources, requests, limits) } - case constants.Manager: - requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.ManagerMemoryRequest) - requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.ManagerCPURequest) - limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.ManagerMemoryLimit) + case operatorconstants.Manager: + requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.ManagerMemoryRequest) + requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.ManagerCPURequest) + limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.ManagerMemoryLimit) if advanced != nil && advanced.Manager != nil { setResourcesFromCR(advanced.Manager.Resources, requests, limits) } - case constants.Agent: - requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.AgentMemoryRequest) - requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.AgentCPURequest) - limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.AgentMemoryLimit) + case operatorconstants.Agent: + requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.AgentMemoryRequest) + requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.AgentCPURequest) + limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.AgentMemoryLimit) if advanced != nil && advanced.Agent != nil { setResourcesFromCR(advanced.Agent.Resources, requests, limits) } - case constants.Kafka: - requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.KafkaMemoryRequest) - requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.KafkaCPURequest) - limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.KafkaMemoryLimit) + case operatorconstants.Kafka: + requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.KafkaMemoryRequest) + requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.KafkaCPURequest) + limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.KafkaMemoryLimit) if advanced != nil && advanced.Kafka != nil { setResourcesFromCR(advanced.Kafka.Resources, requests, limits) } - case constants.Zookeeper: - requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.ZookeeperMemoryRequest) - requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(constants.ZookeeperCPURequest) - limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(constants.ZookeeperMemoryLimit) + case operatorconstants.Zookeeper: + requests[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.ZookeeperMemoryRequest) + requests[corev1.ResourceName(corev1.ResourceCPU)] = resource.MustParse(operatorconstants.ZookeeperCPURequest) + limits[corev1.ResourceName(corev1.ResourceMemory)] = resource.MustParse(operatorconstants.ZookeeperMemoryLimit) if advanced != nil && advanced.Zookeeper != nil { setResourcesFromCR(advanced.Zookeeper.Resources, requests, limits) } @@ -391,7 +391,7 @@ func RemoveManagedHubClusterFinalizer(ctx context.Context, c client.Client) erro continue } - if ok := controllerutil.RemoveFinalizer(managedHub, commonconstants.GlobalHubCleanupFinalizer); ok { + if ok := controllerutil.RemoveFinalizer(managedHub, constants.GlobalHubCleanupFinalizer); ok { if err := c.Update(ctx, managedHub, &client.UpdateOptions{}); err != nil { return err } @@ -420,8 +420,8 @@ func AnnotateManagedHubCluster(ctx context.Context, c client.Client) error { CopyMap(annotations, managedHub.GetAnnotations()) // set the annotations for the managed hub - orgAnnotations[constants.AnnotationONMulticlusterHub] = "true" - orgAnnotations[constants.AnnotationPolicyONMulticlusterHub] = "true" + orgAnnotations[operatorconstants.AnnotationONMulticlusterHub] = "true" + orgAnnotations[operatorconstants.AnnotationPolicyONMulticlusterHub] = "true" if !equality.Semantic.DeepEqual(annotations, orgAnnotations) { if err := c.Update(ctx, &clusters.Items[idx], &client.UpdateOptions{}); err != nil { return err @@ -440,7 +440,7 @@ func TriggerManagedHubAddons(ctx context.Context, c client.Client, addonManager for i := range clusters.Items { cluster := clusters.Items[i] if !FilterManagedCluster(&cluster) { - addonManager.Trigger(cluster.Name, constants.GHClusterManagementAddonName) + addonManager.Trigger(cluster.Name, operatorconstants.GHClusterManagementAddonName) } } return nil @@ -476,7 +476,7 @@ func ManipulateGlobalHubObjects(objects []*unstructured.Unstructured, if labels == nil { labels = make(map[string]string) } - labels[commonconstants.GlobalHubOwnerLabelKey] = commonconstants.GHOperatorOwnerLabelVal + labels[constants.GlobalHubOwnerLabelKey] = constants.GHOperatorOwnerLabelVal obj.SetLabels(labels) if err := hohDeployer.Deploy(obj); err != nil { diff --git a/operator/pkg/webhook/admission_handler.go b/operator/pkg/webhook/admission_handler.go new file mode 100644 index 000000000..a544b48f8 --- /dev/null +++ b/operator/pkg/webhook/admission_handler.go @@ -0,0 +1,162 @@ +// Copyright (c) 2022 Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project + +package webhook + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + addonv1 "github.com/stolostron/klusterlet-addon-controller/pkg/apis/agent/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog" + clusterv1 "open-cluster-management.io/api/cluster/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/stolostron/multicluster-global-hub/pkg/constants" +) + +// NewAdmissionHandler is to handle the admission webhook for placementrule and placement +func NewAdmissionHandler(c client.Client, s *runtime.Scheme) admission.Handler { + return &admissionHandler{ + client: c, + decoder: admission.NewDecoder(s), + } +} + +type admissionHandler struct { + client client.Client + decoder admission.Decoder +} + +func (a *admissionHandler) Handle(ctx context.Context, req admission.Request) admission.Response { + klog.V(2).Infof("admission webhook is called, name:%v, namespace:%v, kind:%v, operation:%v", req.Name, + req.Namespace, req.Kind.Kind, req.Operation) + switch req.Kind.Kind { + case "ManagedCluster": + cluster := &clusterv1.ManagedCluster{} + err := a.decoder.Decode(req, cluster) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + if cluster.Name == constants.LocalClusterName { + return admission.Allowed("") + } + + // If cluster already imported, skip it + if meta.IsStatusConditionTrue(cluster.Status.Conditions, constants.ManagedClusterImportSucceeded) { + return admission.Allowed("") + } + + changed := setHostedAnnotations(cluster) + if !changed { + return admission.Allowed("") + } + + klog.Infof("Add hosted annotation for managedcluster: %v", cluster.Name) + + marshaledCluster, err := json.Marshal(cluster) + if err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } + return admission.PatchResponseFromRaw(req.Object.Raw, marshaledCluster) + + case "KlusterletAddonConfig": + klusterletaddonconfig := &addonv1.KlusterletAddonConfig{} + err := a.decoder.Decode(req, klusterletaddonconfig) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + // only handle hosted clusters + isHosted, err := isInHostedCluster(ctx, a.client, klusterletaddonconfig.Namespace) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + if !isHosted { + return admission.Allowed("") + } + + changed := disableAddons(klusterletaddonconfig) + if !changed { + return admission.Allowed("") + } + klog.Infof("Disable addons in cluster :%v", klusterletaddonconfig.Namespace) + + marshaledKlusterletAddon, err := json.Marshal(klusterletaddonconfig) + if err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } + return admission.PatchResponseFromRaw(req.Object.Raw, marshaledKlusterletAddon) + default: + return admission.Allowed("") + } +} + +// isInHostedCluster check if the cluster has hosted annotations +func isInHostedCluster(ctx context.Context, client client.Client, mcName string) (bool, error) { + mc := &clusterv1.ManagedCluster{} + err := client.Get(ctx, types.NamespacedName{Name: mcName}, mc) + if err != nil { + if errors.IsNotFound(err) { + return true, nil + } + errMsg := fmt.Errorf("failed to get managedcluster, err:%v", err) + klog.Errorf(errMsg.Error()) + return false, errMsg + } + + if (mc.Annotations[constants.AnnotationClusterDeployMode] == constants.ClusterDeployModeHosted) && + (mc.Annotations[constants.AnnotationClusterHostingClusterName] == constants.LocalClusterName) { + return true, nil + } + return false, nil +} + +// disableAddons disable addons in klusterletaddonconfig, return true if changed +func disableAddons(klusterletaddonconfig *addonv1.KlusterletAddonConfig) bool { + changed := false + if klusterletaddonconfig.Spec.ApplicationManagerConfig.Enabled { + klusterletaddonconfig.Spec.ApplicationManagerConfig.Enabled = false + changed = true + } + if klusterletaddonconfig.Spec.PolicyController.Enabled { + klusterletaddonconfig.Spec.PolicyController.Enabled = false + changed = true + } + if klusterletaddonconfig.Spec.CertPolicyControllerConfig.Enabled { + klusterletaddonconfig.Spec.CertPolicyControllerConfig.Enabled = false + changed = true + } + + return changed +} + +// setHostedAnnotations set hosted annotation for cluster, and return true if changed +func setHostedAnnotations(cluster *clusterv1.ManagedCluster) bool { + if (cluster.Annotations[constants.AnnotationClusterDeployMode] == constants.ClusterDeployModeHosted) && + (cluster.Annotations[constants.AnnotationClusterHostingClusterName] == constants.LocalClusterName) { + return false + } + if cluster.Annotations == nil { + cluster.Annotations = map[string]string{} + } + cluster.Annotations[constants.AnnotationClusterDeployMode] = constants.ClusterDeployModeHosted + cluster.Annotations[constants.AnnotationClusterHostingClusterName] = constants.LocalClusterName + return true +} + +// AdmissionHandler implements admission.DecoderInjector. +// A decoder will be automatically injected. + +// InjectDecoder injects the decoder. +func (a *admissionHandler) InjectDecoder(d admission.Decoder) error { + a.decoder = d + return nil +} diff --git a/operator/pkg/webhook/admission_handler_test.go b/operator/pkg/webhook/admission_handler_test.go new file mode 100644 index 000000000..e56311d41 --- /dev/null +++ b/operator/pkg/webhook/admission_handler_test.go @@ -0,0 +1,216 @@ +// Copyright (c) 2022 Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project + +package webhook + +import ( + "context" + "testing" + + addonv1 "github.com/stolostron/klusterlet-addon-controller/pkg/apis/agent/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "open-cluster-management.io/api/cluster/v1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/stolostron/multicluster-global-hub/operator/pkg/config" + "github.com/stolostron/multicluster-global-hub/pkg/constants" +) + +func Test_setHostedAnnotations(t *testing.T) { + tests := []struct { + name string + cluster *clusterv1.ManagedCluster + want bool + }{ + { + name: "no annotation", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + }, + want: true, + }, + { + name: "has other annotation", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Annotations: map[string]string{ + "a": "b", + }, + }, + }, + want: true, + }, + { + name: "has false annotation", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Annotations: map[string]string{ + constants.AnnotationClusterDeployMode: "b", + constants.AnnotationClusterHostingClusterName: constants.LocalClusterName, + }, + }, + }, + want: true, + }, + { + name: "has hosted annotation", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + Annotations: map[string]string{ + constants.AnnotationClusterDeployMode: constants.ClusterDeployModeHosted, + constants.AnnotationClusterHostingClusterName: constants.LocalClusterName, + }, + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := setHostedAnnotations(tt.cluster); got != tt.want { + t.Errorf("name:%v, setHostedAnnotations() = %v, want %v", tt.name, got, tt.want) + } + }) + } +} + +func Test_disableAddons(t *testing.T) { + tests := []struct { + name string + klusterletaddonconfig *addonv1.KlusterletAddonConfig + want bool + }{ + { + name: "enable all addons", + klusterletaddonconfig: &addonv1.KlusterletAddonConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: addonv1.KlusterletAddonConfigSpec{ + ApplicationManagerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + PolicyController: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + CertPolicyControllerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + }, + }, + want: true, + }, + { + name: "enable some addons", + klusterletaddonconfig: &addonv1.KlusterletAddonConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: addonv1.KlusterletAddonConfigSpec{ + ApplicationManagerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: false, + }, + PolicyController: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: false, + }, + CertPolicyControllerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + }, + }, + want: true, + }, + { + name: "disable all addons", + klusterletaddonconfig: &addonv1.KlusterletAddonConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: addonv1.KlusterletAddonConfigSpec{ + ApplicationManagerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: false, + }, + PolicyController: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: false, + }, + CertPolicyControllerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: false, + }, + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := disableAddons(tt.klusterletaddonconfig); got != tt.want { + t.Errorf("disableAddons() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_isInHostedCluster(t *testing.T) { + tests := []struct { + name string + want bool + cluster *clusterv1.ManagedCluster + }{ + { + name: "no annotation", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-not", + }, + }, + want: true, + }, + { + name: "has annotation, but not hosted", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{ + "k": "v", + }, + }, + }, + want: false, + }, + { + name: "has hosted annotation", + cluster: &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{ + constants.AnnotationClusterDeployMode: constants.ClusterDeployModeHosted, + constants.AnnotationClusterHostingClusterName: constants.LocalClusterName, + }, + }, + }, + want: true, + }, + } + for _, tt := range tests { + ctx := context.Background() + client := fake.NewClientBuilder().WithScheme(config.GetRuntimeScheme()).WithObjects(tt.cluster).Build() + t.Run(tt.name, func(t *testing.T) { + if got, err := isInHostedCluster(ctx, client, "test"); got != tt.want { + t.Errorf("isInHostedCluster() = %v, want %v", got, tt.want) + t.Errorf("err:%v", err) + } + }) + } +} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index dc2a5862f..b846f3bd1 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -49,6 +49,18 @@ const ( ) const ( + // AnnotationAddonHostingClusterName is the annotation for indicating the hosting cluster name in the addon + AnnotationAddonHostingClusterName = "addon.open-cluster-management.io/hosting-cluster-name" + // AnnotationClusterHostingClusterName is the annotation for indicating the hosting cluster name in the cluster + AnnotationClusterHostingClusterName = "import.open-cluster-management.io/hosting-cluster-name" + AnnotationClusterDeployMode = "import.open-cluster-management.io/klusterlet-deploy-mode" + AnnotationClusterKlusterletDeployNamespace = "import.open-cluster-management.io/klusterlet-namespace" + ClusterDeployModeHosted = "Hosted" + ClusterDeployModeDefault = "Default" +) + +const ( + LocalClusterName = "local-cluster" // lock the database LockId = "1" ) @@ -148,3 +160,8 @@ const ( // the label is from the reference object itself PolicyEventClusterNameLabelKey = "policy.open-cluster-management.io/cluster-name" ) + +const ( + // Managedcluster imported status type + ManagedClusterImportSucceeded = "ManagedClusterImportSucceeded" +) diff --git a/samples/config/confluent_config.go b/samples/config/confluent_config.go index 66a25c629..2db53a01a 100644 --- a/samples/config/confluent_config.go +++ b/samples/config/confluent_config.go @@ -9,7 +9,7 @@ import ( kafkav1beta2 "github.com/RedHatInsights/strimzi-client-go/apis/kafka.strimzi.io/v1beta2" "github.com/confluentinc/confluent-kafka-go/v2/kafka" operatorconfig "github.com/stolostron/multicluster-global-hub/operator/pkg/config" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon/certificates" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent/certificates" "github.com/stolostron/multicluster-global-hub/pkg/constants" "github.com/stolostron/multicluster-global-hub/pkg/transport" "github.com/stolostron/multicluster-global-hub/pkg/transport/config" diff --git a/test/integration/manager/webhook/admission_handler_test.go b/test/integration/manager/webhook/admission_handler_test.go index 47e38dfd4..b6ddb7119 100644 --- a/test/integration/manager/webhook/admission_handler_test.go +++ b/test/integration/manager/webhook/admission_handler_test.go @@ -4,63 +4,21 @@ package webhook_test import ( - "context" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1" placementrulesv1 "open-cluster-management.io/multicloud-operators-subscription/pkg/apis/apps/placementrule/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - "sigs.k8s.io/controller-runtime/pkg/webhook" - mgrwebhook "github.com/stolostron/multicluster-global-hub/manager/pkg/webhook" "github.com/stolostron/multicluster-global-hub/pkg/constants" "github.com/stolostron/multicluster-global-hub/pkg/utils" ) var _ = Describe("Multicluster hub manager webhook", func() { - var cancel context.CancelFunc - var c client.Client - Context("Test Placement and placementrule are handled by the global hub manager webhook", Ordered, func() { - BeforeAll(func() { - // add scheme - err := placementrulesv1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - err = clusterv1beta1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - m, err := manager.New(testEnv.Config, manager.Options{ - WebhookServer: webhook.NewServer(webhook.Options{ - Host: testEnv.WebhookInstallOptions.LocalServingHost, - Port: testEnv.WebhookInstallOptions.LocalServingPort, - CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, - }), - Scheme: scheme.Scheme, - Metrics: metricsserver.Options{ - BindAddress: "0", // disable the metrics serving - }, - }) // we need manager here just to leverage manager.SetFields - Expect(err).NotTo(HaveOccurred()) - - c, err = client.New(testEnv.Config, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - - server := m.GetWebhookServer() - server.Register("/mutating", &webhook.Admission{ - Handler: mgrwebhook.NewAdmissionHandler(m.GetClient(), m.GetScheme()), - }) - - ctx, cancel = context.WithCancel(context.Background()) - go func() { - _ = m.Start(ctx) - }() - }) It("Should add cluster.open-cluster-management.io/experimental-scheduling-disable annotation to placement", func() { testPlacement := &clusterv1beta1.Placement{ ObjectMeta: metav1.ObjectMeta{ @@ -147,9 +105,5 @@ var _ = Describe("Multicluster hub manager webhook", func() { return placementrule.Spec.SchedulerName != constants.GlobalHubSchedulerName }, 1*time.Second, 5*time.Second).Should(BeTrue()) }) - - AfterAll(func() { - cancel() - }) }) }) diff --git a/test/integration/manager/webhook/admission_suite_test.go b/test/integration/manager/webhook/admission_suite_test.go index 11bdb8da3..0d1a23f76 100644 --- a/test/integration/manager/webhook/admission_suite_test.go +++ b/test/integration/manager/webhook/admission_suite_test.go @@ -21,13 +21,23 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + addonapi "github.com/stolostron/klusterlet-addon-controller/pkg/apis" admissionv1 "k8s.io/api/admissionregistration/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" + clusterv1 "open-cluster-management.io/api/cluster/v1" + clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1" + placementrulesv1 "open-cluster-management.io/multicloud-operators-subscription/pkg/apis/apps/placementrule/v1" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + mgrwebhook "github.com/stolostron/multicluster-global-hub/manager/pkg/webhook" "github.com/stolostron/multicluster-global-hub/pkg/utils" ) @@ -39,6 +49,7 @@ var ( testEnv *envtest.Environment ctx context.Context cancel context.CancelFunc + c client.Client ) func TestControllers(t *testing.T) { @@ -68,14 +79,51 @@ var _ = BeforeSuite(func() { cfg, err = testEnv.Start() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) + + // add scheme + err = placementrulesv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = clusterv1beta1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = addonapi.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + clusterv1.AddToScheme(scheme.Scheme) + + m, err := manager.New(testEnv.Config, manager.Options{ + WebhookServer: webhook.NewServer(webhook.Options{ + Host: testEnv.WebhookInstallOptions.LocalServingHost, + Port: testEnv.WebhookInstallOptions.LocalServingPort, + CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, + }), + Scheme: scheme.Scheme, + Metrics: metricsserver.Options{ + BindAddress: "0", // disable the metrics serving + }, + }) // we need manager here just to leverage manager.SetFields + Expect(err).NotTo(HaveOccurred()) + + c, err = client.New(testEnv.Config, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + + server := m.GetWebhookServer() + server.Register("/mutating", &webhook.Admission{ + Handler: mgrwebhook.NewAdmissionHandler(m.GetClient(), m.GetScheme()), + }) + + ctx, cancel = context.WithCancel(context.Background()) + go func() { + _ = m.Start(ctx) + }() }) var _ = AfterSuite(func() { + cancel() Expect(testEnv.Stop()).NotTo(HaveOccurred()) }) func initializeWebhookInEnvironment() { namespacedScopeV1 := admissionv1.NamespacedScope + clusterScope := admissionv1.ClusterScope failedTypeV1 := admissionv1.Fail equivalentTypeV1 := admissionv1.Equivalent noSideEffectsV1 := admissionv1.SideEffectClassNone @@ -108,6 +156,24 @@ func initializeWebhookInEnvironment() { Scope: &namespacedScopeV1, }, }, + { + Operations: []admissionv1.OperationType{"CREATE", "UPDATE"}, + Rule: admissionv1.Rule{ + APIGroups: []string{"agent.open-cluster-management.io"}, + APIVersions: []string{"v1"}, + Resources: []string{"klusterletaddonconfigs"}, + Scope: &namespacedScopeV1, + }, + }, + { + Operations: []admissionv1.OperationType{"CREATE", "UPDATE"}, + Rule: admissionv1.Rule{ + APIGroups: []string{"cluster.open-cluster-management.io"}, + APIVersions: []string{"v1"}, + Resources: []string{"managedclusters"}, + Scope: &clusterScope, + }, + }, }, FailurePolicy: &failedTypeV1, MatchPolicy: &equivalentTypeV1, diff --git a/test/integration/operator/addons/addons_hosted_test.go b/test/integration/operator/addons/addons_hosted_test.go new file mode 100644 index 000000000..316a298d6 --- /dev/null +++ b/test/integration/operator/addons/addons_hosted_test.go @@ -0,0 +1,176 @@ +package addons + +import ( + "reflect" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog" + "open-cluster-management.io/api/addon/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + globalhubv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" + "github.com/stolostron/multicluster-global-hub/operator/pkg/config" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addons" + "github.com/stolostron/multicluster-global-hub/pkg/constants" + "github.com/stolostron/multicluster-global-hub/pkg/utils" +) + +var addonList = sets.NewString( + "work-manager", + "cluster-proxy", + "managed-serviceaccount", +) + +var ( + timeout = time.Second * 30 + interval = time.Millisecond * 250 + hostedNamespace = "mc-hosted" +) + +var newNamespaceConfig = v1alpha1.PlacementStrategy{ + PlacementRef: v1alpha1.PlacementRef{ + Namespace: "open-cluster-management-global-set", + Name: "global", + }, + Configs: []v1alpha1.AddOnConfig{ + { + ConfigReferent: v1alpha1.ConfigReferent{ + Name: "global-hub", + Namespace: constants.GHDefaultNamespace, + }, + ConfigGroupResource: v1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + }, + }, +} + +var workManager = v1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "work-manager", + }, + Spec: v1alpha1.ClusterManagementAddOnSpec{ + InstallStrategy: v1alpha1.InstallStrategy{ + Type: "Manual", + }, + }, +} + +var proxy = v1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-proxy", + }, + Spec: v1alpha1.ClusterManagementAddOnSpec{ + InstallStrategy: v1alpha1.InstallStrategy{ + Type: "Manual", + }, + }, +} + +var msa = v1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "managed-serviceaccount", + }, + Spec: v1alpha1.ClusterManagementAddOnSpec{ + InstallStrategy: v1alpha1.InstallStrategy{ + Type: "Manual", + }, + }, +} + +var mgh = globalhubv1alpha4.MulticlusterGlobalHub{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: utils.GetDefaultNamespace(), + Name: "mgh", + Annotations: map[string]string{ + "import-cluster-in-hosted": "true", + }, + }, + Spec: globalhubv1alpha4.MulticlusterGlobalHubSpec{}, +} + +var _ = Describe("addons hosted mode test", Ordered, func() { + var addonsReconciler *addons.AddonsReconciler + BeforeAll(func() { + config.SetImportClusterInHosted(&mgh) + addonsReconciler = addons.NewAddonsReconciler(mgr) + err := addonsReconciler.SetupWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + mcHostedNamespace := &corev1.Namespace{ObjectMeta: v1.ObjectMeta{Name: hostedNamespace}} + err = mgr.GetClient().Create(ctx, mcHostedNamespace) + Expect(err).Should(Succeed()) + time.Sleep(1 * time.Second) + + workManagerDefault := workManager.DeepCopy() + workManagerDefault.Namespace = hostedNamespace + err = mgr.GetClient().Create(ctx, workManagerDefault) + Expect(err).NotTo(HaveOccurred()) + + proxyDefault := proxy.DeepCopy() + proxyDefault.Namespace = hostedNamespace + err = mgr.GetClient().Create(ctx, proxyDefault) + Expect(err).NotTo(HaveOccurred()) + + msaDefault := msa.DeepCopy() + msaDefault.Namespace = hostedNamespace + err = mgr.GetClient().Create(ctx, msaDefault) + Expect(err).NotTo(HaveOccurred()) + }) + + AfterAll(func() { + err := mgr.GetClient().Delete(ctx, &workManager) + Expect(err).NotTo(HaveOccurred()) + err = mgr.GetClient().Delete(ctx, &proxy) + Expect(err).NotTo(HaveOccurred()) + err = mgr.GetClient().Delete(ctx, &msa) + Expect(err).NotTo(HaveOccurred()) + }) + + It("addons should be added the new config", func() { + Eventually(func() bool { + cma := &v1alpha1.ClusterManagementAddOn{} + for addonName := range addonList { + _, err := addonsReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: hostedNamespace, + Name: addonName, + }, + }) + if err != nil { + klog.Errorf("Failed to reconcile addon, err:%v", err) + return false + } + + err = mgr.GetClient().Get(ctx, types.NamespacedName{ + Namespace: hostedNamespace, + Name: addonName, + }, cma) + if err != nil { + klog.Errorf("Failed to list ClusterManagementAddOn") + return false + } + + found := false + for _, ps := range cma.Spec.InstallStrategy.Placements { + if reflect.DeepEqual(ps.PlacementRef, newNamespaceConfig.PlacementRef) && + reflect.DeepEqual(ps.Configs, newNamespaceConfig.Configs) { + found = true + } + } + if !found { + klog.Errorf("Can not found expected config in %v", cma.Spec.InstallStrategy) + return false + } + } + return true + }, timeout, interval).Should(BeTrue()) + }) +}) diff --git a/test/integration/operator/addons/suite_test.go b/test/integration/operator/addons/suite_test.go new file mode 100644 index 000000000..bc31ea3ef --- /dev/null +++ b/test/integration/operator/addons/suite_test.go @@ -0,0 +1,79 @@ +package addons + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + _ "github.com/lib/pq" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + "github.com/stolostron/multicluster-global-hub/operator/pkg/config" +) + +var ( + testenv *envtest.Environment + cfg *rest.Config + ctx context.Context + cancel context.CancelFunc + mgr manager.Manager +) + +func TestController(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Addons Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + Expect(os.Setenv("POD_NAMESPACE", "default")).To(Succeed()) + + ctx, cancel = context.WithCancel(context.Background()) + + By("Prepare envtest environment") + var err error + testenv = &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join("..", "..", "..", "manifest", "crd"), + }, + ErrorIfCRDPathMissing: true, + } + cfg, err = testenv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + mgr, err = ctrl.NewManager(cfg, ctrl.Options{ + Metrics: metricsserver.Options{ + BindAddress: "0", // disable the metrics serving + }, + Scheme: config.GetRuntimeScheme(), + }) + Expect(err).NotTo(HaveOccurred()) + go func() { + Expect(mgr.Start(ctx)).NotTo(HaveOccurred()) + }() + + By("Waiting for the manager to be ready") + Expect(mgr.GetCache().WaitForCacheSync(ctx)).To(BeTrue()) +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testenv.Stop() + // https://github.com/kubernetes-sigs/controller-runtime/issues/1571 + // Set 4 with random + if err != nil { + time.Sleep(4 * time.Second) + Expect(testenv.Stop()).NotTo(HaveOccurred()) + } + cancel() +}) diff --git a/test/integration/operator/addon/addon_deploy_test.go b/test/integration/operator/agent/addon_deploy_test.go similarity index 93% rename from test/integration/operator/addon/addon_deploy_test.go rename to test/integration/operator/agent/addon_deploy_test.go index 749ac8e61..e0afaa864 100644 --- a/test/integration/operator/addon/addon_deploy_test.go +++ b/test/integration/operator/agent/addon_deploy_test.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "fmt" @@ -163,7 +163,7 @@ var _ = Describe("addon deploy", func() { operatorconstants.GHAgentDeployModeLabelKey: operatorconstants.GHAgentDeployModeDefault, }, map[string]string{ - operatorconstants.AnnotationClusterHostingClusterName: hostingClusterName, + constants.AnnotationClusterHostingClusterName: hostingClusterName, }, []clusterv1.ManagedClusterClaim{}, clusterAvailableCondition) @@ -209,9 +209,9 @@ var _ = Describe("addon deploy", func() { operatorconstants.GHAgentDeployModeLabelKey: operatorconstants.GHAgentDeployModeHosted, }, map[string]string{ - operatorconstants.AnnotationClusterDeployMode: operatorconstants.ClusterDeployModeHosted, - operatorconstants.AnnotationClusterKlusterletDeployNamespace: "open-cluster-management-hub1", - operatorconstants.AnnotationClusterHostingClusterName: hostingClusterName, + constants.AnnotationClusterDeployMode: constants.ClusterDeployModeHosted, + constants.AnnotationClusterKlusterletDeployNamespace: "open-cluster-management-hub1", + constants.AnnotationClusterHostingClusterName: hostingClusterName, }, []clusterv1.ManagedClusterClaim{}, clusterAvailableCondition) @@ -232,7 +232,7 @@ var _ = Describe("addon deploy", func() { }, addon) }, timeout, interval).ShouldNot(HaveOccurred()) - Expect(addon.GetAnnotations()[operatorconstants.AnnotationAddonHostingClusterName]).Should(Equal(hostingClusterName)) + Expect(addon.GetAnnotations()[constants.AnnotationAddonHostingClusterName]).Should(Equal(hostingClusterName)) By("By checking the agent manifestworks are created for the newly created managed cluster") work := &workv1.ManifestWork{} @@ -270,9 +270,9 @@ var _ = Describe("addon deploy", func() { operatorconstants.GHAgentACMHubInstallLabelKey: "", }, map[string]string{ - operatorconstants.AnnotationClusterDeployMode: operatorconstants.ClusterDeployModeHosted, - operatorconstants.AnnotationClusterKlusterletDeployNamespace: "open-cluster-management-hub1", - operatorconstants.AnnotationClusterHostingClusterName: hostingClusterName, + constants.AnnotationClusterDeployMode: constants.ClusterDeployModeHosted, + constants.AnnotationClusterKlusterletDeployNamespace: "open-cluster-management-hub1", + constants.AnnotationClusterHostingClusterName: hostingClusterName, }, []clusterv1.ManagedClusterClaim{ { @@ -298,7 +298,7 @@ var _ = Describe("addon deploy", func() { }, addon) }, timeout, interval).ShouldNot(HaveOccurred()) - Expect(addon.GetAnnotations()[operatorconstants.AnnotationAddonHostingClusterName]).Should(Equal(hostingClusterName)) + Expect(addon.GetAnnotations()[constants.AnnotationAddonHostingClusterName]).Should(Equal(hostingClusterName)) By("By checking the agent manifestworks are created for the newly created managed cluster") work := &workv1.ManifestWork{} @@ -351,7 +351,7 @@ var _ = Describe("addon deploy", func() { []clusterv1.ManagedClusterClaim{}, ) By("By preparing a local cluster") - clusterName4 := operatorconstants.LocalClusterName + clusterName4 := constants.LocalClusterName prepareCluster(clusterName4, map[string]string{ "vendor": "OpenShift", operatorconstants.GHAgentDeployModeLabelKey: operatorconstants.GHAgentDeployModeDefault, diff --git a/test/integration/operator/addon/addon_registry_test.go b/test/integration/operator/agent/addon_registry_test.go similarity index 99% rename from test/integration/operator/addon/addon_registry_test.go rename to test/integration/operator/agent/addon_registry_test.go index c30a6eb50..6fe140b14 100644 --- a/test/integration/operator/addon/addon_registry_test.go +++ b/test/integration/operator/agent/addon_registry_test.go @@ -1,4 +1,4 @@ -package addon +package agent import ( "encoding/json" diff --git a/test/integration/operator/addon/suite_test.go b/test/integration/operator/agent/suite_test.go similarity index 96% rename from test/integration/operator/addon/suite_test.go rename to test/integration/operator/agent/suite_test.go index a070af293..210d6ef23 100644 --- a/test/integration/operator/addon/suite_test.go +++ b/test/integration/operator/agent/suite_test.go @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package addon +package agent import ( "context" @@ -39,7 +39,7 @@ import ( globalhubv1alpha4 "github.com/stolostron/multicluster-global-hub/operator/apis/v1alpha4" "github.com/stolostron/multicluster-global-hub/operator/pkg/config" operatorconstants "github.com/stolostron/multicluster-global-hub/operator/pkg/constants" - "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/addon" + "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/agent" operatortrans "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/hubofhubs/transporter/protocol" "github.com/stolostron/multicluster-global-hub/pkg/constants" "github.com/stolostron/multicluster-global-hub/pkg/utils" @@ -100,7 +100,7 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) By("Add the addon installer to the manager") - err = (&addon.AddonInstaller{ + err = (&agent.AddonInstaller{ Client: runtimeClient, Log: ctrl.Log.WithName("addon install controller"), }).SetupWithManager(ctx, k8sManager) @@ -112,7 +112,7 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) By("Add the addon controller to the manager") - addonController, err := addon.NewAddonController(k8sManager.GetConfig(), runtimeClient, &config.OperatorConfig{ + addonController, err := agent.NewAddonController(k8sManager.GetConfig(), runtimeClient, &config.OperatorConfig{ GlobalResourceEnabled: true, LogLevel: "info", EnablePprof: false, @@ -207,7 +207,7 @@ func prepareBeforeTest() { // set fake packagemenifestwork configuration By("By setting a fake packagemanifest configuration") - addon.SetPackageManifestConfig("release-2.6", "advanced-cluster-management.v2.6.0", + agent.SetPackageManifestConfig("release-2.6", "advanced-cluster-management.v2.6.0", "stable-2.0", "multicluster-engine.v2.0.1", map[string]string{"multiclusterhub-operator": "example.com/registration-operator:test"}, map[string]string{"registration-operator": "example.com/registration-operator:test"}) @@ -240,6 +240,11 @@ func prepareBeforeTest() { constants.GlobalHubOwnerLabelKey: constants.GHOperatorOwnerLabelVal, }, }, + Spec: addonv1alpha1.ClusterManagementAddOnSpec{ + InstallStrategy: addonv1alpha1.InstallStrategy{ + Type: "Manual", + }, + }, } Expect(runtimeClient.Create(ctx, clusterManagementAddon)).Should(Succeed()) } diff --git a/test/integration/operator/webhook/admission_handler_test.go b/test/integration/operator/webhook/admission_handler_test.go new file mode 100644 index 000000000..20cf7277a --- /dev/null +++ b/test/integration/operator/webhook/admission_handler_test.go @@ -0,0 +1,95 @@ +// Copyright (c) 2021 Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project + +package webhook_test + +import ( + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + addonv1 "github.com/stolostron/klusterlet-addon-controller/pkg/apis/agent/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog" + clusterv1 "open-cluster-management.io/api/cluster/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/stolostron/multicluster-global-hub/pkg/constants" + "github.com/stolostron/multicluster-global-hub/pkg/utils" +) + +var _ = Describe("Multicluster hub webhook", func() { + Context("Test managedclusters are handled by the global hub manager webhook", Ordered, func() { + It("managedcluster should be added the hosted annotations", func() { + testmanagedcluster := &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-mc-", + Namespace: utils.GetDefaultNamespace(), + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + } + + Eventually(func() bool { + if err := c.Create(ctx, testmanagedcluster, &client.CreateOptions{}); err != nil { + return false + } + mc := &clusterv1.ManagedCluster{} + if err := c.Get(ctx, client.ObjectKeyFromObject(testmanagedcluster), mc); err != nil { + return false + } + if mc.Annotations[constants.AnnotationClusterDeployMode] != constants.ClusterDeployModeHosted { + return false + } + if mc.Annotations[constants.AnnotationClusterHostingClusterName] != constants.LocalClusterName { + return false + } + return true + }, 1*time.Second, 5*time.Second).Should(BeTrue()) + }) + }) + + Context("Test klusterletaddonconfig are handled by the global hub manager webhook", Ordered, func() { + It("klusterletaddonconfig should be added the hosted annotations", func() { + klusterletConfig := &addonv1.KlusterletAddonConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: addonv1.KlusterletAddonConfigSpec{ + ApplicationManagerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + PolicyController: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + CertPolicyControllerConfig: addonv1.KlusterletAddonAgentConfigSpec{ + Enabled: true, + }, + }, + } + + Eventually(func() bool { + if err := c.Create(ctx, klusterletConfig, &client.CreateOptions{}); err != nil { + klog.Errorf("Failed to create klusterletAddonConfig, err:%v", err) + return false + } + kac := &addonv1.KlusterletAddonConfig{} + if err := c.Get(ctx, client.ObjectKeyFromObject(klusterletConfig), kac); err != nil { + klog.Errorf("Failed to get klusterletAddonConfig, err:%v", err) + return false + } + if kac.Spec.PolicyController.Enabled == true { + return false + } + if kac.Spec.ApplicationManagerConfig.Enabled == true { + return false + } + if kac.Spec.CertPolicyControllerConfig.Enabled == true { + return false + } + return true + }, 1*time.Second, 5*time.Second).Should(BeTrue()) + }) + }) +}) diff --git a/test/integration/operator/webhook/admission_suite_test.go b/test/integration/operator/webhook/admission_suite_test.go new file mode 100644 index 000000000..f67d7b6b8 --- /dev/null +++ b/test/integration/operator/webhook/admission_suite_test.go @@ -0,0 +1,173 @@ +/* +Copyright 2022. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package webhook_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + addonapi "github.com/stolostron/klusterlet-addon-controller/pkg/apis" + admissionv1 "k8s.io/api/admissionregistration/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + clusterv1 "open-cluster-management.io/api/cluster/v1" + clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + mgrwebhook "github.com/stolostron/multicluster-global-hub/operator/pkg/webhook" + "github.com/stolostron/multicluster-global-hub/pkg/utils" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var ( + cfg *rest.Config + testEnv *envtest.Environment + ctx context.Context + cancel context.CancelFunc + c client.Client +) + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Controller Integration Suite") +} + +var _ = BeforeSuite(func() { + Expect(os.Setenv("POD_NAMESPACE", "default")).To(Succeed()) + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + ctx, cancel = context.WithCancel(context.TODO()) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join("..", "..", "..", "manifest", "crd"), + }, + ErrorIfCRDPathMissing: true, + } + + // we're initializing webhook here and not in webhook.go to also test the envtest install code via WebhookOptions + initializeWebhookInEnvironment() + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + // add scheme + err = clusterv1beta1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = addonapi.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + clusterv1.AddToScheme(scheme.Scheme) + + m, err := manager.New(testEnv.Config, manager.Options{ + WebhookServer: webhook.NewServer(webhook.Options{ + Host: testEnv.WebhookInstallOptions.LocalServingHost, + Port: testEnv.WebhookInstallOptions.LocalServingPort, + CertDir: testEnv.WebhookInstallOptions.LocalServingCertDir, + }), + Scheme: scheme.Scheme, + Metrics: metricsserver.Options{ + BindAddress: "0", // disable the metrics serving + }, + }) // we need manager here just to leverage manager.SetFields + Expect(err).NotTo(HaveOccurred()) + + c, err = client.New(testEnv.Config, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + + server := m.GetWebhookServer() + server.Register("/mutating", &webhook.Admission{ + Handler: mgrwebhook.NewAdmissionHandler(m.GetClient(), m.GetScheme()), + }) + + ctx, cancel = context.WithCancel(context.Background()) + go func() { + _ = m.Start(ctx) + }() +}) + +var _ = AfterSuite(func() { + cancel() + Expect(testEnv.Stop()).NotTo(HaveOccurred()) +}) + +func initializeWebhookInEnvironment() { + namespacedScopeV1 := admissionv1.NamespacedScope + clusterScope := admissionv1.ClusterScope + failedTypeV1 := admissionv1.Fail + equivalentTypeV1 := admissionv1.Equivalent + noSideEffectsV1 := admissionv1.SideEffectClassNone + webhookPathV1 := "/mutating" + testEnv.WebhookInstallOptions = envtest.WebhookInstallOptions{ + MutatingWebhooks: []*admissionv1.MutatingWebhookConfiguration{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-mutating", + }, + Webhooks: []admissionv1.MutatingWebhook{ + { + Name: "global-hub.open-cluster-management.io", + Rules: []admissionv1.RuleWithOperations{ + { + Operations: []admissionv1.OperationType{"CREATE", "UPDATE"}, + Rule: admissionv1.Rule{ + APIGroups: []string{"agent.open-cluster-management.io"}, + APIVersions: []string{"v1"}, + Resources: []string{"klusterletaddonconfigs"}, + Scope: &namespacedScopeV1, + }, + }, + { + Operations: []admissionv1.OperationType{"CREATE", "UPDATE"}, + Rule: admissionv1.Rule{ + APIGroups: []string{"cluster.open-cluster-management.io"}, + APIVersions: []string{"v1"}, + Resources: []string{"managedclusters"}, + Scope: &clusterScope, + }, + }, + }, + FailurePolicy: &failedTypeV1, + MatchPolicy: &equivalentTypeV1, + SideEffects: &noSideEffectsV1, + ClientConfig: admissionv1.WebhookClientConfig{ + Service: &admissionv1.ServiceReference{ + Name: "multicluster-global-hub-mutator", + Namespace: utils.GetDefaultNamespace(), + Path: &webhookPathV1, + }, + }, + AdmissionReviewVersions: []string{"v1", "v1beta1"}, + }, + }, + }, + }, + } +} diff --git a/test/manifest/crd/0000_00_addon.open-cluster-management.io_clustermanagementaddons.crd.yaml b/test/manifest/crd/0000_00_addon.open-cluster-management.io_clustermanagementaddons.crd.yaml index 6326a7b48..66ca8e609 100644 --- a/test/manifest/crd/0000_00_addon.open-cluster-management.io_clustermanagementaddons.crd.yaml +++ b/test/manifest/crd/0000_00_addon.open-cluster-management.io_clustermanagementaddons.crd.yaml @@ -8,66 +8,667 @@ spec: kind: ClusterManagementAddOn listKind: ClusterManagementAddOnList plural: clustermanagementaddons + shortNames: + - cma + - cmas singular: clustermanagementaddon - scope: Cluster preserveUnknownFields: false + scope: Cluster versions: - - additionalPrinterColumns: - - jsonPath: .spec.addOnMeta.displayName - name: DISPLAY NAME - type: string - - jsonPath: .spec.addOnConfiguration.crdName - name: CRD NAME - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: ClusterManagementAddOn represents the registration of an add-on to the cluster manager. This resource allows the user to discover which add-on is available for the cluster manager and also provides metadata information about the add-on. This resource also provides a linkage to ManagedClusterAddOn, the name of the ClusterManagementAddOn resource will be used for the namespace-scoped ManagedClusterAddOn resource. ClusterManagementAddOn is a cluster-scoped resource. - type: object - 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 - spec: - description: spec represents a desired configuration for the agent on the cluster management add-on. - type: object - properties: - addOnConfiguration: - description: addOnConfiguration is a reference to configuration information for the add-on. In scenario where a multiple add-ons share the same add-on CRD, multiple ClusterManagementAddOn resources need to be created and reference the same AddOnConfiguration. + - additionalPrinterColumns: + - jsonPath: .spec.addOnMeta.displayName + name: DISPLAY NAME + type: string + - jsonPath: .spec.addOnConfiguration.crdName + name: CRD NAME + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterManagementAddOn represents the registration of an add-on + to the cluster manager. This resource allows you to discover which add-ons + are available for the cluster manager and provides metadata information + about the add-ons. The ClusterManagementAddOn name is used for the namespace-scoped + ManagedClusterAddOn resource. ClusterManagementAddOn is a cluster-scoped + resource. + 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 + spec: + description: spec represents a desired configuration for the agent on + the cluster management add-on. + properties: + addOnConfiguration: + description: 'Deprecated: Use supportedConfigs filed instead addOnConfiguration + is a reference to configuration information for the add-on. In scenario + where a multiple add-ons share the same add-on CRD, multiple ClusterManagementAddOn + resources need to be created and reference the same AddOnConfiguration.' + properties: + crName: + description: crName is the name of the CR used to configure instances + of the managed add-on. This field should be configured if add-on + CR have a consistent name across the all of the ManagedCluster + instaces. + type: string + crdName: + description: crdName is the name of the CRD used to configure + instances of the managed add-on. This field should be configured + if the add-on have a CRD that controls the configuration of + the add-on. + type: string + lastObservedGeneration: + description: lastObservedGeneration is the observed generation + of the custom resource for the configuration of the addon. + format: int64 + type: integer + type: object + addOnMeta: + description: addOnMeta is a reference to the metadata information + for the add-on. + properties: + description: + description: description represents the detailed description of + the add-on. + type: string + displayName: + description: displayName represents the name of add-on that will + be displayed. + type: string + type: object + installStrategy: + default: + type: Manual + description: InstallStrategy represents that related ManagedClusterAddOns + should be installed on certain clusters. + properties: + placements: + description: Placements is a list of placement references honored + when install strategy type is Placements. All clusters selected + by these placements will install the addon If one cluster belongs + to multiple placements, it will only apply the strategy defined + later in the order. That is to say, The latter strategy overrides + the previous one. + items: + properties: + configs: + description: Configs is the configuration of managedClusterAddon + during installation. User can override the configuration + by updating the managedClusterAddon directly. + items: + properties: + group: + default: "" + description: group of the add-on configuration. + type: string + name: + description: name of the add-on configuration. + minLength: 1 + type: string + namespace: + description: namespace of the add-on configuration. + If this field is not set, the configuration is in + the cluster scope. + type: string + resource: + description: resource of the add-on configuration. + minLength: 1 + type: string + required: + - name + - resource + type: object + type: array + name: + description: Name is the name of the placement + minLength: 1 + type: string + namespace: + description: Namespace is the namespace of the placement + minLength: 1 + type: string + rolloutStrategy: + default: + type: All + description: The rollout strategy to apply addon configurations + change. The rollout strategy only watches the addon configurations + defined in ClusterManagementAddOn. + properties: + all: + description: All defines required fields for RolloutStrategy + type All + properties: + maxFailures: + anyOf: + - type: integer + - type: string + default: 0 + description: MaxFailures is a percentage or number + of clusters in the current rollout that can fail + before proceeding to the next rollout. Fail means + the cluster has a failed status or timeout status + (does not reach successful status after ProgressDeadline). + Once the MaxFailures is breached, the rollout + will stop. MaxFailures is only considered for + rollout types Progressive and ProgressivePerGroup. + For Progressive, this is considered over the total + number of clusters. For ProgressivePerGroup, this + is considered according to the size of the current + group. For both Progressive and ProgressivePerGroup, + the MaxFailures does not apply for MandatoryDecisionGroups, + which tolerate no failures. Default is that no + failures are tolerated. + pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ + x-kubernetes-int-or-string: true + minSuccessTime: + default: "0" + description: MinSuccessTime is a "soak" time. In + other words, the minimum amount of time the workload + applier controller will wait from the start of + each rollout before proceeding (assuming a successful + state has been reached and MaxFailures wasn't + breached). MinSuccessTime is only considered for + rollout types Progressive and ProgressivePerGroup. + The default value is 0 meaning the workload applier + proceeds immediately after a successful state + is reached. MinSuccessTime must be defined in + [0-9h]|[0-9m]|[0-9s] format examples; 2h , 90m + , 360s + type: string + progressDeadline: + default: None + description: ProgressDeadline defines how long workload + applier controller will wait for the workload + to reach a successful state in the cluster. If + the workload does not reach a successful state + after ProgressDeadline, will stop waiting and + workload will be treated as "timeout" and be counted + into MaxFailures. Once the MaxFailures is breached, + the rollout will stop. ProgressDeadline default + value is "None", meaning the workload applier + will wait for a successful state indefinitely. + ProgressDeadline must be defined in [0-9h]|[0-9m]|[0-9s] + format examples; 2h , 90m , 360s + pattern: ^(([0-9])+[h|m|s])|None$ + type: string + type: object + progressive: + description: Progressive defines required fields for + RolloutStrategy type Progressive + properties: + mandatoryDecisionGroups: + description: List of the decision groups names or + indexes to apply the workload first and fail if + workload did not reach successful state. GroupName + or GroupIndex must match with the decisionGroups + defined in the placement's decisionStrategy + items: + description: MandatoryDecisionGroup set the decision + group name or group index. GroupName is considered + first to select the decisionGroups then GroupIndex. + properties: + groupIndex: + description: GroupIndex of the decision group + should match the placementDecisions label + value with label key cluster.open-cluster-management.io/decision-group-index + format: int32 + type: integer + groupName: + description: GroupName of the decision group + should match the placementDecisions label + value with label key cluster.open-cluster-management.io/decision-group-name + type: string + type: object + type: array + maxConcurrency: + anyOf: + - type: integer + - type: string + description: MaxConcurrency is the max number of + clusters to deploy workload concurrently. The + default value for MaxConcurrency is determined + from the clustersPerDecisionGroup defined in the + placement->DecisionStrategy. + pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ + x-kubernetes-int-or-string: true + maxFailures: + anyOf: + - type: integer + - type: string + default: 0 + description: MaxFailures is a percentage or number + of clusters in the current rollout that can fail + before proceeding to the next rollout. Fail means + the cluster has a failed status or timeout status + (does not reach successful status after ProgressDeadline). + Once the MaxFailures is breached, the rollout + will stop. MaxFailures is only considered for + rollout types Progressive and ProgressivePerGroup. + For Progressive, this is considered over the total + number of clusters. For ProgressivePerGroup, this + is considered according to the size of the current + group. For both Progressive and ProgressivePerGroup, + the MaxFailures does not apply for MandatoryDecisionGroups, + which tolerate no failures. Default is that no + failures are tolerated. + pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ + x-kubernetes-int-or-string: true + minSuccessTime: + default: "0" + description: MinSuccessTime is a "soak" time. In + other words, the minimum amount of time the workload + applier controller will wait from the start of + each rollout before proceeding (assuming a successful + state has been reached and MaxFailures wasn't + breached). MinSuccessTime is only considered for + rollout types Progressive and ProgressivePerGroup. + The default value is 0 meaning the workload applier + proceeds immediately after a successful state + is reached. MinSuccessTime must be defined in + [0-9h]|[0-9m]|[0-9s] format examples; 2h , 90m + , 360s + type: string + progressDeadline: + default: None + description: ProgressDeadline defines how long workload + applier controller will wait for the workload + to reach a successful state in the cluster. If + the workload does not reach a successful state + after ProgressDeadline, will stop waiting and + workload will be treated as "timeout" and be counted + into MaxFailures. Once the MaxFailures is breached, + the rollout will stop. ProgressDeadline default + value is "None", meaning the workload applier + will wait for a successful state indefinitely. + ProgressDeadline must be defined in [0-9h]|[0-9m]|[0-9s] + format examples; 2h , 90m , 360s + pattern: ^(([0-9])+[h|m|s])|None$ + type: string + type: object + progressivePerGroup: + description: ProgressivePerGroup defines required fields + for RolloutStrategy type ProgressivePerGroup + properties: + mandatoryDecisionGroups: + description: List of the decision groups names or + indexes to apply the workload first and fail if + workload did not reach successful state. GroupName + or GroupIndex must match with the decisionGroups + defined in the placement's decisionStrategy + items: + description: MandatoryDecisionGroup set the decision + group name or group index. GroupName is considered + first to select the decisionGroups then GroupIndex. + properties: + groupIndex: + description: GroupIndex of the decision group + should match the placementDecisions label + value with label key cluster.open-cluster-management.io/decision-group-index + format: int32 + type: integer + groupName: + description: GroupName of the decision group + should match the placementDecisions label + value with label key cluster.open-cluster-management.io/decision-group-name + type: string + type: object + type: array + maxFailures: + anyOf: + - type: integer + - type: string + default: 0 + description: MaxFailures is a percentage or number + of clusters in the current rollout that can fail + before proceeding to the next rollout. Fail means + the cluster has a failed status or timeout status + (does not reach successful status after ProgressDeadline). + Once the MaxFailures is breached, the rollout + will stop. MaxFailures is only considered for + rollout types Progressive and ProgressivePerGroup. + For Progressive, this is considered over the total + number of clusters. For ProgressivePerGroup, this + is considered according to the size of the current + group. For both Progressive and ProgressivePerGroup, + the MaxFailures does not apply for MandatoryDecisionGroups, + which tolerate no failures. Default is that no + failures are tolerated. + pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ + x-kubernetes-int-or-string: true + minSuccessTime: + default: "0" + description: MinSuccessTime is a "soak" time. In + other words, the minimum amount of time the workload + applier controller will wait from the start of + each rollout before proceeding (assuming a successful + state has been reached and MaxFailures wasn't + breached). MinSuccessTime is only considered for + rollout types Progressive and ProgressivePerGroup. + The default value is 0 meaning the workload applier + proceeds immediately after a successful state + is reached. MinSuccessTime must be defined in + [0-9h]|[0-9m]|[0-9s] format examples; 2h , 90m + , 360s + type: string + progressDeadline: + default: None + description: ProgressDeadline defines how long workload + applier controller will wait for the workload + to reach a successful state in the cluster. If + the workload does not reach a successful state + after ProgressDeadline, will stop waiting and + workload will be treated as "timeout" and be counted + into MaxFailures. Once the MaxFailures is breached, + the rollout will stop. ProgressDeadline default + value is "None", meaning the workload applier + will wait for a successful state indefinitely. + ProgressDeadline must be defined in [0-9h]|[0-9m]|[0-9s] + format examples; 2h , 90m , 360s + pattern: ^(([0-9])+[h|m|s])|None$ + type: string + type: object + type: + default: All + enum: + - All + - Progressive + - ProgressivePerGroup + type: string + type: object + required: + - name + - namespace + type: object + type: array + x-kubernetes-list-map-keys: + - namespace + - name + x-kubernetes-list-type: map + type: + default: Manual + description: 'Type is the type of the install strategy, it can + be: - Manual: no automatic install - Placements: install to + clusters selected by placements.' + enum: + - Manual + - Placements + type: string + type: object + supportedConfigs: + description: supportedConfigs is a list of configuration types supported + by add-on. An empty list means the add-on does not require configurations. + The default is an empty list + items: + description: ConfigMeta represents a collection of metadata information + for add-on configuration. + properties: + defaultConfig: + description: defaultConfig represents the namespace and name + of the default add-on configuration. In scenario where all + add-ons have a same configuration. + properties: + name: + description: name of the add-on configuration. + minLength: 1 + type: string + namespace: + description: namespace of the add-on configuration. If this + field is not set, the configuration is in the cluster + scope. + type: string + required: + - name + type: object + group: + default: "" + description: group of the add-on configuration. + type: string + resource: + description: resource of the add-on configuration. + minLength: 1 + type: string + required: + - resource type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + x-kubernetes-list-type: map + type: object + status: + description: status represents the current status of cluster management + add-on. + properties: + defaultconfigReferences: + description: defaultconfigReferences is a list of current add-on default + configuration references. + items: + description: DefaultConfigReference is a reference to the current + add-on configuration. This resource is used to record the configuration + resource for the current add-on. properties: - crName: - description: crName is the name of the CR used to configure instances of the managed add-on. This field should be configured if add-on CR have a consistent name across the all of the ManagedCluster instaces. + desiredConfig: + description: desiredConfig record the desired config spec hash. + properties: + name: + description: name of the add-on configuration. + minLength: 1 + type: string + namespace: + description: namespace of the add-on configuration. If this + field is not set, the configuration is in the cluster + scope. + type: string + specHash: + description: spec hash for an add-on configuration. + type: string + required: + - name + type: object + group: + default: "" + description: group of the add-on configuration. type: string - crdName: - description: crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on. + resource: + description: resource of the add-on configuration. + minLength: 1 type: string - lastObservedGeneration: - description: lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon. - type: integer - format: int64 - addOnMeta: - description: addOnMeta is a reference to the metadata information for the add-on. + required: + - resource type: object + type: array + installProgressions: + description: installProgression is a list of current add-on configuration + references per placement. + items: properties: - description: - description: description represents the detailed description of the add-on. + conditions: + description: conditions describe the state of the managed and + monitored components for the operator. + items: + description: "Condition contains details for one aspect of + the current state of this API Resource. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, \n type FooStatus struct{ + // Represents the observations of a foo's current state. + // Known .status.conditions.type are: \"Available\", \"Progressing\", + and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields + }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should + be when the underlying condition changed. If that is + not known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, + if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier + indicating the reason for the condition's last transition. + Producers of specific condition types may define expected + values and meanings for this field, and whether the + values are considered a guaranteed API. The value should + be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + configReferences: + description: configReferences is a list of current add-on configuration + references. + items: + description: InstallConfigReference is a reference to the + current add-on configuration. This resource is used to record + the configuration resource for the current add-on. + properties: + desiredConfig: + description: desiredConfig record the desired config name + and spec hash. + properties: + name: + description: name of the add-on configuration. + minLength: 1 + type: string + namespace: + description: namespace of the add-on configuration. + If this field is not set, the configuration is in + the cluster scope. + type: string + specHash: + description: spec hash for an add-on configuration. + type: string + required: + - name + type: object + group: + default: "" + description: group of the add-on configuration. + type: string + lastAppliedConfig: + description: lastAppliedConfig records the config spec + hash when the all the corresponding ManagedClusterAddOn + are applied successfully. + properties: + name: + description: name of the add-on configuration. + minLength: 1 + type: string + namespace: + description: namespace of the add-on configuration. + If this field is not set, the configuration is in + the cluster scope. + type: string + specHash: + description: spec hash for an add-on configuration. + type: string + required: + - name + type: object + lastKnownGoodConfig: + description: lastKnownGoodConfig records the last known + good config spec hash. For fresh install or rollout + with type UpdateAll or RollingUpdate, the lastKnownGoodConfig + is the same as lastAppliedConfig. For rollout with type + RollingUpdateWithCanary, the lastKnownGoodConfig is + the last successfully applied config spec hash of the + canary placement. + properties: + name: + description: name of the add-on configuration. + minLength: 1 + type: string + namespace: + description: namespace of the add-on configuration. + If this field is not set, the configuration is in + the cluster scope. + type: string + specHash: + description: spec hash for an add-on configuration. + type: string + required: + - name + type: object + resource: + description: resource of the add-on configuration. + minLength: 1 + type: string + required: + - resource + type: object + type: array + name: + description: Name is the name of the placement + minLength: 1 type: string - displayName: - description: displayName represents the name of add-on that will be displayed. + namespace: + description: Namespace is the namespace of the placement + minLength: 1 type: string - status: - description: status represents the current status of cluster management add-on. - type: object - served: true - storage: true - subresources: - status: {} + required: + - name + - namespace + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} status: acceptedNames: kind: "" diff --git a/test/manifest/crd/0000_00_agent.open-cluster-management.io_klusterletaddonconfigs_crd.yaml b/test/manifest/crd/0000_00_agent.open-cluster-management.io_klusterletaddonconfigs_crd.yaml new file mode 100644 index 000000000..e273af468 --- /dev/null +++ b/test/manifest/crd/0000_00_agent.open-cluster-management.io_klusterletaddonconfigs_crd.yaml @@ -0,0 +1,289 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: klusterletaddonconfigs.agent.open-cluster-management.io +spec: + group: agent.open-cluster-management.io + names: + kind: KlusterletAddonConfig + listKind: KlusterletAddonConfigList + plural: klusterletaddonconfigs + singular: klusterletaddonconfig + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: KlusterletAddonConfig is the Schema for the klusterletaddonconfigs + 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 + spec: + description: KlusterletAddonConfigSpec defines the desired state of KlusterletAddonConfig + properties: + applicationManager: + description: ApplicationManagerConfig defines the configurations of + ApplicationManager addon agent. + properties: + enabled: + description: Enabled is the flag to enable/disable the addon. + default is false. + type: boolean + proxyPolicy: + description: |- + ProxyPolicy defines the policy to set proxy for each addon agent. default is Disabled. + Disabled means that the addon agent pods do not configure the proxy env variables. + OCPGlobalProxy means that the addon agent pods use the cluster-wide proxy config of OCP cluster provisioned by ACM. + CustomProxy means that the addon agent pods use the ProxyConfig specified in KlusterletAddonConfig. + enum: + - Disabled + - OCPGlobalProxy + - CustomProxy + type: string + type: object + certPolicyController: + description: CertPolicyControllerConfig defines the configurations + of CertPolicyController addon agent. + properties: + enabled: + description: Enabled is the flag to enable/disable the addon. + default is false. + type: boolean + proxyPolicy: + description: |- + ProxyPolicy defines the policy to set proxy for each addon agent. default is Disabled. + Disabled means that the addon agent pods do not configure the proxy env variables. + OCPGlobalProxy means that the addon agent pods use the cluster-wide proxy config of OCP cluster provisioned by ACM. + CustomProxy means that the addon agent pods use the ProxyConfig specified in KlusterletAddonConfig. + enum: + - Disabled + - OCPGlobalProxy + - CustomProxy + type: string + type: object + clusterLabels: + additionalProperties: + type: string + description: DEPRECATED in release 2.4 and will be removed in the + future since not used anymore. + type: object + clusterName: + description: DEPRECATED in release 2.4 and will be removed in the + future since not used anymore. + minLength: 1 + type: string + clusterNamespace: + description: DEPRECATED in release 2.4 and will be removed in the + future since not used anymore. + minLength: 1 + type: string + iamPolicyController: + description: DEPRECATED in release 2.11 and will be removed in the + future since not used anymore. + properties: + enabled: + description: Enabled is the flag to enable/disable the addon. + default is false. + type: boolean + proxyPolicy: + description: |- + ProxyPolicy defines the policy to set proxy for each addon agent. default is Disabled. + Disabled means that the addon agent pods do not configure the proxy env variables. + OCPGlobalProxy means that the addon agent pods use the cluster-wide proxy config of OCP cluster provisioned by ACM. + CustomProxy means that the addon agent pods use the ProxyConfig specified in KlusterletAddonConfig. + enum: + - Disabled + - OCPGlobalProxy + - CustomProxy + type: string + type: object + policyController: + description: PolicyController defines the configurations of PolicyController + addon agent. + properties: + enabled: + description: Enabled is the flag to enable/disable the addon. + default is false. + type: boolean + proxyPolicy: + description: |- + ProxyPolicy defines the policy to set proxy for each addon agent. default is Disabled. + Disabled means that the addon agent pods do not configure the proxy env variables. + OCPGlobalProxy means that the addon agent pods use the cluster-wide proxy config of OCP cluster provisioned by ACM. + CustomProxy means that the addon agent pods use the ProxyConfig specified in KlusterletAddonConfig. + enum: + - Disabled + - OCPGlobalProxy + - CustomProxy + type: string + type: object + proxyConfig: + description: ProxyConfig defines the cluster-wide proxy configuration + of the OCP managed cluster. + properties: + httpProxy: + description: HTTPProxy is the URL of the proxy for HTTP requests. Empty + means unset and will not result in an env var. + type: string + httpsProxy: + description: HTTPSProxy is the URL of the proxy for HTTPS requests. Empty + means unset and will not result in an env var. + type: string + noProxy: + description: |- + NoProxy is a comma-separated list of hostnames and/or CIDRs for which the proxy should not be used. + Empty means unset and will not result in an env var. + The API Server of Hub cluster should be added here. + And If you scale up workers that are not included in the network defined by the networking.machineNetwork[].cidr + field from the installation configuration, you must add them to this list to prevent connection issues. + type: string + type: object + searchCollector: + description: SearchCollectorConfig defines the configurations of SearchCollector + addon agent. + properties: + enabled: + description: Enabled is the flag to enable/disable the addon. + default is false. + type: boolean + proxyPolicy: + description: |- + ProxyPolicy defines the policy to set proxy for each addon agent. default is Disabled. + Disabled means that the addon agent pods do not configure the proxy env variables. + OCPGlobalProxy means that the addon agent pods use the cluster-wide proxy config of OCP cluster provisioned by ACM. + CustomProxy means that the addon agent pods use the ProxyConfig specified in KlusterletAddonConfig. + enum: + - Disabled + - OCPGlobalProxy + - CustomProxy + type: string + type: object + version: + description: DEPRECATED in release 2.4 and will be removed in the + future since not used anymore. + type: string + required: + - applicationManager + - certPolicyController + - policyController + - searchCollector + type: object + status: + description: KlusterletAddonConfigStatus defines the observed state of + KlusterletAddonConfig + properties: + conditions: + description: Conditions contains condition information for the klusterletAddonConfig + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + ocpGlobalProxy: + description: OCPGlobalProxy is the cluster-wide proxy config of the + OCP cluster provisioned by ACM + properties: + httpProxy: + description: HTTPProxy is the URL of the proxy for HTTP requests. Empty + means unset and will not result in an env var. + type: string + httpsProxy: + description: HTTPSProxy is the URL of the proxy for HTTPS requests. Empty + means unset and will not result in an env var. + type: string + noProxy: + description: |- + NoProxy is a comma-separated list of hostnames and/or CIDRs for which the proxy should not be used. + Empty means unset and will not result in an env var. + The API Server of Hub cluster should be added here. + And If you scale up workers that are not included in the network defined by the networking.machineNetwork[].cidr + field from the installation configuration, you must add them to this list to prevent connection issues. + type: string + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/test/manifest/crd/0000_01_addon.open-cluster-management.io_managedclusteraddons.crd.yaml b/test/manifest/crd/0000_01_addon.open-cluster-management.io_managedclusteraddons.crd.yaml index 614048d1e..be567246e 100644 --- a/test/manifest/crd/0000_01_addon.open-cluster-management.io_managedclusteraddons.crd.yaml +++ b/test/manifest/crd/0000_01_addon.open-cluster-management.io_managedclusteraddons.crd.yaml @@ -12,180 +12,237 @@ spec: scope: Namespaced preserveUnknownFields: false versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Available")].status - name: Available - type: string - - jsonPath: .status.conditions[?(@.type=="Degraded")].status - name: Degraded - type: string - - jsonPath: .status.conditions[?(@.type=="Progressing")].status - name: Progressing - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: ManagedClusterAddOn is the Custom Resource object which holds the current state of an add-on. This object is used by add-on operators to convey their state. This resource should be created in the ManagedCluster namespace. - type: object - required: - - spec - 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 - spec: - description: spec holds configuration that could apply to any operator. - type: object - properties: - installNamespace: - description: installNamespace is the namespace on the managed cluster to install the addon agent. If it is not set, open-cluster-management-agent-addon namespace is used to install the addon agent. - type: string - maxLength: 63 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - status: - description: status holds the information about the state of an operator. It is consistent with status information across the Kubernetes ecosystem. - type: object - properties: - addOnConfiguration: - description: addOnConfiguration is a reference to configuration information for the add-on. This resource is use to locate the configuration resource for the add-on. + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Available")].status + name: Available + type: string + - jsonPath: .status.conditions[?(@.type=="Degraded")].status + name: Degraded + type: string + - jsonPath: .status.conditions[?(@.type=="Progressing")].status + name: Progressing + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ManagedClusterAddOn is the Custom Resource object which holds + the current state of an add-on. This object is used by add-on operators + to convey their state. This resource should be created in the ManagedCluster + namespace. + type: object + required: + - spec + 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 + spec: + description: spec holds configuration that could apply to any operator. + type: object + properties: + installNamespace: + description: installNamespace is the namespace on the managed cluster + to install the addon agent. If it is not set, open-cluster-management-agent-addon + namespace is used to install the addon agent. + type: string + maxLength: 63 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + status: + description: status holds the information about the state of an operator. It + is consistent with status information across the Kubernetes ecosystem. + type: object + properties: + addOnConfiguration: + description: addOnConfiguration is a reference to configuration information + for the add-on. This resource is use to locate the configuration + resource for the add-on. + type: object + properties: + crName: + description: crName is the name of the CR used to configure instances + of the managed add-on. This field should be configured if add-on + CR have a consistent name across the all of the ManagedCluster + instaces. + type: string + crdName: + description: crdName is the name of the CRD used to configure + instances of the managed add-on. This field should be configured + if the add-on have a CRD that controls the configuration of + the add-on. + type: string + addOnMeta: + description: addOnMeta is a reference to the metadata information + for the add-on. This should be same as the addOnMeta for the corresponding + ClusterManagementAddOn resource. + type: object + properties: + description: + description: description represents the detailed description of + the add-on. + type: string + displayName: + description: displayName represents the name of add-on that will + be displayed. + type: string + conditions: + description: conditions describe the state of the managed and monitored + components for the operator. + type: array + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: + \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // +listMapKey=type + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" type: object + required: + - lastTransitionTime + - message + - reason + - status + - type properties: - crName: - description: crName is the name of the CR used to configure instances of the managed add-on. This field should be configured if add-on CR have a consistent name across the all of the ManagedCluster instaces. + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. type: string - crdName: - description: crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on. + format: date-time + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. type: string - lastObservedGeneration: - description: lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon. + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. type: integer format: int64 - addOnMeta: - description: addOnMeta is a reference to the metadata information for the add-on. This should be same as the addOnMeta for the corresponding ClusterManagementAddOn resource. - type: object - properties: - description: - description: description represents the detailed description of the add-on. + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. type: string - displayName: - description: displayName represents the name of add-on that will be displayed. + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) type: string - conditions: - description: conditions describe the state of the managed and monitored components for the operator. - type: array - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - type: object - required: - - lastTransitionTime - - message - - reason - - status - - type - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - type: string - format: date-time - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - type: string - maxLength: 32768 - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - type: integer - format: int64 - minimum: 0 - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - type: string - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - status: - description: status of the condition, one of True, False, Unknown. - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - type: string - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - healthCheck: - description: healthCheck indicates how to check the healthiness status of the current addon. It should be set by each addon implementation, by default, the lease mode will be used. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + registrations: + description: registrations is the conifigurations for the addon agent + to register to hub. It should be set by each addon controller on + hub to define how the addon agent on managedcluster is registered. + With the registration defined, The addon agent can access to kube + apiserver with kube style API or other endpoints on hub cluster + with client certificate authentication. A csr will be created per + registration configuration. If more than one registrationConfig + is defined, a csr will be created for each registration configuration. + It is not allowed that multiple registrationConfigs have the same + signer name. After the csr is approved on the hub cluster, the klusterlet + agent will create a secret in the installNamespace for the registrationConfig. + If the signerName is "kubernetes.io/kube-apiserver-client", the + secret name will be "{addon name}-hub-kubeconfig" whose contents + includes key/cert and kubeconfig. Otherwise, the secret name will + be "{addon name}-{signer name}-client-cert" whose contents includes + key/cert. + type: array + items: + description: RegistrationConfig defines the configuration of the + addon agent to register to hub. The Klusterlet agent will create + a csr for the addon agent with the registrationConfig. type: object properties: - mode: - description: mode indicates which mode will be used to check the healthiness status of the addon. + signerName: + description: signerName is the name of signer that addon agent + will use to create csr. type: string - default: Lease - enum: - - Lease - - Customized - registrations: - description: registrations is the conifigurations for the addon agent to register to hub. It should be set by each addon controller on hub to define how the addon agent on managedcluster is registered. With the registration defined, The addon agent can access to kube apiserver with kube style API or other endpoints on hub cluster with client certificate authentication. A csr will be created per registration configuration. If more than one registrationConfig is defined, a csr will be created for each registration configuration. It is not allowed that multiple registrationConfigs have the same signer name. After the csr is approved on the hub cluster, the klusterlet agent will create a secret in the installNamespace for the registrationConfig. If the signerName is "kubernetes.io/kube-apiserver-client", the secret name will be "{addon name}-hub-kubeconfig" whose contents includes key/cert and kubeconfig. Otherwise, the secret name will be "{addon name}-{signer name}-client-cert" whose contents includes key/cert. - type: array - items: - description: RegistrationConfig defines the configuration of the addon agent to register to hub. The Klusterlet agent will create a csr for the addon agent with the registrationConfig. - type: object - properties: - signerName: - description: signerName is the name of signer that addon agent will use to create csr. - type: string - maxLength: 571 - minLength: 5 - subject: - description: "subject is the user subject of the addon agent to be registered to the hub. If it is not set, the addon agent will have the default subject \"subject\": { \t\"user\": \"system:open-cluster-management:addon:{addonName}:{clusterName}:{agentName}\", \t\"groups: [\"system:open-cluster-management:addon\", \"system:open-cluster-management:addon:{addonName}\", \"system:authenticated\"] }" - type: object - properties: - groups: - description: groups is the user group of the addon agent. - type: array - items: - type: string - organizationUnit: - description: organizationUnit is the ou of the addon agent - type: array - items: - type: string - user: - description: user is the user name of the addon agent. + maxLength: 571 + minLength: 5 + subject: + description: "subject is the user subject of the addon agent + to be registered to the hub. If it is not set, the addon agent + will have the default subject \"subject\": { \t\"user\": \"system:open-cluster-management:addon:{addonName}:{clusterName}:{agentName}\", + \t\"groups: [\"system:open-cluster-management:addon\", \"system:open-cluster-management:addon:{addonName}\", + \"system:authenticated\"] }" + type: object + properties: + groups: + description: groups is the user group of the addon agent. + type: array + items: + type: string + organizationUnit: + description: organizationUnit is the ou of the addon agent + type: array + items: type: string - relatedObjects: - description: 'relatedObjects is a list of objects that are "interesting" or related to this operator. Common uses are: 1. the detailed resource driving the operator 2. operator namespaces 3. operand namespaces 4. related ClusterManagementAddon resource' - type: array - items: - description: ObjectReference contains enough information to let you inspect or modify the referred object. - type: object - required: - - group - - name - - resource - properties: - group: - description: group of the referent. - type: string - name: - description: name of the referent. - type: string - namespace: - description: namespace of the referent. - type: string - resource: - description: resource of the referent. - type: string - served: true - storage: true - subresources: - status: {} + user: + description: user is the user name of the addon agent. + type: string + relatedObjects: + description: 'relatedObjects is a list of objects that are "interesting" + or related to this operator. Common uses are: 1. the detailed resource + driving the operator 2. operator namespaces 3. operand namespaces + 4. related ClusterManagementAddon resource' + type: array + items: + description: ObjectReference contains enough information to let + you inspect or modify the referred object. + type: object + required: + - group + - name + - resource + properties: + group: + description: group of the referent. + type: string + name: + description: name of the referent. + type: string + resource: + description: resource of the referent. + type: string + served: true + storage: true + subresources: + status: {} status: acceptedNames: kind: "" diff --git a/test/manifest/crd/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml b/test/manifest/crd/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml new file mode 100644 index 000000000..ee8f797a8 --- /dev/null +++ b/test/manifest/crd/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml @@ -0,0 +1,180 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: addondeploymentconfigs.addon.open-cluster-management.io +spec: + group: addon.open-cluster-management.io + names: + kind: AddOnDeploymentConfig + listKind: AddOnDeploymentConfigList + plural: addondeploymentconfigs + singular: addondeploymentconfig + preserveUnknownFields: false + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: AddOnDeploymentConfig represents a configuration to customize + the deployments of an add-on. For example, you can specify the NodePlacement + to control the scheduling of the add-on agents. + 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 + spec: + description: spec represents a desired configuration for an add-on. + properties: + agentInstallNamespace: + default: open-cluster-management-agent-addon + description: AgentInstallNamespace is the namespace where the add-on + agent should be installed on the managed cluster. + maxLength: 63 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + customizedVariables: + description: CustomizedVariables is a list of name-value variables + for the current add-on deployment. The add-on implementation can + use these variables to render its add-on deployment. The default + is an empty list. + items: + description: CustomizedVariable represents a customized variable + for add-on deployment. + properties: + name: + description: Name of this variable. + maxLength: 255 + pattern: ^[a-zA-Z_][_a-zA-Z0-9]*$ + type: string + value: + description: Value of this variable. + maxLength: 1024 + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodePlacement: + description: NodePlacement enables explicit control over the scheduling + of the add-on agents on the managed cluster. All add-on agent pods + are expected to comply with this node placement. If the placement + is nil, the placement is not specified, it will be omitted. If the + placement is an empty object, the placement will match all nodes + and tolerate nothing. + properties: + nodeSelector: + additionalProperties: + type: string + description: NodeSelector defines which Nodes the Pods are scheduled + on. If the selector is an empty list, it will match all nodes. + The default is an empty list. + type: object + tolerations: + description: Tolerations is attached by pods to tolerate any taint + that matches the triple using the matching + operator . If the tolerations is an empty list, it + will tolerate nothing. The default is an empty list. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, allowed + values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies + to. Empty means match all taint keys. If the key is empty, + operator must be Exists; this combination means to match + all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to + the value. Valid operators are Exists and Equal. Defaults + to Equal. Exists is equivalent to wildcard for value, + so that a pod can tolerate all taints of a particular + category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the taint + forever (do not evict). Zero and negative values will + be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + type: object + proxyConfig: + description: ProxyConfig holds proxy settings for add-on agent on + the managed cluster. Empty means no proxy settings is available. + properties: + caBundle: + description: CABundle is a CA certificate bundle to verify the + proxy server. And it's only useful when HTTPSProxy is set and + a HTTPS proxy server is specified. + format: byte + type: string + httpProxy: + description: HTTPProxy is the URL of the proxy for HTTP requests + type: string + httpsProxy: + description: HTTPSProxy is the URL of the proxy for HTTPS requests + type: string + noProxy: + description: NoProxy is a comma-separated list of hostnames and/or + CIDRs and/or IPs for which the proxy should not be used. + type: string + type: object + registries: + description: "Registries describes how to override images used by + the addon agent on the managed cluster. the following example will + override image \"quay.io/open-cluster-management/addon-agent\" to + \"quay.io/ocm/addon-agent\" when deploying the addon agent \n registries: + - source: quay.io/open-cluster-management/addon-agent mirror: quay.io/ocm/addon-agent" + items: + description: ImageMirror describes how to mirror images from a source + properties: + mirror: + description: Mirror is the mirrored registry of the Source. + Will be ignored if Mirror is empty. + type: string + source: + description: Source is the source registry. All image registries + will be replaced by Mirror if Source is empty. + type: string + required: + - mirror + type: object + type: array + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: []