From 0b204cb9a995c5886285794b65ec5a261c239df4 Mon Sep 17 00:00:00 2001 From: haoqing0110 Date: Fri, 19 Jul 2024 07:39:10 +0000 Subject: [PATCH] sync between ManagedCluster and cluster inventory API Signed-off-by: haoqing0110 --- .../templates/cluster_role.yaml | 6 + .../config/rbac/cluster_role.yaml | 6 + ...cluster-manager.clusterserviceversion.yaml | 21 +- .../klusterlet.clusterserviceversion.yaml | 2 +- go.mod | 5 +- go.sum | 8 +- ...icluster.x-k8s.io_clusterprofiles.crd.yaml | 185 ++++++++++++ ...r-manager-clusterprofiles-clusterrole.yaml | 12 + ...er-clusterprofiles-clusterrolebinding.yaml | 12 + manifests/config.go | 1 + .../clustermanager_controller.go | 1 + .../clustermanager_crd_reconcile.go | 19 +- .../clustermanager_hub_reconcile.go | 19 ++ .../hub/clusterprofile/controller.go | 175 ++++++++++++ .../hub/clusterprofile/controller_test.go | 263 ++++++++++++++++++ pkg/registration/hub/clusterprofile/doc.go | 3 + pkg/registration/hub/manager.go | 31 ++- .../operator/clustermanager_hosted_test.go | 130 ++++++++- .../operator/clustermanager_test.go | 130 ++++++++- vendor/github.com/go-openapi/swag/util.go | 16 +- vendor/modules.txt | 17 +- .../sigs.k8s.io/cluster-inventory-api/LICENSE | 201 +++++++++++++ .../apis/v1alpha1/clusterprofile_types.go | 152 ++++++++++ .../apis/v1alpha1/groupversion_info.go | 58 ++++ .../apis/v1alpha1/zz_generated.deepcopy.go | 174 ++++++++++++ .../client/clientset/versioned/clientset.go | 119 ++++++++ .../versioned/fake/clientset_generated.go | 84 ++++++ .../client/clientset/versioned/fake/doc.go | 19 ++ .../clientset/versioned/fake/register.go | 55 ++++ .../client/clientset/versioned/scheme/doc.go | 19 ++ .../clientset/versioned/scheme/register.go | 55 ++++ .../typed/apis/v1alpha1/apis_client.go | 106 +++++++ .../typed/apis/v1alpha1/clusterprofile.go | 194 +++++++++++++ .../versioned/typed/apis/v1alpha1/doc.go | 19 ++ .../versioned/typed/apis/v1alpha1/fake/doc.go | 19 ++ .../apis/v1alpha1/fake/fake_apis_client.go | 39 +++ .../apis/v1alpha1/fake/fake_clusterprofile.go | 140 ++++++++++ .../apis/v1alpha1/generated_expansion.go | 20 ++ .../externalversions/apis/interface.go | 45 +++ .../apis/v1alpha1/clusterprofile.go | 89 ++++++ .../apis/v1alpha1/interface.go | 44 +++ .../informers/externalversions/factory.go | 260 +++++++++++++++++ .../informers/externalversions/generic.go | 61 ++++ .../internalinterfaces/factory_interfaces.go | 39 +++ .../listers/apis/v1alpha1/clusterprofile.go | 98 +++++++ .../apis/v1alpha1/expansion_generated.go | 26 ++ 46 files changed, 3178 insertions(+), 19 deletions(-) create mode 100644 manifests/cluster-manager/hub/0000_00_multicluster.x-k8s.io_clusterprofiles.crd.yaml create mode 100644 manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrole.yaml create mode 100644 manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrolebinding.yaml create mode 100644 pkg/registration/hub/clusterprofile/controller.go create mode 100644 pkg/registration/hub/clusterprofile/controller_test.go create mode 100644 pkg/registration/hub/clusterprofile/doc.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/LICENSE create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/clusterprofile_types.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/groupversion_info.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/clientset.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/clientset_generated.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/doc.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/register.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/doc.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/register.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/clusterprofile.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/doc.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_clusterprofile.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/interface.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/clusterprofile.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/interface.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/factory.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/generic.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/clusterprofile.go create mode 100644 vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/expansion_generated.go diff --git a/deploy/cluster-manager/chart/cluster-manager/templates/cluster_role.yaml b/deploy/cluster-manager/chart/cluster-manager/templates/cluster_role.yaml index 6dd0a9eb1..7271c81bd 100644 --- a/deploy/cluster-manager/chart/cluster-manager/templates/cluster_role.yaml +++ b/deploy/cluster-manager/chart/cluster-manager/templates/cluster_role.yaml @@ -144,3 +144,9 @@ rules: - apiGroups: ["config.openshift.io"] resources: ["infrastructures"] verbs: ["get"] +- apiGroups: ["multicluster.x-k8s.io"] + resources: ["clusterprofiles"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: ["multicluster.x-k8s.io"] + resources: ["clusterprofiles/status"] + verbs: ["update", "patch"] diff --git a/deploy/cluster-manager/config/rbac/cluster_role.yaml b/deploy/cluster-manager/config/rbac/cluster_role.yaml index 3d74b1cbf..a902a7cb2 100644 --- a/deploy/cluster-manager/config/rbac/cluster_role.yaml +++ b/deploy/cluster-manager/config/rbac/cluster_role.yaml @@ -146,3 +146,9 @@ rules: - apiGroups: ["config.openshift.io"] resources: ["infrastructures"] verbs: ["get"] +- apiGroups: ["multicluster.x-k8s.io"] + resources: ["clusterprofiles"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: ["multicluster.x-k8s.io"] + resources: ["clusterprofiles/status"] + verbs: ["update", "patch"] diff --git a/deploy/cluster-manager/olm-catalog/latest/manifests/cluster-manager.clusterserviceversion.yaml b/deploy/cluster-manager/olm-catalog/latest/manifests/cluster-manager.clusterserviceversion.yaml index 07fd5dcbe..cb6f2ae0d 100644 --- a/deploy/cluster-manager/olm-catalog/latest/manifests/cluster-manager.clusterserviceversion.yaml +++ b/deploy/cluster-manager/olm-catalog/latest/manifests/cluster-manager.clusterserviceversion.yaml @@ -59,7 +59,7 @@ metadata: categories: Integration & Delivery,OpenShift Optional certified: "false" containerImage: quay.io/open-cluster-management/registration-operator:latest - createdAt: "2024-10-08T08:24:18Z" + createdAt: "2024-10-11T02:21:31Z" description: Manages the installation and upgrade of the ClusterManager. operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 @@ -506,6 +506,25 @@ spec: - infrastructures verbs: - get + - apiGroups: + - multicluster.x-k8s.io + resources: + - clusterprofiles + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - multicluster.x-k8s.io + resources: + - clusterprofiles/status + verbs: + - update + - patch serviceAccountName: cluster-manager deployments: - label: diff --git a/deploy/klusterlet/olm-catalog/latest/manifests/klusterlet.clusterserviceversion.yaml b/deploy/klusterlet/olm-catalog/latest/manifests/klusterlet.clusterserviceversion.yaml index e8182362c..d34b2db76 100644 --- a/deploy/klusterlet/olm-catalog/latest/manifests/klusterlet.clusterserviceversion.yaml +++ b/deploy/klusterlet/olm-catalog/latest/manifests/klusterlet.clusterserviceversion.yaml @@ -31,7 +31,7 @@ metadata: categories: Integration & Delivery,OpenShift Optional certified: "false" containerImage: quay.io/open-cluster-management/registration-operator:latest - createdAt: "2024-10-08T08:24:18Z" + createdAt: "2024-10-11T02:21:31Z" description: Manages the installation and upgrade of the Klusterlet. operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 diff --git a/go.mod b/go.mod index 71094f5d7..b4c5e5412 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module open-cluster-management.io/ocm go 1.22.5 require ( - github.com/davecgh/go-spew v1.1.1 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/evanphx/json-patch v5.9.0+incompatible github.com/ghodss/yaml v1.0.0 github.com/google/go-cmp v0.6.0 @@ -35,6 +35,7 @@ require ( open-cluster-management.io/addon-framework v0.10.1-0.20241009100235-11aa520f541f open-cluster-management.io/api v0.14.1-0.20241008081048-f6c658202790 open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866 + sigs.k8s.io/cluster-inventory-api v0.0.0-20240730014211-ef0154379848 sigs.k8s.io/controller-runtime v0.18.5 sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 sigs.k8s.io/yaml v1.4.0 @@ -72,7 +73,7 @@ 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-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect diff --git a/go.sum b/go.sum index c6ae90643..d0fb73908 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,9 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= @@ -93,8 +94,9 @@ github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -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-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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -447,6 +449,8 @@ open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866 h1:nxYrS open-cluster-management.io/sdk-go v0.14.1-0.20240918072645-225dcf1b6866/go.mod h1:jCyXPY900UK1n4xwUBWSz27s7lcXN/fhIDF6xu3jIHw= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= +sigs.k8s.io/cluster-inventory-api v0.0.0-20240730014211-ef0154379848 h1:WYPi2PdQyZwZkHG648v2jQl6deyCgyjJ0fkLYgUJ618= +sigs.k8s.io/cluster-inventory-api v0.0.0-20240730014211-ef0154379848/go.mod h1:/aN4e7RWOMHgT4xAjCNkV4YFcpKfpZCeumMIL7S+KNM= sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= sigs.k8s.io/controller-runtime v0.18.5/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/manifests/cluster-manager/hub/0000_00_multicluster.x-k8s.io_clusterprofiles.crd.yaml b/manifests/cluster-manager/hub/0000_00_multicluster.x-k8s.io_clusterprofiles.crd.yaml new file mode 100644 index 000000000..f8883b17d --- /dev/null +++ b/manifests/cluster-manager/hub/0000_00_multicluster.x-k8s.io_clusterprofiles.crd.yaml @@ -0,0 +1,185 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: clusterprofiles.multicluster.x-k8s.io +spec: + group: multicluster.x-k8s.io + names: + kind: ClusterProfile + listKind: ClusterProfileList + plural: clusterprofiles + singular: clusterprofile + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterProfile represents a single cluster in a multi-cluster + deployment. + 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: ClusterProfileSpec defines the desired state of ClusterProfile. + properties: + clusterManager: + description: ClusterManager defines which cluster manager owns this + ClusterProfile resource + properties: + name: + description: Name defines the name of the cluster manager + type: string + required: + - name + type: object + x-kubernetes-validations: + - message: ClusterManager is immutable + rule: self == oldSelf + displayName: + description: DisplayName defines a human-readable name of the ClusterProfile + type: string + required: + - clusterManager + type: object + status: + description: ClusterProfileStatus defines the observed state of ClusterProfile. + properties: + conditions: + description: Conditions contains the different condition statuses + for this cluster. + 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 + properties: + description: |- + Properties defines name/value pairs to represent properties of a cluster. + It could be a collection of ClusterProperty (KEP-2149) resources, + but could also be info based on other implementations. + The names of the properties can be predefined names from ClusterProperty resources + and is allowed to be customized by different cluster managers. + items: + description: |- + Property defines a name/value pair to represent a property of a cluster. + It could be a ClusterProperty (KEP-2149) resource, + but could also be info based on other implementations. + The name of the property can be predefined name from a ClusterProperty resource + and is allowed to be customized by different cluster managers. + This property can store various configurable details and metrics of a cluster, + which may include information such as the number of nodes, total and free CPU, + and total and free memory, among other potential attributes. + properties: + name: + description: |- + Name is the name of a property resource on cluster. It's a well-known + or customized name to identify the property. + maxLength: 253 + minLength: 1 + type: string + value: + description: Value is a property-dependent string + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + type: array + version: + description: Version defines the version information of the cluster. + properties: + kubernetes: + description: Kubernetes is the kubernetes version of the cluster. + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrole.yaml b/manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrole.yaml new file mode 100644 index 000000000..1f13a4c3a --- /dev/null +++ b/manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrole.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: open-cluster-management:{{ .ClusterManagerName }}-clusterprofile:controller +rules: +# Allow hub to manage clusterprofile +- apiGroups: ["multicluster.x-k8s.io"] + resources: ["clusterprofiles"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: ["multicluster.x-k8s.io"] + resources: ["clusterprofiles/status"] + verbs: ["update", "patch"] diff --git a/manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrolebinding.yaml b/manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrolebinding.yaml new file mode 100644 index 000000000..ab70b13e6 --- /dev/null +++ b/manifests/cluster-manager/hub/cluster-manager-clusterprofiles-clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: open-cluster-management:{{ .ClusterManagerName }}-clusterprofile:controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: open-cluster-management:{{ .ClusterManagerName }}-clusterprofile:controller +subjects: +- kind: ServiceAccount + namespace: {{ .ClusterManagerNamespace }} + name: registration-controller-sa diff --git a/manifests/config.go b/manifests/config.go index 9828407ec..023e24e79 100644 --- a/manifests/config.go +++ b/manifests/config.go @@ -19,6 +19,7 @@ type HubConfig struct { AddOnManagerImage string AddOnManagerEnabled bool MWReplicaSetEnabled bool + ClusterProfileEnabled bool CloudEventsDriverEnabled bool WorkDriver string AutoApproveUsers string diff --git a/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_controller.go b/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_controller.go index 1cd2d6593..0f3aabfff 100644 --- a/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_controller.go +++ b/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_controller.go @@ -183,6 +183,7 @@ func (n *clusterManagerController) sync(ctx context.Context, controllerContext f } config.RegistrationFeatureGates, registrationFeatureMsgs = helpers.ConvertToFeatureGateFlags("Registration", registrationFeatureGates, ocmfeature.DefaultHubRegistrationFeatureGates) + config.ClusterProfileEnabled = helpers.FeatureGateEnabled(registrationFeatureGates, ocmfeature.DefaultHubRegistrationFeatureGates, ocmfeature.ClusterProfile) var workFeatureGates []operatorapiv1.FeatureGate if clusterManager.Spec.WorkConfiguration != nil { diff --git a/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_crd_reconcile.go b/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_crd_reconcile.go index 4c83c0174..a8bfdb939 100644 --- a/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_crd_reconcile.go +++ b/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_crd_reconcile.go @@ -50,6 +50,11 @@ var ( "cluster-manager/hub/0000_03_clusters.open-cluster-management.io_placementdecisions.crd.yaml", "cluster-manager/hub/0000_05_clusters.open-cluster-management.io_addonplacementscores.crd.yaml", } + + hubClusterProfileCRDResourceFiles = []string{ + // clusterprofile crd + "cluster-manager/hub/0000_00_multicluster.x-k8s.io_clusterprofiles.crd.yaml", + } ) type crdReconcile struct { @@ -68,6 +73,16 @@ func (c *crdReconcile) reconcile(ctx context.Context, cm *operatorapiv1.ClusterM crdmanager.EqualV1, ) + // CRD resource files to deploy + hubDeployCRDResources := hubCRDResourceFiles + + // If featuregate ClusterProfile is enabled, include the ClusterProfile CRD. + // The ClusterProfile CRD will not be removed when featuregate is disabled (same behavior as other crds) + // and will not be cleaned when ClusterManager is deleting since the CRD might be used by other projects. + if config.ClusterProfileEnabled { + hubDeployCRDResources = append(hubDeployCRDResources, hubClusterProfileCRDResourceFiles...) + } + if err := crdManager.Apply(ctx, func(name string) ([]byte, error) { template, err := manifests.ClusterManagerManifestFiles.ReadFile(name) @@ -78,7 +93,7 @@ func (c *crdReconcile) reconcile(ctx context.Context, cm *operatorapiv1.ClusterM helpers.SetRelatedResourcesStatusesWithObj(&cm.Status.RelatedResources, objData) return objData, nil }, - hubCRDResourceFiles...); err != nil { + hubDeployCRDResources...); err != nil { meta.SetStatusCondition(&cm.Status.Conditions, metav1.Condition{ Type: operatorapiv1.ConditionClusterManagerApplied, Status: metav1.ConditionFalse, @@ -109,6 +124,8 @@ func (c *crdReconcile) clean(ctx context.Context, cm *operatorapiv1.ClusterManag return cm, reconcileContinue, nil } + // Only the crds list in the hubCRDResourceFiles will be cleaned. + // Never clean the ClusterProfile CRD since it might be used by other projects. if err := crdManager.Clean(ctx, c.skipRemoveCRDs, func(name string) ([]byte, error) { template, err := manifests.ClusterManagerManifestFiles.ReadFile(name) diff --git a/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_hub_reconcile.go b/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_hub_reconcile.go index a2a736770..3da93dd09 100644 --- a/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_hub_reconcile.go +++ b/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller/clustermanager_hub_reconcile.go @@ -62,6 +62,12 @@ var ( "cluster-manager/hub/cluster-manager-addon-manager-serviceaccount.yaml", } + clusterProfileResourceFiles = []string{ + // clusterprofile + "cluster-manager/hub/cluster-manager-clusterprofiles-clusterrole.yaml", + "cluster-manager/hub/cluster-manager-clusterprofiles-clusterrolebinding.yaml", + } + // The hubHostedWebhookServiceFiles should only be deployed on the hub cluster when the deploy mode is hosted. hubDefaultWebhookServiceFiles = []string{ "cluster-manager/hub/cluster-manager-registration-webhook-service.yaml", @@ -101,6 +107,14 @@ func (c *hubReconcile) reconcile(ctx context.Context, cm *operatorapiv1.ClusterM } } + // If ClusterProfile is not enabled, remove related resources + if !config.ClusterProfileEnabled { + _, _, err := cleanResources(ctx, c.hubKubeClient, cm, config, clusterProfileResourceFiles...) + if err != nil { + return cm, reconcileStop, err + } + } + hubResources := getHubResources(cm.Spec.DeployOption.Mode, config) var appliedErrs []error @@ -156,6 +170,11 @@ func getHubResources(mode operatorapiv1.InstallMode, config manifests.HubConfig) if config.MWReplicaSetEnabled { hubResources = append(hubResources, mwReplicaSetResourceFiles...) } + + if config.ClusterProfileEnabled { + hubResources = append(hubResources, clusterProfileResourceFiles...) + } + // the hubHostedWebhookServiceFiles are only used in hosted mode if helpers.IsHosted(mode) { hubResources = append(hubResources, hubHostedWebhookServiceFiles...) diff --git a/pkg/registration/hub/clusterprofile/controller.go b/pkg/registration/hub/clusterprofile/controller.go new file mode 100644 index 000000000..4a9721aa5 --- /dev/null +++ b/pkg/registration/hub/clusterprofile/controller.go @@ -0,0 +1,175 @@ +package clusterprofile + +import ( + "context" + + "github.com/openshift/library-go/pkg/controller/factory" + "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + cpv1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" + cpclientset "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned" + cpinformerv1alpha1 "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1" + cplisterv1alpha1 "sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1" + + informerv1 "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1" + listerv1 "open-cluster-management.io/api/client/cluster/listers/cluster/v1" + v1 "open-cluster-management.io/api/cluster/v1" + v1beta2 "open-cluster-management.io/api/cluster/v1beta2" + "open-cluster-management.io/sdk-go/pkg/patcher" + + "open-cluster-management.io/ocm/pkg/common/queue" +) + +const ( + ClusterProfileManagerName = "open-cluster-management" + ClusterProfileNamespace = "open-cluster-management" +) + +// clusterProfileController reconciles instances of ClusterProfile on the hub. +type clusterProfileController struct { + clusterLister listerv1.ManagedClusterLister + clusterProfileClient cpclientset.Interface + clusterProfileLister cplisterv1alpha1.ClusterProfileLister + patcher patcher.Patcher[*cpv1alpha1.ClusterProfile, cpv1alpha1.ClusterProfileSpec, cpv1alpha1.ClusterProfileStatus] + eventRecorder events.Recorder +} + +// NewClusterProfileController creates a new managed cluster controller +func NewClusterProfileController( + clusterInformer informerv1.ManagedClusterInformer, + clusterProfileClient cpclientset.Interface, + clusterProfileInformer cpinformerv1alpha1.ClusterProfileInformer, + recorder events.Recorder) factory.Controller { + c := &clusterProfileController{ + clusterLister: clusterInformer.Lister(), + clusterProfileClient: clusterProfileClient, + clusterProfileLister: clusterProfileInformer.Lister(), + patcher: patcher.NewPatcher[ + *cpv1alpha1.ClusterProfile, cpv1alpha1.ClusterProfileSpec, cpv1alpha1.ClusterProfileStatus]( + clusterProfileClient.ApisV1alpha1().ClusterProfiles(ClusterProfileNamespace)), + eventRecorder: recorder.WithComponentSuffix("cluster-profile-controller"), + } + + return factory.New(). + WithInformersQueueKeysFunc(queue.QueueKeyByMetaName, clusterInformer.Informer(), clusterProfileInformer.Informer()). + WithSync(c.sync). + ToController("ClusterProfileController", recorder) +} + +func (c *clusterProfileController) sync(ctx context.Context, syncCtx factory.SyncContext) error { + managedClusterName := syncCtx.QueueKey() + logger := klog.FromContext(ctx) + logger.V(4).Info("Reconciling Cluster", "ClusterName", managedClusterName) + + managedCluster, err := c.clusterLister.Get(managedClusterName) + if errors.IsNotFound(err) { + // Spoke cluster not found, could have been deleted, do nothing. + return nil + } + if err != nil { + return err + } + + clusterProfile, err := c.clusterProfileLister.ClusterProfiles(ClusterProfileNamespace).Get(managedClusterName) + + // if the managed cluster is deleting, delete the clusterprofile as well. + if !managedCluster.DeletionTimestamp.IsZero() { + if errors.IsNotFound(err) { + return nil + } + err = c.clusterProfileClient.ApisV1alpha1().ClusterProfiles(ClusterProfileNamespace).Delete(ctx, managedClusterName, metav1.DeleteOptions{}) + return err + } + + // create cluster profile if not found + if errors.IsNotFound(err) { + clusterProfile = &cpv1alpha1.ClusterProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: managedClusterName, + Labels: map[string]string{cpv1alpha1.LabelClusterManagerKey: ClusterProfileManagerName}, + }, + Spec: cpv1alpha1.ClusterProfileSpec{ + DisplayName: managedClusterName, + ClusterManager: cpv1alpha1.ClusterManager{ + Name: ClusterProfileManagerName, + }, + }, + } + _, err = c.clusterProfileClient.ApisV1alpha1().ClusterProfiles(ClusterProfileNamespace).Create(ctx, clusterProfile, metav1.CreateOptions{}) + return err + } + if err != nil { + return err + } + + // return if not managed by ocm + if clusterProfile.Spec.ClusterManager.Name != ClusterProfileManagerName { + logger.Info("Not managed by open-cluster-management, skipping", "ClusterName", managedClusterName) + return nil + } + + newClusterProfile := clusterProfile.DeepCopy() + + // sync required labels + mclLabels := managedCluster.GetLabels() + mclSetLabel := mclLabels[v1beta2.ClusterSetLabel] + // The value of label "x-k8s.io/cluster-manager" MUST be the same as the name of the cluster manager. + requiredLabels := map[string]string{ + cpv1alpha1.LabelClusterManagerKey: newClusterProfile.Spec.ClusterManager.Name, + cpv1alpha1.LabelClusterSetKey: mclSetLabel, + } + modified := false + resourcemerge.MergeMap(&modified, &newClusterProfile.Labels, requiredLabels) + + // patch labels + if modified { + _, err := c.patcher.PatchLabelAnnotations(ctx, newClusterProfile, newClusterProfile.ObjectMeta, clusterProfile.ObjectMeta) + return err + } + + // sync status.version.kubernetes + newClusterProfile.Status.Version.Kubernetes = managedCluster.Status.Version.Kubernetes + + // sync status.properties + cpProperties := []cpv1alpha1.Property{} + for _, v := range managedCluster.Status.ClusterClaims { + cpProperties = append(cpProperties, cpv1alpha1.Property{Name: v.Name, Value: v.Value}) + } + newClusterProfile.Status.Properties = cpProperties + + // sync status.conditions + managedClusterAvailableCondition := meta.FindStatusCondition(managedCluster.Status.Conditions, v1.ManagedClusterConditionAvailable) + if managedClusterAvailableCondition != nil { + c := metav1.Condition{ + Type: cpv1alpha1.ClusterConditionControlPlaneHealthy, + Status: managedClusterAvailableCondition.Status, + Reason: managedClusterAvailableCondition.Reason, + Message: managedClusterAvailableCondition.Message, + } + meta.SetStatusCondition(&newClusterProfile.Status.Conditions, c) + } + managedClusterJoinedCondition := meta.FindStatusCondition(managedCluster.Status.Conditions, v1.ManagedClusterConditionJoined) + if managedClusterJoinedCondition != nil { + c := metav1.Condition{ + Type: "Joined", + Status: managedClusterJoinedCondition.Status, + Reason: managedClusterJoinedCondition.Reason, + Message: managedClusterJoinedCondition.Message, + } + meta.SetStatusCondition(&newClusterProfile.Status.Conditions, c) + } + + // patch status + updated, err := c.patcher.PatchStatus(ctx, newClusterProfile, newClusterProfile.Status, clusterProfile.Status) + if err != nil { + return err + } + if updated { + c.eventRecorder.Eventf("ClusterProfileSynced", "cluster profile %s is synced from open cluster management", managedClusterName) + } + return nil +} diff --git a/pkg/registration/hub/clusterprofile/controller_test.go b/pkg/registration/hub/clusterprofile/controller_test.go new file mode 100644 index 000000000..08aea1dea --- /dev/null +++ b/pkg/registration/hub/clusterprofile/controller_test.go @@ -0,0 +1,263 @@ +package clusterprofile + +import ( + "context" + "encoding/json" + "reflect" + "testing" + "time" + + "github.com/openshift/library-go/pkg/operator/events/eventstesting" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clienttesting "k8s.io/client-go/testing" + cpv1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" + cpfake "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake" + cpinformers "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions" + + clusterfake "open-cluster-management.io/api/client/cluster/clientset/versioned/fake" + clusterinformers "open-cluster-management.io/api/client/cluster/informers/externalversions" + v1 "open-cluster-management.io/api/cluster/v1" + v1beta2 "open-cluster-management.io/api/cluster/v1beta2" + "open-cluster-management.io/sdk-go/pkg/patcher" + + testingcommon "open-cluster-management.io/ocm/pkg/common/testing" + testinghelpers "open-cluster-management.io/ocm/pkg/registration/helpers/testing" +) + +func TestSyncClusterProfile(t *testing.T) { + managedCluster := &v1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: testinghelpers.TestManagedClusterName, + Labels: map[string]string{v1beta2.ClusterSetLabel: "default"}, + }, + Status: v1.ManagedClusterStatus{ + Version: v1.ManagedClusterVersion{ + Kubernetes: "v1.25.3", + }, + ClusterClaims: []v1.ManagedClusterClaim{ + {Name: "claim1", Value: "value1"}, + }, + Conditions: []metav1.Condition{ + { + Type: v1.ManagedClusterConditionAvailable, + Status: metav1.ConditionTrue, + }, + { + Type: v1.ManagedClusterConditionJoined, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + expectedCreatedClusterProfile := &cpv1alpha1.ClusterProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: testinghelpers.TestManagedClusterName, + Namespace: ClusterProfileNamespace, + Labels: map[string]string{ + cpv1alpha1.LabelClusterManagerKey: ClusterProfileManagerName, + }, + }, + Spec: cpv1alpha1.ClusterProfileSpec{ + DisplayName: testinghelpers.TestManagedClusterName, + ClusterManager: cpv1alpha1.ClusterManager{ + Name: ClusterProfileManagerName, + }, + }, + } + + expectedPatchedClusterProfileLabels := &cpv1alpha1.ClusterProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: testinghelpers.TestManagedClusterName, + Namespace: ClusterProfileNamespace, + Labels: map[string]string{ + cpv1alpha1.LabelClusterManagerKey: ClusterProfileManagerName, + cpv1alpha1.LabelClusterSetKey: "default", + }, + }, + Spec: cpv1alpha1.ClusterProfileSpec{ + DisplayName: testinghelpers.TestManagedClusterName, + ClusterManager: cpv1alpha1.ClusterManager{ + Name: ClusterProfileManagerName, + }, + }, + } + + expectedPatchedClusterProfileStatus := &cpv1alpha1.ClusterProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: testinghelpers.TestManagedClusterName, + Namespace: ClusterProfileNamespace, + Labels: map[string]string{ + cpv1alpha1.LabelClusterManagerKey: ClusterProfileManagerName, + cpv1alpha1.LabelClusterSetKey: "default", + }, + }, + Spec: cpv1alpha1.ClusterProfileSpec{ + DisplayName: testinghelpers.TestManagedClusterName, + ClusterManager: cpv1alpha1.ClusterManager{ + Name: ClusterProfileManagerName, + }, + }, + Status: cpv1alpha1.ClusterProfileStatus{ + Version: cpv1alpha1.ClusterVersion{ + Kubernetes: "v1.25.3", + }, + Properties: []cpv1alpha1.Property{ + {Name: "claim1", Value: "value1"}, + }, + Conditions: []metav1.Condition{ + { + Type: v1.ManagedClusterConditionAvailable, + Status: metav1.ConditionTrue, + }, + { + Type: v1.ManagedClusterConditionJoined, + Status: metav1.ConditionTrue, + }, + }, + }, + } + + cases := []struct { + name string + autoApprovalEnabled bool + mc []runtime.Object + cp []runtime.Object + validateActions func(t *testing.T, actions []clienttesting.Action) + }{ + { + name: "create clusterprofile", + mc: []runtime.Object{managedCluster}, + cp: []runtime.Object{}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertActions(t, actions, "create") + clusterprofile := actions[0].(clienttesting.CreateAction).GetObject().(*cpv1alpha1.ClusterProfile) + if !reflect.DeepEqual(clusterprofile.Labels, expectedCreatedClusterProfile.Labels) { + t.Errorf("expect clusterprofile labels %v but get %v", expectedCreatedClusterProfile.Labels, clusterprofile.Labels) + } + if !reflect.DeepEqual(clusterprofile.Spec, expectedCreatedClusterProfile.Spec) { + t.Errorf("expect clusterprofile spec %v but get %v", expectedCreatedClusterProfile.Spec, clusterprofile.Spec) + } + }, + }, + { + name: "patch clusterprofile clusterset labels", + mc: []runtime.Object{managedCluster}, + cp: []runtime.Object{expectedCreatedClusterProfile}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertActions(t, actions, "patch") + patch := actions[0].(clienttesting.PatchAction).GetPatch() + clusterprofile := &cpv1alpha1.ClusterProfile{} + err := json.Unmarshal(patch, clusterprofile) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(clusterprofile.Labels[cpv1alpha1.LabelClusterSetKey], expectedPatchedClusterProfileLabels.Labels[cpv1alpha1.LabelClusterSetKey]) { + t.Errorf("expect clusterprofile labels %v but get %v", expectedPatchedClusterProfileLabels.Labels, clusterprofile.Labels) + } + }, + }, + { + name: "patch clusterprofile status", + mc: []runtime.Object{managedCluster}, + cp: []runtime.Object{expectedPatchedClusterProfileLabels}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertActions(t, actions, "patch") + patch := actions[0].(clienttesting.PatchAction).GetPatch() + clusterprofile := &cpv1alpha1.ClusterProfile{} + err := json.Unmarshal(patch, clusterprofile) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(clusterprofile.Status.Version, expectedPatchedClusterProfileStatus.Status.Version) || + !reflect.DeepEqual(clusterprofile.Status.Properties, expectedPatchedClusterProfileStatus.Status.Properties) || + len(expectedPatchedClusterProfileStatus.Status.Conditions) != 2 { + t.Errorf("expect clusterprofile status %v but get %v", expectedPatchedClusterProfileStatus.Status, clusterprofile.Status) + } + }, + }, + { + name: "deleting clusterprofile", + mc: []runtime.Object{testinghelpers.NewDeletingManagedCluster()}, + cp: []runtime.Object{expectedPatchedClusterProfileStatus}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertActions(t, actions, "delete") + }, + }, + { + name: "deleted clusterprofile", + mc: []runtime.Object{testinghelpers.NewDeletingManagedCluster()}, + cp: []runtime.Object{}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertNoActions(t, actions) + }, + }, + { + name: "no managed cluster", + mc: []runtime.Object{}, + cp: []runtime.Object{}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertNoActions(t, actions) + }, + }, + { + name: "clusterprofile not managed by ocm", + mc: []runtime.Object{managedCluster}, + cp: []runtime.Object{&cpv1alpha1.ClusterProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: testinghelpers.TestManagedClusterName, + Namespace: ClusterProfileNamespace, + Labels: map[string]string{ + cpv1alpha1.LabelClusterManagerKey: "not-open-cluster-management", + }, + }, + Spec: cpv1alpha1.ClusterProfileSpec{ + ClusterManager: cpv1alpha1.ClusterManager{ + Name: "not-open-cluster-management", + }, + }, + }}, + validateActions: func(t *testing.T, actions []clienttesting.Action) { + testingcommon.AssertNoActions(t, actions) + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + clusterClient := clusterfake.NewSimpleClientset(c.mc...) + clusterProfileClient := cpfake.NewSimpleClientset(c.cp...) + clusterInformerFactory := clusterinformers.NewSharedInformerFactory(clusterClient, time.Minute*10) + clusterProfileInformerFactory := cpinformers.NewSharedInformerFactory(clusterProfileClient, time.Minute*10) + clusterStore := clusterInformerFactory.Cluster().V1().ManagedClusters().Informer().GetStore() + for _, cluster := range c.mc { + if err := clusterStore.Add(cluster); err != nil { + t.Fatal(err) + } + } + clusterProfileStore := clusterProfileInformerFactory.Apis().V1alpha1().ClusterProfiles().Informer().GetStore() + for _, clusterprofile := range c.cp { + if err := clusterProfileStore.Add(clusterprofile); err != nil { + t.Fatal(err) + } + } + + ctrl := clusterProfileController{ + clusterInformerFactory.Cluster().V1().ManagedClusters().Lister(), + clusterProfileClient, + clusterProfileInformerFactory.Apis().V1alpha1().ClusterProfiles().Lister(), + patcher.NewPatcher[ + *cpv1alpha1.ClusterProfile, cpv1alpha1.ClusterProfileSpec, cpv1alpha1.ClusterProfileStatus]( + clusterProfileClient.ApisV1alpha1().ClusterProfiles(ClusterProfileNamespace)), + eventstesting.NewTestingEventRecorder(t), + } + syncErr := ctrl.sync(context.TODO(), testingcommon.NewFakeSyncContext(t, testinghelpers.TestManagedClusterName)) + if syncErr != nil { + t.Errorf("unexpected err: %v", syncErr) + } + + c.validateActions(t, clusterProfileClient.Actions()) + }) + } +} diff --git a/pkg/registration/hub/clusterprofile/doc.go b/pkg/registration/hub/clusterprofile/doc.go new file mode 100644 index 000000000..e2c3e5c8d --- /dev/null +++ b/pkg/registration/hub/clusterprofile/doc.go @@ -0,0 +1,3 @@ +// package clusterprofile contains the hub-side reconciler for the ClusterProfile +// resource. +package clusterprofile diff --git a/pkg/registration/hub/manager.go b/pkg/registration/hub/manager.go index 4873ba97f..8b5782319 100644 --- a/pkg/registration/hub/manager.go +++ b/pkg/registration/hub/manager.go @@ -11,6 +11,8 @@ import ( kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/metadata" + cpclientset "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned" + cpinformerv1alpha1 "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions" addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" addonclient "open-cluster-management.io/api/client/addon/clientset/versioned" @@ -26,6 +28,7 @@ import ( commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers" "open-cluster-management.io/ocm/pkg/features" "open-cluster-management.io/ocm/pkg/registration/hub/addon" + "open-cluster-management.io/ocm/pkg/registration/hub/clusterprofile" "open-cluster-management.io/ocm/pkg/registration/hub/clusterrole" "open-cluster-management.io/ocm/pkg/registration/hub/gc" "open-cluster-management.io/ocm/pkg/registration/hub/lease" @@ -78,6 +81,11 @@ func (m *HubManagerOptions) RunControllerManager(ctx context.Context, controller return err } + clusterProfileClient, err := cpclientset.NewForConfig(controllerContext.KubeConfig) + if err != nil { + return err + } + workClient, err := workv1client.NewForConfig(controllerContext.KubeConfig) if err != nil { return err @@ -89,6 +97,7 @@ func (m *HubManagerOptions) RunControllerManager(ctx context.Context, controller } clusterInformers := clusterv1informers.NewSharedInformerFactory(clusterClient, 30*time.Minute) + clusterProfileInformers := cpinformerv1alpha1.NewSharedInformerFactory(clusterProfileClient, 30*time.Minute) workInformers := workv1informers.NewSharedInformerFactory(workClient, 30*time.Minute) kubeInfomers := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 30*time.Minute, kubeinformers.WithTweakListOptions( func(listOptions *metav1.ListOptions) { @@ -112,8 +121,8 @@ func (m *HubManagerOptions) RunControllerManager(ctx context.Context, controller return m.RunControllerManagerWithInformers( ctx, controllerContext, - kubeClient, metadataClient, clusterClient, addOnClient, - kubeInfomers, clusterInformers, workInformers, addOnInformers, + kubeClient, metadataClient, clusterClient, clusterProfileClient, addOnClient, + kubeInfomers, clusterInformers, clusterProfileInformers, workInformers, addOnInformers, ) } @@ -123,9 +132,11 @@ func (m *HubManagerOptions) RunControllerManagerWithInformers( kubeClient kubernetes.Interface, metadataClient metadata.Interface, clusterClient clusterv1client.Interface, + clusterProfileClient cpclientset.Interface, addOnClient addonclient.Interface, kubeInformers kubeinformers.SharedInformerFactory, clusterInformers clusterv1informers.SharedInformerFactory, + clusterProfileInformers cpinformerv1alpha1.SharedInformerFactory, workInformers workv1informers.SharedInformerFactory, addOnInformers addoninformers.SharedInformerFactory, ) error { @@ -223,6 +234,16 @@ func (m *HubManagerOptions) RunControllerManagerWithInformers( ) } + var clusterProfileController factory.Controller + if features.HubMutableFeatureGate.Enabled(ocmfeature.ClusterProfile) { + clusterProfileController = clusterprofile.NewClusterProfileController( + clusterInformers.Cluster().V1().ManagedClusters(), + clusterProfileClient, + clusterProfileInformers.Apis().V1alpha1().ClusterProfiles(), + controllerContext.EventRecorder, + ) + } + gcController := gc.NewGCController( kubeInformers.Rbac().V1().ClusterRoles().Lister(), kubeInformers.Rbac().V1().ClusterRoleBindings().Lister(), @@ -242,6 +263,9 @@ func (m *HubManagerOptions) RunControllerManagerWithInformers( go workInformers.Start(ctx.Done()) go kubeInformers.Start(ctx.Done()) go addOnInformers.Start(ctx.Done()) + if features.HubMutableFeatureGate.Enabled(ocmfeature.DefaultClusterSet) { + go clusterProfileInformers.Start(ctx.Done()) + } go managedClusterController.Run(ctx, 1) go taintController.Run(ctx, 1) @@ -257,6 +281,9 @@ func (m *HubManagerOptions) RunControllerManagerWithInformers( go defaultManagedClusterSetController.Run(ctx, 1) go globalManagedClusterSetController.Run(ctx, 1) } + if features.HubMutableFeatureGate.Enabled(ocmfeature.ClusterProfile) { + go clusterProfileController.Run(ctx, 1) + } go gcController.Run(ctx, 1) diff --git a/test/integration/operator/clustermanager_hosted_test.go b/test/integration/operator/clustermanager_hosted_test.go index f87e1be47..46135f9dd 100644 --- a/test/integration/operator/clustermanager_hosted_test.go +++ b/test/integration/operator/clustermanager_hosted_test.go @@ -74,6 +74,7 @@ var _ = ginkgo.Describe("ClusterManager Hosted Mode", func() { var hubAddonManagerDeployment = fmt.Sprintf("%s-addon-manager-controller", clusterManagerName) var hubRegistrationClusterRole = fmt.Sprintf("open-cluster-management:%s-registration:controller", clusterManagerName) var hubRegistrationWebhookClusterRole = fmt.Sprintf("open-cluster-management:%s-registration:webhook", clusterManagerName) + var hubRegistrationClusterProfileRole = fmt.Sprintf("open-cluster-management:%s-clusterprofile:controller", clusterManagerName) var hubWorkWebhookClusterRole = fmt.Sprintf("open-cluster-management:%s-registration:webhook", clusterManagerName) var hubWorkControllerClusterRole = fmt.Sprintf("open-cluster-management:%s-work:controller", clusterManagerName) var hubAddOnManagerClusterRole = fmt.Sprintf("open-cluster-management:%s-addon-manager:controller", clusterManagerName) @@ -762,6 +763,130 @@ var _ = ginkgo.Describe("ClusterManager Hosted Mode", func() { }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) }) + ginkgo.It("should have expected resource created/deleted when feature gates ClusterProfile enabled/disabled", func() { + ginkgo.By("Enable ClusterProfile feature gate") + gomega.Eventually(func() error { + clusterManager, err := hostedOperatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + featureGate := []operatorapiv1.FeatureGate{ + { + Feature: string(feature.ClusterProfile), + Mode: operatorapiv1.FeatureGateModeTypeEnable, + }, + } + if clusterManager.Spec.RegistrationConfiguration != nil { + for _, fg := range clusterManager.Spec.RegistrationConfiguration.FeatureGates { + if fg.Feature != string(feature.ClusterProfile) { + featureGate = append(featureGate, fg) + } + } + } + clusterManager.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationHubConfiguration{ + FeatureGates: featureGate, + } + _, err = hostedOperatorClient.OperatorV1().ClusterManagers().Update( + context.Background(), clusterManager, metav1.UpdateOptions{}) + return err + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + + // Check clusterrole/clusterrolebinding + gomega.Eventually(func() error { + if _, err := hostedKubeClient.RbacV1().ClusterRoles().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}); err != nil { + return err + } + return nil + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + gomega.Eventually(func() error { + if _, err := hostedKubeClient.RbacV1().ClusterRoleBindings().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}); err != nil { + return err + } + return nil + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + + // Check if relatedResources are correct + gomega.Eventually(func() error { + actual, err := hostedOperatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + // increase 3 resources clusterrole/clusterrolebinding and crd + if len(actual.Status.RelatedResources) != 48 { + return fmt.Errorf("should get 48 relatedResources, actual got %v, %v", + len(actual.Status.RelatedResources), actual.Status.RelatedResources) + } + return nil + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) + + ginkgo.By("Revert ClusterProfile to disable mode") + // Check ClusterProfile disable + gomega.Eventually(func() error { + clusterManager, err := hostedOperatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + featureGate := []operatorapiv1.FeatureGate{ + { + Feature: string(feature.ClusterProfile), + Mode: operatorapiv1.FeatureGateModeTypeDisable, + }, + } + if clusterManager.Spec.RegistrationConfiguration != nil { + for _, fg := range clusterManager.Spec.RegistrationConfiguration.FeatureGates { + if fg.Feature != string(feature.ClusterProfile) { + featureGate = append(featureGate, fg) + } + } + } + clusterManager.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationHubConfiguration{ + FeatureGates: featureGate, + } + _, err = hostedOperatorClient.OperatorV1().ClusterManagers().Update( + context.Background(), clusterManager, metav1.UpdateOptions{}) + return err + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + + // Check clusterrole/clusterrolebinding + gomega.Eventually(func() bool { + _, err := hostedKubeClient.RbacV1().ClusterRoles().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}) + if err == nil { + return false + } + return errors.IsNotFound(err) + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + gomega.Eventually(func() bool { + _, err := hostedKubeClient.RbacV1().ClusterRoleBindings().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}) + if err == nil { + return false + } + return errors.IsNotFound(err) + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + + // Check if relatedResources are correct + gomega.Eventually(func() error { + actual, err := hostedOperatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + // reduce 2 resources clusterrole/clusterrolebinding + if len(actual.Status.RelatedResources) != 46 { + return fmt.Errorf("should get 46 relatedResources, actual got %v, %v", + len(actual.Status.RelatedResources), actual.Status.RelatedResources) + } + return nil + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) + + }) + ginkgo.It("Deployment should be updated when clustermanager is changed", func() { gomega.Eventually(func() error { if _, err := hostedKubeClient.AppsV1().Deployments(hubNamespaceHosted).Get(hostedCtx, hubRegistrationDeployment, metav1.GetOptions{}); err != nil { @@ -830,8 +955,8 @@ var _ = ginkgo.Describe("ClusterManager Hosted Mode", func() { if err != nil { return err } - if len(actual.Status.RelatedResources) != 45 { - return fmt.Errorf("should get 45 relatedResources, actual got %v", len(actual.Status.RelatedResources)) + if len(actual.Status.RelatedResources) != 46 { + return fmt.Errorf("should get 46 relatedResources, actual got %v", len(actual.Status.RelatedResources)) } return nil }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) @@ -885,6 +1010,7 @@ var _ = ginkgo.Describe("ClusterManager Hosted Mode", func() { hubRegistrationDeployment, hubPlacementDeployment, hubRegistrationWebhookDeployment, hubWorkWebhookDeployment, hubWorkControllerDeployment, hubAddonManagerDeployment) }) + ginkgo.It("Deployment should be reconciled when manually updated", func() { gomega.Eventually(func() error { registrationDeployment, err := hostedKubeClient.AppsV1().Deployments(hubNamespaceHosted).Get(hostedCtx, hubRegistrationDeployment, metav1.GetOptions{}) diff --git a/test/integration/operator/clustermanager_test.go b/test/integration/operator/clustermanager_test.go index 1c173b486..d30803f5e 100644 --- a/test/integration/operator/clustermanager_test.go +++ b/test/integration/operator/clustermanager_test.go @@ -63,6 +63,7 @@ var _ = ginkgo.Describe("ClusterManager Default Mode", func() { var hubAddonManagerDeployment = fmt.Sprintf("%s-addon-manager-controller", clusterManagerName) var hubRegistrationClusterRole = fmt.Sprintf("open-cluster-management:%s-registration:controller", clusterManagerName) var hubRegistrationWebhookClusterRole = fmt.Sprintf("open-cluster-management:%s-registration:webhook", clusterManagerName) + var hubRegistrationClusterProfileRole = fmt.Sprintf("open-cluster-management:%s-clusterprofile:controller", clusterManagerName) var hubWorkWebhookClusterRole = fmt.Sprintf("open-cluster-management:%s-work:webhook", clusterManagerName) var hubWorkControllerClusterRole = fmt.Sprintf("open-cluster-management:%s-work:controller", clusterManagerName) var hubAddOnManagerClusterRole = fmt.Sprintf("open-cluster-management:%s-addon-manager:controller", clusterManagerName) @@ -730,6 +731,130 @@ var _ = ginkgo.Describe("ClusterManager Default Mode", func() { }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) }) + ginkgo.It("should have expected resource created/deleted when feature gates ClusterProfile enabled/disabled", func() { + ginkgo.By("Enable ClusterProfile feature gate") + gomega.Eventually(func() error { + clusterManager, err := operatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + featureGate := []operatorapiv1.FeatureGate{ + { + Feature: string(feature.ClusterProfile), + Mode: operatorapiv1.FeatureGateModeTypeEnable, + }, + } + if clusterManager.Spec.RegistrationConfiguration != nil { + for _, fg := range clusterManager.Spec.RegistrationConfiguration.FeatureGates { + if fg.Feature != string(feature.ClusterProfile) { + featureGate = append(featureGate, fg) + } + } + } + clusterManager.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationHubConfiguration{ + FeatureGates: featureGate, + } + _, err = operatorClient.OperatorV1().ClusterManagers().Update( + context.Background(), clusterManager, metav1.UpdateOptions{}) + return err + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + + // Check clusterrole/clusterrolebinding + gomega.Eventually(func() error { + if _, err := kubeClient.RbacV1().ClusterRoles().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}); err != nil { + return err + } + return nil + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + gomega.Eventually(func() error { + if _, err := kubeClient.RbacV1().ClusterRoleBindings().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}); err != nil { + return err + } + return nil + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + + // Check if relatedResources are correct + gomega.Eventually(func() error { + actual, err := operatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + // increase 3 resources clusterrole/clusterrolebinding and crd + if len(actual.Status.RelatedResources) != 48 { + return fmt.Errorf("should get 48 relatedResources, actual got %v, %v", + len(actual.Status.RelatedResources), actual.Status.RelatedResources) + } + return nil + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) + + ginkgo.By("Revert ClusterProfile to disable mode") + // Check ClusterProfile disable + gomega.Eventually(func() error { + clusterManager, err := operatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + featureGate := []operatorapiv1.FeatureGate{ + { + Feature: string(feature.ClusterProfile), + Mode: operatorapiv1.FeatureGateModeTypeDisable, + }, + } + if clusterManager.Spec.RegistrationConfiguration != nil { + for _, fg := range clusterManager.Spec.RegistrationConfiguration.FeatureGates { + if fg.Feature != string(feature.ClusterProfile) { + featureGate = append(featureGate, fg) + } + } + } + clusterManager.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationHubConfiguration{ + FeatureGates: featureGate, + } + _, err = operatorClient.OperatorV1().ClusterManagers().Update( + context.Background(), clusterManager, metav1.UpdateOptions{}) + return err + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeNil()) + + // Check clusterrole/clusterrolebinding + gomega.Eventually(func() bool { + _, err := kubeClient.RbacV1().ClusterRoles().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}) + if err == nil { + return false + } + return errors.IsNotFound(err) + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + gomega.Eventually(func() bool { + _, err := kubeClient.RbacV1().ClusterRoleBindings().Get( + context.Background(), hubRegistrationClusterProfileRole, metav1.GetOptions{}) + if err == nil { + return false + } + return errors.IsNotFound(err) + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + + // Check if relatedResources are correct + gomega.Eventually(func() error { + actual, err := operatorClient.OperatorV1().ClusterManagers().Get( + context.Background(), clusterManagerName, metav1.GetOptions{}) + if err != nil { + return err + } + // reduce 2 resources clusterrole/clusterrolebinding + if len(actual.Status.RelatedResources) != 46 { + return fmt.Errorf("should get 46 relatedResources, actual got %v, %v", + len(actual.Status.RelatedResources), actual.Status.RelatedResources) + } + return nil + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) + + }) + ginkgo.It("Deployment should be updated when clustermanager is changed", func() { gomega.Eventually(func() error { if _, err := kubeClient.AppsV1().Deployments(hubNamespace).Get(context.Background(), hubRegistrationDeployment, metav1.GetOptions{}); err != nil { @@ -794,8 +919,8 @@ var _ = ginkgo.Describe("ClusterManager Default Mode", func() { if err != nil { return err } - if len(actual.Status.RelatedResources) != 45 { - return fmt.Errorf("should get 45 relatedResources, actual got %v", len(actual.Status.RelatedResources)) + if len(actual.Status.RelatedResources) != 46 { + return fmt.Errorf("should get 46 relatedResources, actual got %v", len(actual.Status.RelatedResources)) } return nil }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) @@ -848,6 +973,7 @@ var _ = ginkgo.Describe("ClusterManager Default Mode", func() { hubRegistrationDeployment, hubPlacementDeployment, hubRegistrationWebhookDeployment, hubWorkWebhookDeployment, hubWorkControllerDeployment, hubAddonManagerDeployment) }) + ginkgo.It("Deployment should be reconciled when manually updated", func() { gomega.Eventually(func() error { if _, err := kubeClient.AppsV1().Deployments(hubNamespace).Get(context.Background(), hubRegistrationDeployment, metav1.GetOptions{}); err != nil { diff --git a/vendor/github.com/go-openapi/swag/util.go b/vendor/github.com/go-openapi/swag/util.go index f78ab684a..d971fbe34 100644 --- a/vendor/github.com/go-openapi/swag/util.go +++ b/vendor/github.com/go-openapi/swag/util.go @@ -341,12 +341,21 @@ type zeroable interface { // IsZero returns true when the value passed into the function is a zero value. // This allows for safer checking of interface values. func IsZero(data interface{}) bool { + v := reflect.ValueOf(data) + // check for nil data + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + if v.IsNil() { + return true + } + } + // check for things that have an IsZero method instead if vv, ok := data.(zeroable); ok { return vv.IsZero() } + // continue with slightly more complex reflection - v := reflect.ValueOf(data) switch v.Kind() { case reflect.String: return v.Len() == 0 @@ -358,14 +367,13 @@ func IsZero(data interface{}) bool { return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return v.IsNil() case reflect.Struct, reflect.Array: return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface()) case reflect.Invalid: return true + default: + return false } - return false } // AddInitialisms add additional initialisms diff --git a/vendor/modules.txt b/vendor/modules.txt index d14191c14..678e7adf0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -74,7 +74,7 @@ github.com/coreos/go-systemd/v22/journal # github.com/cyphar/filepath-securejoin v0.2.4 ## explicit; go 1.13 github.com/cyphar/filepath-securejoin -# github.com/davecgh/go-spew v1.1.1 +# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew # github.com/eclipse/paho.golang v0.12.0 @@ -122,7 +122,7 @@ github.com/go-openapi/jsonpointer ## explicit; go 1.13 github.com/go-openapi/jsonreference github.com/go-openapi/jsonreference/internal -# github.com/go-openapi/swag v0.22.3 +# github.com/go-openapi/swag v0.22.4 ## explicit; go 1.18 github.com/go-openapi/swag # github.com/go-task/slim-sprig/v3 v3.0.0 @@ -1642,6 +1642,19 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client +# sigs.k8s.io/cluster-inventory-api v0.0.0-20240730014211-ef0154379848 +## explicit; go 1.22.0 +sigs.k8s.io/cluster-inventory-api/apis/v1alpha1 +sigs.k8s.io/cluster-inventory-api/client/clientset/versioned +sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake +sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme +sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1 +sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake +sigs.k8s.io/cluster-inventory-api/client/informers/externalversions +sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis +sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1 +sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces +sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1 # sigs.k8s.io/controller-runtime v0.18.5 ## explicit; go 1.22.0 sigs.k8s.io/controller-runtime diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/LICENSE b/vendor/sigs.k8s.io/cluster-inventory-api/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/clusterprofile_types.go b/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/clusterprofile_types.go new file mode 100644 index 000000000..f083ff874 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/clusterprofile_types.go @@ -0,0 +1,152 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ClusterProfileSpec defines the desired state of ClusterProfile. +type ClusterProfileSpec struct { + // DisplayName defines a human-readable name of the ClusterProfile + // +optional + DisplayName string `json:"displayName,omitempty"` + + // ClusterManager defines which cluster manager owns this ClusterProfile resource + // +required + ClusterManager ClusterManager `json:"clusterManager"` +} + +// ClusterManager defines which cluster manager owns this ClusterProfile resource. +// A cluster manager is a system that centralizes the administration, coordination, +// and operation of multiple clusters across various infrastructures. +// Examples of cluster managers include Open Cluster Management, AZ Fleet, Karmada, and Clusternet. +// +// This field is immutable. +// It's recommended that each cluster manager instance should set a different values to this field. +// In addition, it's recommended that a predefined label with key "x-k8s.io/cluster-manager" +// should be added by the cluster manager upon creation. See constant LabelClusterManagerKey. +// The value of the label should be the same as the name of the cluster manager. +// The purpose of this label is to make filter clusters from different cluster managers easier. +// +// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ClusterManager is immutable" +type ClusterManager struct { + // Name defines the name of the cluster manager + // +required + Name string `json:"name"` +} + +// ClusterProfileStatus defines the observed state of ClusterProfile. +type ClusterProfileStatus struct { + // Conditions contains the different condition statuses for this cluster. + // +optional + Conditions []metav1.Condition `json:"conditions"` + + // Version defines the version information of the cluster. + // +optional + Version ClusterVersion `json:"version,omitempty"` + + // Properties defines name/value pairs to represent properties of a cluster. + // It could be a collection of ClusterProperty (KEP-2149) resources, + // but could also be info based on other implementations. + // The names of the properties can be predefined names from ClusterProperty resources + // and is allowed to be customized by different cluster managers. + // +optional + Properties []Property `json:"properties,omitempty"` +} + +// ClusterVersion represents version information about the cluster. +type ClusterVersion struct { + // Kubernetes is the kubernetes version of the cluster. + // +optional + Kubernetes string `json:"kubernetes,omitempty"` +} + +// Property defines a name/value pair to represent a property of a cluster. +// It could be a ClusterProperty (KEP-2149) resource, +// but could also be info based on other implementations. +// The name of the property can be predefined name from a ClusterProperty resource +// and is allowed to be customized by different cluster managers. +// This property can store various configurable details and metrics of a cluster, +// which may include information such as the number of nodes, total and free CPU, +// and total and free memory, among other potential attributes. +type Property struct { + // Name is the name of a property resource on cluster. It's a well-known + // or customized name to identify the property. + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:MinLength=1 + // +required + Name string `json:"name"` + + // Value is a property-dependent string + // +kubebuilder:validation:MaxLength=1024 + // +kubebuilder:validation:MinLength=1 + // +required + Value string `json:"value"` +} + +// Predefined healthy conditions indicate the cluster is in a good state or not. +// The condition and states conforms to metav1.Condition format. +// States are True/False/Unknown. +const ( + // ClusterConditionControlPlaneHealthy means the controlplane of the cluster is in a healthy state. + // If the control plane is not healthy, then the status condition will be "False". + ClusterConditionControlPlaneHealthy string = "ControlPlaneHealthy" +) + +const ( + // LabelClusterManagerKey is used to indicate the name of the cluster manager that a ClusterProfile belongs to. + // The value of the label MUST be the same as the name of the cluster manager. + // The purpose of this label is to make filter clusters from different cluster managers easier. + LabelClusterManagerKey = "x-k8s.io/cluster-manager" + + // LabelClusterSetKey is used on a namespace to indicate the clusterset that a ClusterProfile belongs to. + // If a cluster inventory represents a ClusterSet, + // all its ClusterProfile objects MUST be part of the same clusterSet and namespace must be used as the grouping mechanism. + // The namespace MUST have LabelClusterSet and the value as the name of the clusterSet. + LabelClusterSetKey = "multicluster.x-k8s.io/clusterset" +) + +//+genclient +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:resource:scope=Namespaced + +// ClusterProfile represents a single cluster in a multi-cluster deployment. +type ClusterProfile struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +required + Spec ClusterProfileSpec `json:"spec"` + + // +optional + Status ClusterProfileStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ClusterProfileList contains a list of ClusterProfile. +type ClusterProfileList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterProfile `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ClusterProfile{}, &ClusterProfileList{}) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/groupversion_info.go b/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/groupversion_info.go new file mode 100644 index 000000000..b5210514a --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/groupversion_info.go @@ -0,0 +1,58 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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 v1alpha1 contains API Schema definitions for the multicluster.x-k8s.io v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=multicluster.x-k8s.io +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "multicluster.x-k8s.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // SchemeGroupVersion generated code relies on this name + // Deprecated + SchemeGroupVersion = GroupVersion + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource generated code relies on this being here, but it logically belongs to the group +// DEPRECATED +func Resource(resource string) schema.GroupResource { + return schema.GroupResource{Group: GroupVersion.Group, Resource: resource} +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(GroupVersion, + &ClusterProfile{}, + &ClusterProfileList{}, + ) + metav1.AddToGroupVersion(scheme, GroupVersion) + return nil +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/zz_generated.deepcopy.go b/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..a94b2db9e --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/apis/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,174 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterManager) DeepCopyInto(out *ClusterManager) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterManager. +func (in *ClusterManager) DeepCopy() *ClusterManager { + if in == nil { + return nil + } + out := new(ClusterManager) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterProfile) DeepCopyInto(out *ClusterProfile) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProfile. +func (in *ClusterProfile) DeepCopy() *ClusterProfile { + if in == nil { + return nil + } + out := new(ClusterProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterProfile) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterProfileList) DeepCopyInto(out *ClusterProfileList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProfileList. +func (in *ClusterProfileList) DeepCopy() *ClusterProfileList { + if in == nil { + return nil + } + out := new(ClusterProfileList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterProfileList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterProfileSpec) DeepCopyInto(out *ClusterProfileSpec) { + *out = *in + out.ClusterManager = in.ClusterManager +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProfileSpec. +func (in *ClusterProfileSpec) DeepCopy() *ClusterProfileSpec { + if in == nil { + return nil + } + out := new(ClusterProfileSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterProfileStatus) DeepCopyInto(out *ClusterProfileStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.Version = in.Version + if in.Properties != nil { + in, out := &in.Properties, &out.Properties + *out = make([]Property, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProfileStatus. +func (in *ClusterProfileStatus) DeepCopy() *ClusterProfileStatus { + if in == nil { + return nil + } + out := new(ClusterProfileStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterVersion) DeepCopyInto(out *ClusterVersion) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterVersion. +func (in *ClusterVersion) DeepCopy() *ClusterVersion { + if in == nil { + return nil + } + out := new(ClusterVersion) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Property) DeepCopyInto(out *Property) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Property. +func (in *Property) DeepCopy() *Property { + if in == nil { + return nil + } + out := new(Property) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/clientset.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/clientset.go new file mode 100644 index 000000000..03be6f21f --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/clientset.go @@ -0,0 +1,119 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + "fmt" + "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + apisv1alpha1 "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ApisV1alpha1() apisv1alpha1.ApisV1alpha1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + apisV1alpha1 *apisv1alpha1.ApisV1alpha1Client +} + +// ApisV1alpha1 retrieves the ApisV1alpha1Client +func (c *Clientset) ApisV1alpha1() apisv1alpha1.ApisV1alpha1Interface { + return c.apisV1alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.apisV1alpha1, err = apisv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.apisV1alpha1 = apisv1alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/clientset_generated.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..b431dc172 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,84 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned" + apisv1alpha1 "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1" + fakeapisv1alpha1 "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// ApisV1alpha1 retrieves the ApisV1alpha1Client +func (c *Clientset) ApisV1alpha1() apisv1alpha1.ApisV1alpha1Interface { + return &fakeapisv1alpha1.FakeApisV1alpha1{Fake: &c.Fake} +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/doc.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..634bd02c9 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/register.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/register.go new file mode 100644 index 000000000..11a64abfe --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/fake/register.go @@ -0,0 +1,55 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + apisv1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + apisv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/doc.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..40e42c29f --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/register.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..eb332b0b2 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme/register.go @@ -0,0 +1,55 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + apisv1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + apisv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go new file mode 100644 index 000000000..e09a553a2 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/apis_client.go @@ -0,0 +1,106 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "net/http" + + rest "k8s.io/client-go/rest" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" + "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme" +) + +type ApisV1alpha1Interface interface { + RESTClient() rest.Interface + ClusterProfilesGetter +} + +// ApisV1alpha1Client is used to interact with features provided by the apis group. +type ApisV1alpha1Client struct { + restClient rest.Interface +} + +func (c *ApisV1alpha1Client) ClusterProfiles(namespace string) ClusterProfileInterface { + return newClusterProfiles(c, namespace) +} + +// NewForConfig creates a new ApisV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ApisV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ApisV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ApisV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ApisV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new ApisV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ApisV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ApisV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *ApisV1alpha1Client { + return &ApisV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ApisV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/clusterprofile.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/clusterprofile.go new file mode 100644 index 000000000..1ed110549 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/clusterprofile.go @@ -0,0 +1,194 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" + scheme "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/scheme" +) + +// ClusterProfilesGetter has a method to return a ClusterProfileInterface. +// A group's client should implement this interface. +type ClusterProfilesGetter interface { + ClusterProfiles(namespace string) ClusterProfileInterface +} + +// ClusterProfileInterface has methods to work with ClusterProfile resources. +type ClusterProfileInterface interface { + Create(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.CreateOptions) (*v1alpha1.ClusterProfile, error) + Update(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.UpdateOptions) (*v1alpha1.ClusterProfile, error) + UpdateStatus(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.UpdateOptions) (*v1alpha1.ClusterProfile, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.ClusterProfile, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.ClusterProfileList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterProfile, err error) + ClusterProfileExpansion +} + +// clusterProfiles implements ClusterProfileInterface +type clusterProfiles struct { + client rest.Interface + ns string +} + +// newClusterProfiles returns a ClusterProfiles +func newClusterProfiles(c *ApisV1alpha1Client, namespace string) *clusterProfiles { + return &clusterProfiles{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the clusterProfile, and returns the corresponding clusterProfile object, and an error if there is any. +func (c *clusterProfiles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterProfile, err error) { + result = &v1alpha1.ClusterProfile{} + err = c.client.Get(). + Namespace(c.ns). + Resource("clusterprofiles"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ClusterProfiles that match those selectors. +func (c *clusterProfiles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterProfileList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ClusterProfileList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("clusterprofiles"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterProfiles. +func (c *clusterProfiles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("clusterprofiles"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a clusterProfile and creates it. Returns the server's representation of the clusterProfile, and an error, if there is any. +func (c *clusterProfiles) Create(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.CreateOptions) (result *v1alpha1.ClusterProfile, err error) { + result = &v1alpha1.ClusterProfile{} + err = c.client.Post(). + Namespace(c.ns). + Resource("clusterprofiles"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(clusterProfile). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a clusterProfile and updates it. Returns the server's representation of the clusterProfile, and an error, if there is any. +func (c *clusterProfiles) Update(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.UpdateOptions) (result *v1alpha1.ClusterProfile, err error) { + result = &v1alpha1.ClusterProfile{} + err = c.client.Put(). + Namespace(c.ns). + Resource("clusterprofiles"). + Name(clusterProfile.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(clusterProfile). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *clusterProfiles) UpdateStatus(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.UpdateOptions) (result *v1alpha1.ClusterProfile, err error) { + result = &v1alpha1.ClusterProfile{} + err = c.client.Put(). + Namespace(c.ns). + Resource("clusterprofiles"). + Name(clusterProfile.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(clusterProfile). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the clusterProfile and deletes it. Returns an error if one occurs. +func (c *clusterProfiles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("clusterprofiles"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *clusterProfiles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("clusterprofiles"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched clusterProfile. +func (c *clusterProfiles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterProfile, err error) { + result = &v1alpha1.ClusterProfile{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("clusterprofiles"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/doc.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/doc.go new file mode 100644 index 000000000..28991e22c --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go new file mode 100644 index 000000000..fbfccbb91 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go new file mode 100644 index 000000000..4a41183fe --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_apis_client.go @@ -0,0 +1,39 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1" +) + +type FakeApisV1alpha1 struct { + *testing.Fake +} + +func (c *FakeApisV1alpha1) ClusterProfiles(namespace string) v1alpha1.ClusterProfileInterface { + return &FakeClusterProfiles{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeApisV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_clusterprofile.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_clusterprofile.go new file mode 100644 index 000000000..091b4885a --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/fake/fake_clusterprofile.go @@ -0,0 +1,140 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" +) + +// FakeClusterProfiles implements ClusterProfileInterface +type FakeClusterProfiles struct { + Fake *FakeApisV1alpha1 + ns string +} + +var clusterprofilesResource = v1alpha1.SchemeGroupVersion.WithResource("clusterprofiles") + +var clusterprofilesKind = v1alpha1.SchemeGroupVersion.WithKind("ClusterProfile") + +// Get takes name of the clusterProfile, and returns the corresponding clusterProfile object, and an error if there is any. +func (c *FakeClusterProfiles) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterProfile, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(clusterprofilesResource, c.ns, name), &v1alpha1.ClusterProfile{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterProfile), err +} + +// List takes label and field selectors, and returns the list of ClusterProfiles that match those selectors. +func (c *FakeClusterProfiles) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterProfileList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(clusterprofilesResource, clusterprofilesKind, c.ns, opts), &v1alpha1.ClusterProfileList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ClusterProfileList{ListMeta: obj.(*v1alpha1.ClusterProfileList).ListMeta} + for _, item := range obj.(*v1alpha1.ClusterProfileList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterProfiles. +func (c *FakeClusterProfiles) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(clusterprofilesResource, c.ns, opts)) + +} + +// Create takes the representation of a clusterProfile and creates it. Returns the server's representation of the clusterProfile, and an error, if there is any. +func (c *FakeClusterProfiles) Create(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.CreateOptions) (result *v1alpha1.ClusterProfile, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(clusterprofilesResource, c.ns, clusterProfile), &v1alpha1.ClusterProfile{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterProfile), err +} + +// Update takes the representation of a clusterProfile and updates it. Returns the server's representation of the clusterProfile, and an error, if there is any. +func (c *FakeClusterProfiles) Update(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.UpdateOptions) (result *v1alpha1.ClusterProfile, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(clusterprofilesResource, c.ns, clusterProfile), &v1alpha1.ClusterProfile{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterProfile), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterProfiles) UpdateStatus(ctx context.Context, clusterProfile *v1alpha1.ClusterProfile, opts v1.UpdateOptions) (*v1alpha1.ClusterProfile, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(clusterprofilesResource, "status", c.ns, clusterProfile), &v1alpha1.ClusterProfile{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterProfile), err +} + +// Delete takes name of the clusterProfile and deletes it. Returns an error if one occurs. +func (c *FakeClusterProfiles) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(clusterprofilesResource, c.ns, name, opts), &v1alpha1.ClusterProfile{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterProfiles) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(clusterprofilesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ClusterProfileList{}) + return err +} + +// Patch applies the patch and returns the patched clusterProfile. +func (c *FakeClusterProfiles) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterProfile, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(clusterprofilesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ClusterProfile{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterProfile), err +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go new file mode 100644 index 000000000..72d29996f --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/clientset/versioned/typed/apis/v1alpha1/generated_expansion.go @@ -0,0 +1,20 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type ClusterProfileExpansion interface{} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/interface.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/interface.go new file mode 100644 index 000000000..bc9a56e05 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/interface.go @@ -0,0 +1,45 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package apis + +import ( + v1alpha1 "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1" + internalinterfaces "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/clusterprofile.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/clusterprofile.go new file mode 100644 index 000000000..9c581a01c --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/clusterprofile.go @@ -0,0 +1,89 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisv1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" + versioned "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned" + internalinterfaces "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1" +) + +// ClusterProfileInformer provides access to a shared informer and lister for +// ClusterProfiles. +type ClusterProfileInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ClusterProfileLister +} + +type clusterProfileInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewClusterProfileInformer constructs a new informer for ClusterProfile type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterProfileInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterProfileInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterProfileInformer constructs a new informer for ClusterProfile type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterProfileInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApisV1alpha1().ClusterProfiles(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApisV1alpha1().ClusterProfiles(namespace).Watch(context.TODO(), options) + }, + }, + &apisv1alpha1.ClusterProfile{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterProfileInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterProfileInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterProfileInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisv1alpha1.ClusterProfile{}, f.defaultInformer) +} + +func (f *clusterProfileInformer) Lister() v1alpha1.ClusterProfileLister { + return v1alpha1.NewClusterProfileLister(f.Informer().GetIndexer()) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/interface.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/interface.go new file mode 100644 index 000000000..2d79ec48c --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis/v1alpha1/interface.go @@ -0,0 +1,44 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterProfiles returns a ClusterProfileInformer. + ClusterProfiles() ClusterProfileInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterProfiles returns a ClusterProfileInformer. +func (v *version) ClusterProfiles() ClusterProfileInformer { + return &clusterProfileInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/factory.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/factory.go new file mode 100644 index 000000000..542f1cf2e --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/factory.go @@ -0,0 +1,260 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned" + apis "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/apis" + internalinterfaces "sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Apis() apis.Interface +} + +func (f *sharedInformerFactory) Apis() apis.Interface { + return apis.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/generic.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/generic.go new file mode 100644 index 000000000..9f7cb5835 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/generic.go @@ -0,0 +1,61 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=apis, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("clusterprofiles"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Apis().V1alpha1().ClusterProfiles().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..27fe82d07 --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,39 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "sigs.k8s.io/cluster-inventory-api/client/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/clusterprofile.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/clusterprofile.go new file mode 100644 index 000000000..997429d7e --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/clusterprofile.go @@ -0,0 +1,98 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1" +) + +// ClusterProfileLister helps list ClusterProfiles. +// All objects returned here must be treated as read-only. +type ClusterProfileLister interface { + // List lists all ClusterProfiles in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.ClusterProfile, err error) + // ClusterProfiles returns an object that can list and get ClusterProfiles. + ClusterProfiles(namespace string) ClusterProfileNamespaceLister + ClusterProfileListerExpansion +} + +// clusterProfileLister implements the ClusterProfileLister interface. +type clusterProfileLister struct { + indexer cache.Indexer +} + +// NewClusterProfileLister returns a new ClusterProfileLister. +func NewClusterProfileLister(indexer cache.Indexer) ClusterProfileLister { + return &clusterProfileLister{indexer: indexer} +} + +// List lists all ClusterProfiles in the indexer. +func (s *clusterProfileLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterProfile, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ClusterProfile)) + }) + return ret, err +} + +// ClusterProfiles returns an object that can list and get ClusterProfiles. +func (s *clusterProfileLister) ClusterProfiles(namespace string) ClusterProfileNamespaceLister { + return clusterProfileNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ClusterProfileNamespaceLister helps list and get ClusterProfiles. +// All objects returned here must be treated as read-only. +type ClusterProfileNamespaceLister interface { + // List lists all ClusterProfiles in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.ClusterProfile, err error) + // Get retrieves the ClusterProfile from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.ClusterProfile, error) + ClusterProfileNamespaceListerExpansion +} + +// clusterProfileNamespaceLister implements the ClusterProfileNamespaceLister +// interface. +type clusterProfileNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ClusterProfiles in the indexer for a given namespace. +func (s clusterProfileNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterProfile, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ClusterProfile)) + }) + return ret, err +} + +// Get retrieves the ClusterProfile from the indexer for a given namespace and name. +func (s clusterProfileNamespaceLister) Get(name string) (*v1alpha1.ClusterProfile, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("clusterprofile"), name) + } + return obj.(*v1alpha1.ClusterProfile), nil +} diff --git a/vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/expansion_generated.go b/vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/expansion_generated.go new file mode 100644 index 000000000..3109bab4d --- /dev/null +++ b/vendor/sigs.k8s.io/cluster-inventory-api/client/listers/apis/v1alpha1/expansion_generated.go @@ -0,0 +1,26 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// ClusterProfileListerExpansion allows custom methods to be added to +// ClusterProfileLister. +type ClusterProfileListerExpansion interface{} + +// ClusterProfileNamespaceListerExpansion allows custom methods to be added to +// ClusterProfileNamespaceLister. +type ClusterProfileNamespaceListerExpansion interface{}