diff --git a/cluster/types.go b/cluster/types.go index 05d783c..189eca7 100644 --- a/cluster/types.go +++ b/cluster/types.go @@ -28,7 +28,7 @@ import ( // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// Cluster represents the desire state and status of a member cluster. +// Cluster represents the desired state and status of a member cluster. type Cluster struct { metav1.TypeMeta metav1.ObjectMeta @@ -44,8 +44,8 @@ type Cluster struct { // ClusterSpec defines the desired state of a member cluster. type ClusterSpec struct { // ID is the unique identifier for the cluster. - // It is different from the object uid(.metadata.uid) and typically collected automatically - // from member cluster during the progress of registration. + // It is different from the object uid(.metadata.uid) and is typically collected automatically + // from each member cluster during the process of registration. // // The value is collected in order: // 1. If the registering cluster enabled ClusterProperty API and defined the cluster ID by @@ -63,7 +63,7 @@ type ClusterSpec struct { // +kubebuilder:validation:Maxlength=128000 ID string `json:"id,omitempty"` - // SyncMode describes how a cluster sync resources from karmada control plane. + // SyncMode describes how a cluster syncs resources from karmada control plane. // +required SyncMode ClusterSyncMode @@ -72,14 +72,14 @@ type ClusterSpec struct { // +optional APIEndpoint string - // SecretRef represents the secret contains mandatory credentials to access the member cluster. + // SecretRef represents the secret that contains mandatory credentials to access the member cluster. // The secret should hold credentials as follows: // - secret.data.token // - secret.data.caBundle // +optional SecretRef *LocalSecretReference - // ImpersonatorSecretRef represents the secret contains the token of impersonator. + // ImpersonatorSecretRef represents the secret that contains the token of impersonator. // The secret should hold credentials as follows: // - secret.data.token // +optional @@ -94,12 +94,12 @@ type ClusterSpec struct { // ProxyURL is the proxy URL for the cluster. // If not empty, the karmada control plane will use this proxy to talk to the cluster. - // More details please refer to: https://github.com/kubernetes/client-go/issues/351 + // For more details please refer to: https://github.com/kubernetes/client-go/issues/351 // +optional ProxyURL string // ProxyHeader is the HTTP header required by proxy server. - // The key in the key-value pair is HTTP header key and value is the associated header payloads. + // The key in the key-value pair is HTTP header key and the value is the associated header payloads. // For the header with multiple values, the values should be separated by comma(e.g. 'k1': 'v1,v2,v3'). // +optional ProxyHeader map[string]string @@ -108,12 +108,12 @@ type ClusterSpec struct { // +optional Provider string - // Region represents the region of the member cluster locate in. + // Region represents the region in which the member cluster is located. // +optional Region string - // Zone represents the zone of the member cluster locate in. - // Deprecated: This filed was never been used by Karmada, and it will not be + // Zone represents the zone in which the member cluster is located. + // Deprecated: This field was never used by Karmada, and it will not be // removed from v1alpha1 for backward compatibility, use Zones instead. // +optional Zone string @@ -126,7 +126,7 @@ type ClusterSpec struct { // +optional Zones []string `json:"zones,omitempty"` - // Taints attached to the member cluster. + // Taints are attached to the member cluster. // Taints on the cluster have the "effect" on // any resource that does not tolerate the Taint. // +optional @@ -204,8 +204,8 @@ type ResourceModel struct { // ResourceModelRange describes the detail of each modeling quota that ranges from min to max. // Please pay attention, by default, the value of min can be inclusive, and the value of max cannot be inclusive. -// E.g. in an interval, min = 2, max =10 is set, which means the interval [2,10). -// This rule ensure that all intervals have the same meaning. If the last interval is infinite, +// E.g. in an interval, min = 2, max = 10 is set, which means the interval [2,10). +// This rule ensures that all intervals have the same meaning. If the last interval is infinite, // it is definitely unreachable. Therefore, we define the right interval as the open interval. // For a valid interval, the value on the right is greater than the value on the left, // in other words, max must be greater than min. @@ -242,13 +242,13 @@ const ( type ClusterSyncMode string const ( - // Push means that the controller on the karmada control plane will in charge of synchronization. - // The controller watches resources change on karmada control plane then pushes them to member cluster. + // Push means that the controller on the karmada control plane will be in charge of synchronization. + // The controller watches resources change on karmada control plane and then pushes them to member cluster. Push ClusterSyncMode = "Push" - // Pull means that the controller running on the member cluster will in charge of synchronization. - // The controller, as well known as 'agent', watches resources change on karmada control plane then fetches them - // and applies locally on the member cluster. + // Pull means that the controller running on the member cluster will be in charge of synchronization. + // The controller, also known as 'agent', watches resources change on karmada control plane, then fetches them + // and applies them locally on the member cluster. Pull ClusterSyncMode = "Pull" ) @@ -258,7 +258,7 @@ type LocalSecretReference struct { // Namespace is the namespace for the resource being referenced. Namespace string - // Name is the name of resource being referenced. + // Name is the name of the resource being referenced. Name string } @@ -266,6 +266,9 @@ type LocalSecretReference struct { const ( // ClusterConditionReady means the cluster is healthy and ready to accept workloads. ClusterConditionReady = "Ready" + + // ClusterConditionCompleteAPIEnablements indicates whether the cluster's API enablements(.status.apiEnablements) are complete. + ClusterConditionCompleteAPIEnablements = "CompleteAPIEnablements" ) // ClusterStatus contains information about the current status of a @@ -275,7 +278,7 @@ type ClusterStatus struct { // +optional KubernetesVersion string - // APIEnablements represents the list of APIs installed in the member cluster. + // APIEnablements represents the list of APIs installed on the member cluster. // +optional APIEnablements []APIEnablement @@ -366,7 +369,7 @@ type AllocatableModeling struct { // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// ClusterList contains a list of member cluster +// ClusterList contains a list of member clusters type ClusterList struct { metav1.TypeMeta metav1.ListMeta diff --git a/cluster/v1alpha1/types.go b/cluster/v1alpha1/types.go index 29cfc61..8a06b94 100644 --- a/cluster/v1alpha1/types.go +++ b/cluster/v1alpha1/types.go @@ -39,7 +39,7 @@ const ( // +kubebuilder:resource:scope="Cluster" // +kubebuilder:subresource:status -// Cluster represents the desire state and status of a member cluster. +// Cluster represents the desired state and status of a member cluster. type Cluster struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -55,8 +55,8 @@ type Cluster struct { // ClusterSpec defines the desired state of a member cluster. type ClusterSpec struct { // ID is the unique identifier for the cluster. - // It is different from the object uid(.metadata.uid) and typically collected automatically - // from member cluster during the progress of registration. + // It is different from the object uid(.metadata.uid) and is typically collected automatically + // from each member cluster during the process of registration. // // The value is collected in order: // 1. If the registering cluster enabled ClusterProperty API and defined the cluster ID by @@ -74,7 +74,7 @@ type ClusterSpec struct { // +kubebuilder:validation:Maxlength=128000 ID string `json:"id,omitempty"` - // SyncMode describes how a cluster sync resources from karmada control plane. + // SyncMode describes how a cluster syncs resources from karmada control plane. // +kubebuilder:validation:Enum=Push;Pull // +required SyncMode ClusterSyncMode `json:"syncMode"` @@ -84,14 +84,14 @@ type ClusterSpec struct { // +optional APIEndpoint string `json:"apiEndpoint,omitempty"` - // SecretRef represents the secret contains mandatory credentials to access the member cluster. + // SecretRef represents the secret that contains mandatory credentials to access the member cluster. // The secret should hold credentials as follows: // - secret.data.token // - secret.data.caBundle // +optional SecretRef *LocalSecretReference `json:"secretRef,omitempty"` - // ImpersonatorSecretRef represents the secret contains the token of impersonator. + // ImpersonatorSecretRef represents the secret that contains the token of impersonator. // The secret should hold credentials as follows: // - secret.data.token // +optional @@ -106,12 +106,12 @@ type ClusterSpec struct { // ProxyURL is the proxy URL for the cluster. // If not empty, the karmada control plane will use this proxy to talk to the cluster. - // More details please refer to: https://github.com/kubernetes/client-go/issues/351 + // For more details please refer to: https://github.com/kubernetes/client-go/issues/351 // +optional ProxyURL string `json:"proxyURL,omitempty"` // ProxyHeader is the HTTP header required by proxy server. - // The key in the key-value pair is HTTP header key and value is the associated header payloads. + // The key in the key-value pair is HTTP header key and the value is the associated header payloads. // For the header with multiple values, the values should be separated by comma(e.g. 'k1': 'v1,v2,v3'). // +optional ProxyHeader map[string]string `json:"proxyHeader,omitempty"` @@ -120,12 +120,12 @@ type ClusterSpec struct { // +optional Provider string `json:"provider,omitempty"` - // Region represents the region of the member cluster locate in. + // Region represents the region in which the member cluster is located. // +optional Region string `json:"region,omitempty"` - // Zone represents the zone of the member cluster locate in. - // Deprecated: This filed was never been used by Karmada, and it will not be + // Zone represents the zone in which the member cluster is located. + // Deprecated: This field was never been used by Karmada, and it will not be // removed from v1alpha1 for backward compatibility, use Zones instead. // +optional Zone string `json:"zone,omitempty"` @@ -138,7 +138,7 @@ type ClusterSpec struct { // +optional Zones []string `json:"zones,omitempty"` - // Taints attached to the member cluster. + // Taints are attached to the member cluster. // Taints on the cluster have the "effect" on // any resource that does not tolerate the Taint. // +optional @@ -216,8 +216,8 @@ type ResourceModel struct { // ResourceModelRange describes the detail of each modeling quota that ranges from min to max. // Please pay attention, by default, the value of min can be inclusive, and the value of max cannot be inclusive. -// E.g. in an interval, min = 2, max =10 is set, which means the interval [2,10). -// This rule ensure that all intervals have the same meaning. If the last interval is infinite, +// E.g. in an interval, min = 2, max = 10 is set, which means the interval [2,10). +// This rule ensures that all intervals have the same meaning. If the last interval is infinite, // it is definitely unreachable. Therefore, we define the right interval as the open interval. // For a valid interval, the value on the right is greater than the value on the left, // in other words, max must be greater than min. @@ -254,13 +254,13 @@ const ( type ClusterSyncMode string const ( - // Push means that the controller on the karmada control plane will in charge of synchronization. - // The controller watches resources change on karmada control plane then pushes them to member cluster. + // Push means that the controller on the karmada control plane will be in charge of synchronization. + // The controller watches resources change on karmada control plane and then pushes them to member cluster. Push ClusterSyncMode = "Push" - // Pull means that the controller running on the member cluster will in charge of synchronization. - // The controller, as well known as 'agent', watches resources change on karmada control plane then fetches them - // and applies locally on the member cluster. + // Pull means that the controller running on the member cluster will be in charge of synchronization. + // The controller, also known as 'agent', watches resources change on karmada control plane, then fetches them + // and applies them locally on the member cluster. Pull ClusterSyncMode = "Pull" ) @@ -270,7 +270,7 @@ type LocalSecretReference struct { // Namespace is the namespace for the resource being referenced. Namespace string `json:"namespace"` - // Name is the name of resource being referenced. + // Name is the name of the resource being referenced. Name string `json:"name"` } @@ -278,6 +278,9 @@ type LocalSecretReference struct { const ( // ClusterConditionReady means the cluster is healthy and ready to accept workloads. ClusterConditionReady = "Ready" + + // ClusterConditionCompleteAPIEnablements indicates whether the cluster's API enablements(.status.apiEnablements) are complete. + ClusterConditionCompleteAPIEnablements = "CompleteAPIEnablements" ) // ClusterStatus contains information about the current status of a @@ -287,7 +290,7 @@ type ClusterStatus struct { // +optional KubernetesVersion string `json:"kubernetesVersion,omitempty"` - // APIEnablements represents the list of APIs installed in the member cluster. + // APIEnablements represents the list of APIs installed on the member cluster. // +optional APIEnablements []APIEnablement `json:"apiEnablements,omitempty"` @@ -375,7 +378,7 @@ type AllocatableModeling struct { // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// ClusterList contains a list of member cluster +// ClusterList contains a list of member clusters type ClusterList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/config/v1alpha1/resourceinterpreterwebhook_types.go b/config/v1alpha1/resourceinterpreterwebhook_types.go index eb3e067..d1edef1 100644 --- a/config/v1alpha1/resourceinterpreterwebhook_types.go +++ b/config/v1alpha1/resourceinterpreterwebhook_types.go @@ -99,7 +99,7 @@ type RuleWithOperations struct { type InterpreterOperation string const ( - // InterpreterOperationAll indicates math all InterpreterOperation. + // InterpreterOperationAll indicates matching all InterpreterOperation. InterpreterOperationAll InterpreterOperation = "*" // InterpreterOperationInterpretReplica indicates that karmada want to figure out the replica declaration of a specific object. diff --git a/go.mod b/go.mod index fce7f21..2ce45a5 100644 --- a/go.mod +++ b/go.mod @@ -1,29 +1,29 @@ module github.com/karmada-io/api -go 1.22.0 - -toolchain go1.22.4 +go 1.22.9 require ( - k8s.io/api v0.30.2 - k8s.io/apiextensions-apiserver v0.30.2 - k8s.io/apimachinery v0.30.2 - k8s.io/utils v0.0.0-20230726121419-3b25d923346b - sigs.k8s.io/controller-runtime v0.18.4 + k8s.io/api v0.31.2 + k8s.io/apiextensions-apiserver v0.31.2 + k8s.io/apimachinery v0.31.2 + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 + sigs.k8s.io/controller-runtime v0.19.1 ) require ( - github.com/go-logr/logr v1.4.1 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/text v0.14.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/text v0.16.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 3087a9d..1cf054a 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,11 @@ 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/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -24,16 +27,19 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -45,8 +51,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -55,8 +61,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -75,18 +81,18 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= -k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= -k8s.io/apiextensions-apiserver v0.30.2 h1:l7Eue2t6QiLHErfn2vwK4KgF4NeDgjQkCXtEbOocKIE= -k8s.io/apiextensions-apiserver v0.30.2/go.mod h1:lsJFLYyK40iguuinsb3nt+Sj6CmodSI4ACDLep1rgjw= -k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= -k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= -sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= +k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= +sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/operator/constants/constants.go b/operator/constants/constants.go deleted file mode 100644 index 2eecdc8..0000000 --- a/operator/constants/constants.go +++ /dev/null @@ -1,107 +0,0 @@ -package constants - -import ( - "time" - - "k8s.io/apimachinery/pkg/labels" -) - -const ( - // KubeDefaultRepository defines the default of the k8s image repository - KubeDefaultRepository = "registry.k8s.io" - // KarmadaDefaultRepository defines the default of the karmada image repository - KarmadaDefaultRepository = "docker.io/karmada" - // EtcdDefaultVersion defines the default of the karmada etcd image tag - EtcdDefaultVersion = "3.5.3-0" - // KarmadaDefaultVersion defines the default of the karmada components image tag - KarmadaDefaultVersion = "v1.4.0" - // KubeDefaultVersion defines the default of the karmada apiserver and kubeControllerManager image tag - KubeDefaultVersion = "v1.25.4" - // KarmadaDefaultServiceSubnet defines the default of the subnet used by k8s services. - KarmadaDefaultServiceSubnet = "10.96.0.0/12" - // KarmadaDefaultDNSDomain defines the default of the DNSDomain - KarmadaDefaultDNSDomain = "cluster.local" - - // KarmadaOperator defines the name of the karmada operator. - KarmadaOperator = "karmada-operator" - // Etcd defines the name of the built-in etcd cluster component - Etcd = "etcd" - // KarmadaAPIServer defines the name of the karmada-apiserver component - KarmadaAPIServer = "karmada-apiserver" - // KubeAPIServer defines the repository name of the kube apiserver - KubeAPIServer = "kube-apiserver" - // KarmadaAggregatedAPIServer defines the name of the karmada-aggregated-apiserver component - KarmadaAggregatedAPIServer = "karmada-aggregated-apiserver" - // KubeControllerManager defines the name of the kube-controller-manager component - KubeControllerManager = "kube-controller-manager" - // KarmadaControllerManager defines the name of the karmada-controller-manager component - KarmadaControllerManager = "karmada-controller-manager" - // KarmadaScheduler defines the name of the karmada-scheduler component - KarmadaScheduler = "karmada-scheduler" - // KarmadaWebhook defines the name of the karmada-webhook component - KarmadaWebhook = "karmada-webhook" - // KarmadaDescheduler defines the name of the karmada-descheduler component - KarmadaDescheduler = "karmada-descheduler" - - // KarmadaSystemNamespace defines the leader selection namespace for karmada components - KarmadaSystemNamespace = "karmada-system" - // KarmadaDataDir defines the karmada data dir - KarmadaDataDir = "/var/lib/karmada" - - // EtcdListenClientPort defines the port etcd listen on for client traffic - EtcdListenClientPort = 2379 - // EtcdMetricsPort is the port at which to obtain etcd metrics and health status - EtcdMetricsPort = 2381 - // EtcdListenPeerPort defines the port etcd listen on for peer traffic - EtcdListenPeerPort = 2380 - // KarmadaAPIserverListenClientPort defines the port karmada apiserver listen on for client traffic - KarmadaAPIserverListenClientPort = 5443 - // EtcdDataVolumeName defines the name to etcd data volume - EtcdDataVolumeName = "etcd-data" - - // CertificateValidity Certificate validity period - CertificateValidity = time.Hour * 24 * 365 - // CaCertAndKeyName ca certificate key name - CaCertAndKeyName = "ca" - // EtcdCaCertAndKeyName etcd ca certificate key name - EtcdCaCertAndKeyName = "etcd-ca" - // EtcdServerCertAndKeyName etcd server certificate key name - EtcdServerCertAndKeyName = "etcd-server" - // EtcdClientCertAndKeyName etcd client certificate key name - EtcdClientCertAndKeyName = "etcd-client" - // KarmadaCertAndKeyName karmada certificate key name - KarmadaCertAndKeyName = "karmada" - // ApiserverCertAndKeyName karmada apiserver certificate key name - ApiserverCertAndKeyName = "apiserver" - // FrontProxyCaCertAndKeyName front-proxy-client certificate key name - FrontProxyCaCertAndKeyName = "front-proxy-ca" - // FrontProxyClientCertAndKeyName front-proxy-client certificate key name - FrontProxyClientCertAndKeyName = "front-proxy-client" - // ClusterName karmada cluster name - ClusterName = "karmada-apiserver" - // UserName karmada cluster user name - UserName = "karmada-admin" - - // KarmadaAPIserverComponent defines the name of karmada-apiserver component - KarmadaAPIserverComponent = "KarmadaAPIServer" - // KarmadaAggregatedAPIServerComponent defines the name of karmada-aggregated-apiserver component - KarmadaAggregatedAPIServerComponent = "KarmadaAggregatedAPIServer" - // KubeControllerManagerComponent defines the name of kube-controller-manager-component - KubeControllerManagerComponent = "KubeControllerManager" - // KarmadaControllerManagerComponent defines the name of karmada-controller-manager component - KarmadaControllerManagerComponent = "KarmadaControllerManager" - // KarmadaSchedulerComponent defines the name of karmada-scheduler component - KarmadaSchedulerComponent = "KarmadaScheduler" - // KarmadaWebhookComponent defines the name of the karmada-webhook component - KarmadaWebhookComponent = "KarmadaWebhook" - // KarmadaDeschedulerComponent defines the name of the karmada-descheduler component - KarmadaDeschedulerComponent = "KarmadaDescheduler" - - // KarmadaOperatorLabelKeyName defines a label key used by all of resources created by karmada operator - KarmadaOperatorLabelKeyName = "app.kubernetes.io/managed-by" -) - -var ( - // KarmadaOperatorLabel defines the default labels in the resource create by karmada operator - KarmadaOperatorLabel = labels.Set{KarmadaOperatorLabelKeyName: KarmadaOperator} -) diff --git a/operator/v1alpha1/register.go b/operator/v1alpha1/register.go new file mode 100644 index 0000000..d09d8aa --- /dev/null +++ b/operator/v1alpha1/register.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The Karmada 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 ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName specifies the group name used to register the objects. +const GroupName = "operator.karmada.io" + +// GroupVersion specifies the group and the version used to register the objects. +var GroupVersion = v1.GroupVersion{Group: GroupName, Version: "v1alpha1"} + +// SchemeGroupVersion is group version used to register these objects +// Deprecated: use GroupVersion instead. +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + // localSchemeBuilder will stay in k8s.io/kubernetes. + localSchemeBuilder = &SchemeBuilder + // AddToScheme applies all the stored functions to the scheme + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs) +} + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Karmada{}, + &KarmadaList{}, + ) + // AddToGroupVersion allows the serialization of client types like ListOptions. + v1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/operator/v1alpha1/type.go b/operator/v1alpha1/type.go index dd2ebb5..69731e8 100644 --- a/operator/v1alpha1/type.go +++ b/operator/v1alpha1/type.go @@ -113,6 +113,26 @@ type KarmadaSpec struct { // By default, the operator will only attempt to download the tarball if it's not yet present in the local cache. // +optional CRDTarball *CRDTarball `json:"crdTarball,omitempty"` + + // CustomCertificate specifies the configuration to customize the certificates + // for Karmada components or control the certificate generation process, such as + // the algorithm, validity period, etc. + // Currently, it only supports customizing the CA certificate for limited components. + // +optional + CustomCertificate *CustomCertificate `json:"customCertificate,omitempty"` +} + +// CustomCertificate holds the configuration for generating the certificate. +type CustomCertificate struct { + // APIServerCACert references a Kubernetes secret containing the CA certificate + // for component karmada-apiserver. + // The secret must contain the following data keys: + // - tls.crt: The TLS certificate. + // - tls.key: The TLS private key. + // If specified, this CA will be used to issue client certificates for + // all components that access the APIServer as clients. + // +optional + APIServerCACert *LocalSecretReference `json:"apiServerCACert,omitempty"` } // ImageRegistry represents an image registry as well as the @@ -239,19 +259,32 @@ type VolumeData struct { // operator has no knowledge of where certificate files live, and they must be supplied. type ExternalEtcd struct { // Endpoints of etcd members. Required for ExternalEtcd. + // +required Endpoints []string `json:"endpoints"` // CAData is an SSL Certificate Authority file used to secure etcd communication. // Required if using a TLS connection. - CAData []byte `json:"caData"` + // Deprecated: This field is deprecated and will be removed in a future version. Use SecretRef for providing client connection credentials. + CAData []byte `json:"caData,omitempty"` // CertData is an SSL certification file used to secure etcd communication. // Required if using a TLS connection. - CertData []byte `json:"certData"` + // Deprecated: This field is deprecated and will be removed in a future version. Use SecretRef for providing client connection credentials. + CertData []byte `json:"certData,omitempty"` // KeyData is an SSL key file used to secure etcd communication. // Required if using a TLS connection. - KeyData []byte `json:"keyData"` + // Deprecated: This field is deprecated and will be removed in a future version. Use SecretRef for providing client connection credentials. + KeyData []byte `json:"keyData,omitempty"` + + // SecretRef references a Kubernetes secret containing the etcd connection credentials. + // The secret must contain the following data keys: + // ca.crt: The Certificate Authority (CA) certificate data. + // tls.crt: The TLS certificate data used for verifying the etcd server's certificate. + // tls.key: The TLS private key. + // Required to configure the connection to an external etcd cluster. + // +required + SecretRef LocalSecretReference `json:"secretRef"` } // KarmadaAPIServer holds settings to kube-apiserver component of the kubernetes. @@ -264,8 +297,12 @@ type KarmadaAPIServer struct { // +optional ServiceSubnet *string `json:"serviceSubnet,omitempty"` - // ServiceType represents the service type of karmada apiserver. - // it is ClusterIP by default. + // ServiceType represents the service type of Karmada API server. + // Valid options are: "ClusterIP", "NodePort", "LoadBalancer". + // Defaults to "ClusterIP". + // + // +kubebuilder:default="ClusterIP" + // +kubebuilder:validation:Enum=ClusterIP;NodePort;LoadBalancer // +optional ServiceType corev1.ServiceType `json:"serviceType,omitempty"` @@ -290,6 +327,24 @@ type KarmadaAPIServer struct { // +optional ExtraArgs map[string]string `json:"extraArgs,omitempty"` + // ExtraVolumes specifies a list of extra volumes for the API server's pod + // To fulfil the base functionality required for a functioning control plane, when provisioning a new Karmada instance, + // the operator will automatically attach volumes for the API server pod needed to configure things such as TLS, + // SA token issuance/signing and secured connection to etcd, amongst others. However, given the wealth of options for configurability, + // there are additional features (e.g., encryption at rest and custom AuthN webhook) that can be configured. ExtraVolumes, in conjunction + // with ExtraArgs and ExtraVolumeMounts can be used to fulfil those use cases. + // +optional + ExtraVolumes []corev1.Volume `json:"extraVolumes,omitempty"` + + // ExtraVolumeMounts specifies a list of extra volume mounts to be mounted into the API server's container + // To fulfil the base functionality required for a functioning control plane, when provisioning a new Karmada instance, + // the operator will automatically mount volumes into the API server container needed to configure things such as TLS, + // SA token issuance/signing and secured connection to etcd, amongst others. However, given the wealth of options for configurability, + // there are additional features (e.g., encryption at rest and custom AuthN webhook) that can be configured. ExtraVolumeMounts, in conjunction + // with ExtraArgs and ExtraVolumes can be used to fulfil those use cases. + // +optional + ExtraVolumeMounts []corev1.VolumeMount `json:"extraVolumeMounts,omitempty"` + // CertSANs sets extra Subject Alternative Names for the API Server signing cert. // +optional CertSANs []string `json:"certSANs,omitempty"` @@ -659,6 +714,21 @@ type KarmadaStatus struct { // Conditions represents the latest available observations of a karmada's current state. // +optional Conditions []metav1.Condition `json:"conditions,omitempty"` + + // APIServerService reports the location of the Karmada API server service which + // can be used by third-party applications to discover the Karmada Service, e.g. + // expose the service outside the cluster by Ingress. + // +optional + APIServerService *APIServerService `json:"apiServerService,omitempty"` +} + +// APIServerService tells the location of Karmada API server service. +// Currently, it only includes the name of the service. The namespace +// of the service is the same as the namespace of the current Karmada object. +type APIServerService struct { + // Name represents the name of the Karmada API Server service. + // +required + Name string `json:"name"` } // LocalSecretReference is a reference to a secret within the enclosing diff --git a/operator/v1alpha1/zz_generated.deepcopy.go b/operator/v1alpha1/zz_generated.deepcopy.go index 465f0cf..4bdec62 100644 --- a/operator/v1alpha1/zz_generated.deepcopy.go +++ b/operator/v1alpha1/zz_generated.deepcopy.go @@ -22,11 +22,27 @@ limitations under the License. package v1alpha1 import ( - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIServerService) DeepCopyInto(out *APIServerService) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServerService. +func (in *APIServerService) DeepCopy() *APIServerService { + if in == nil { + return nil + } + out := new(APIServerService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CRDTarball) DeepCopyInto(out *CRDTarball) { *out = *in @@ -90,6 +106,27 @@ func (in *CommonSettings) DeepCopy() *CommonSettings { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomCertificate) DeepCopyInto(out *CustomCertificate) { + *out = *in + if in.APIServerCACert != nil { + in, out := &in.APIServerCACert, &out.APIServerCACert + *out = new(LocalSecretReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomCertificate. +func (in *CustomCertificate) DeepCopy() *CustomCertificate { + if in == nil { + return nil + } + out := new(CustomCertificate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Etcd) DeepCopyInto(out *Etcd) { *out = *in @@ -139,6 +176,7 @@ func (in *ExternalEtcd) DeepCopyInto(out *ExternalEtcd) { *out = make([]byte, len(*in)) copy(*out, *in) } + out.SecretRef = in.SecretRef return } @@ -277,6 +315,20 @@ func (in *KarmadaAPIServer) DeepCopyInto(out *KarmadaAPIServer) { (*out)[key] = val } } + if in.ExtraVolumes != nil { + in, out := &in.ExtraVolumes, &out.ExtraVolumes + *out = make([]v1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ExtraVolumeMounts != nil { + in, out := &in.ExtraVolumeMounts, &out.ExtraVolumeMounts + *out = make([]v1.VolumeMount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.CertSANs != nil { in, out := &in.CertSANs, &out.CertSANs *out = make([]string, len(*in)) @@ -606,6 +658,11 @@ func (in *KarmadaSpec) DeepCopyInto(out *KarmadaSpec) { *out = new(CRDTarball) (*in).DeepCopyInto(*out) } + if in.CustomCertificate != nil { + in, out := &in.CustomCertificate, &out.CustomCertificate + *out = new(CustomCertificate) + (*in).DeepCopyInto(*out) + } return } @@ -629,11 +686,16 @@ func (in *KarmadaStatus) DeepCopyInto(out *KarmadaStatus) { } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.APIServerService != nil { + in, out := &in.APIServerService, &out.APIServerService + *out = new(APIServerService) + **out = **in + } return } @@ -781,17 +843,17 @@ func (in *VolumeData) DeepCopyInto(out *VolumeData) { *out = *in if in.VolumeClaim != nil { in, out := &in.VolumeClaim, &out.VolumeClaim - *out = new(corev1.PersistentVolumeClaimTemplate) + *out = new(v1.PersistentVolumeClaimTemplate) (*in).DeepCopyInto(*out) } if in.HostPath != nil { in, out := &in.HostPath, &out.HostPath - *out = new(corev1.HostPathVolumeSource) + *out = new(v1.HostPathVolumeSource) (*in).DeepCopyInto(*out) } if in.EmptyDir != nil { in, out := &in.EmptyDir, &out.EmptyDir - *out = new(corev1.EmptyDirVolumeSource) + *out = new(v1.EmptyDirVolumeSource) (*in).DeepCopyInto(*out) } return diff --git a/policy/v1alpha1/override_types.go b/policy/v1alpha1/override_types.go index c57e203..6c8b3d4 100644 --- a/policy/v1alpha1/override_types.go +++ b/policy/v1alpha1/override_types.go @@ -101,6 +101,7 @@ type RuleWithCluster struct { // - ArgsOverrider // - LabelsOverrider // - AnnotationsOverrider +// - FieldOverrider // - Plaintext type Overriders struct { // Plaintext represents override rules defined with plaintext overriders. @@ -126,6 +127,13 @@ type Overriders struct { // AnnotationsOverrider represents the rules dedicated to handling workload annotations // +optional AnnotationsOverrider []LabelAnnotationOverrider `json:"annotationsOverrider,omitempty"` + + // FieldOverrider represents the rules dedicated to modifying a specific field in any Kubernetes resource. + // This allows changing a single field within the resource with multiple operations. + // It is designed to handle structured field values such as those found in ConfigMaps or Secrets. + // The current implementation supports JSON and YAML formats, but can easily be extended to support XML in the future. + // +optional + FieldOverrider []FieldOverrider `json:"fieldOverrider,omitempty"` } // LabelAnnotationOverrider represents the rules dedicated to handling workload labels/annotations @@ -255,6 +263,65 @@ const ( OverriderOpReplace OverriderOperator = "replace" ) +// FieldOverrider represents the rules dedicated to modifying a specific field in any Kubernetes resource. +// This allows changing a single field within the resource with multiple operations. +// It is designed to handle structured field values such as those found in ConfigMaps or Secrets. +// The current implementation supports JSON and YAML formats, but can easily be extended to support XML in the future. +// Note: In any given instance, FieldOverrider processes either JSON or YAML fields, but not both simultaneously. +type FieldOverrider struct { + // FieldPath specifies the initial location in the instance document where the operation should take place. + // The path uses RFC 6901 for navigating into nested structures. For example, the path "/data/db-config.yaml" + // specifies the configuration data key named "db-config.yaml" in a ConfigMap: "/data/db-config.yaml". + // +required + FieldPath string `json:"fieldPath"` + + // JSON represents the operations performed on the JSON document specified by the FieldPath. + // +optional + JSON []JSONPatchOperation `json:"json,omitempty"` + + // YAML represents the operations performed on the YAML document specified by the FieldPath. + // +optional + YAML []YAMLPatchOperation `json:"yaml,omitempty"` +} + +// JSONPatchOperation represents a single field modification operation for JSON format. +type JSONPatchOperation struct { + // SubPath specifies the relative location within the initial FieldPath where the operation should take place. + // The path uses RFC 6901 for navigating into nested structures. + // +required + SubPath string `json:"subPath"` + + // Operator indicates the operation on target field. + // Available operators are: "add", "remove", and "replace". + // +kubebuilder:validation:Enum=add;remove;replace + // +required + Operator OverriderOperator `json:"operator"` + + // Value is the new value to set for the specified field if the operation is "add" or "replace". + // For "remove" operation, this field is ignored. + // +optional + Value apiextensionsv1.JSON `json:"value,omitempty"` +} + +// YAMLPatchOperation represents a single field modification operation for YAML format. +type YAMLPatchOperation struct { + // SubPath specifies the relative location within the initial FieldPath where the operation should take place. + // The path uses RFC 6901 for navigating into nested structures. + // +required + SubPath string `json:"subPath"` + + // Operator indicates the operation on target field. + // Available operators are: "add", "remove", and "replace". + // +kubebuilder:validation:Enum=add;remove;replace + // +required + Operator OverriderOperator `json:"operator"` + + // Value is the new value to set for the specified field if the operation is "add" or "replace". + // For "remove" operation, this field is ignored. + // +optional + Value apiextensionsv1.JSON `json:"value,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // OverridePolicyList is a collection of OverridePolicy. diff --git a/policy/v1alpha1/propagation_types.go b/policy/v1alpha1/propagation_types.go index ee6a38a..fe9316f 100644 --- a/policy/v1alpha1/propagation_types.go +++ b/policy/v1alpha1/propagation_types.go @@ -181,6 +181,25 @@ type PropagationSpec struct { // nil means no suspension. no default values. // +optional Suspension *Suspension `json:"suspension,omitempty"` + + // PreserveResourcesOnDeletion controls whether resources should be preserved on the + // member clusters when the resource template is deleted. + // If set to true, resources will be preserved on the member clusters. + // Default is false, which means resources will be deleted along with the resource template. + // + // This setting is particularly useful during workload migration scenarios to ensure + // that rollback can occur quickly without affecting the workloads running on the + // member clusters. + // + // Additionally, this setting applies uniformly across all member clusters and will not + // selectively control preservation on only some clusters. + // + // Note: This setting does not apply to the deletion of the policy itself. + // When the policy is deleted, the resource templates and their corresponding + // propagated resources in member clusters will remain unchanged unless explicitly deleted. + // + // +optional + PreserveResourcesOnDeletion *bool `json:"preserveResourcesOnDeletion,omitempty"` } // ResourceSelector the resources will be selected. @@ -240,13 +259,19 @@ type SuspendClusters struct { ClusterNames []string `json:"clusterNames,omitempty"` } -// PurgeMode represents that how to deal with the legacy applications on the +// PurgeMode represents how to deal with the legacy application on the // cluster from which the application is migrated. type PurgeMode string const ( // Immediately represents that Karmada will immediately evict the legacy - // application. + // application. This is useful in scenarios where an application can not + // tolerate two instances running simultaneously. + // For example, the Flink application supports exactly-once state consistency, + // which means it requires that no two instances of the application are running + // at the same time. During a failover, it is crucial to ensure that the old + // application is removed before creating a new one to avoid duplicate + // processing and maintaining state consistency. Immediately PurgeMode = "Immediately" // Graciously represents that Karmada will wait for the application to // come back to healthy on the new cluster or after a timeout is reached @@ -299,6 +324,23 @@ type ApplicationFailoverBehavior struct { // Value must be positive integer. // +optional GracePeriodSeconds *int32 `json:"gracePeriodSeconds,omitempty"` + + // StatePreservation defines the policy for preserving and restoring state data + // during failover events for stateful applications. + // + // When an application fails over from one cluster to another, this policy enables + // the extraction of critical data from the original resource configuration. + // Upon successful migration, the extracted data is then re-injected into the new + // resource, ensuring that the application can resume operation with its previous + // state intact. + // This is particularly useful for stateful applications where maintaining data + // consistency across failover events is crucial. + // If not specified, means no state data will be preserved. + // + // Note: This requires the StatefulFailoverInjection feature gate to be enabled, + // which is alpha. + // +optional + StatePreservation *StatePreservation `json:"statePreservation,omitempty"` } // DecisionConditions represents the decision conditions of performing the failover process. @@ -312,6 +354,41 @@ type DecisionConditions struct { TolerationSeconds *int32 `json:"tolerationSeconds,omitempty"` } +// StatePreservation defines the policy for preserving state during failover events. +type StatePreservation struct { + // Rules contains a list of StatePreservationRule configurations. + // Each rule specifies a JSONPath expression targeting specific pieces of + // state data to be preserved during failover events. An AliasLabelName is associated + // with each rule, serving as a label key when the preserved data is passed + // to the new cluster. + // +required + Rules []StatePreservationRule `json:"rules"` +} + +// StatePreservationRule defines a single rule for state preservation. +// It includes a JSONPath expression and an alias name that will be used +// as a label key when passing state information to the new cluster. +type StatePreservationRule struct { + // AliasLabelName is the name that will be used as a label key when the preserved + // data is passed to the new cluster. This facilitates the injection of the + // preserved state back into the application resources during recovery. + // +required + AliasLabelName string `json:"aliasLabelName"` + + // JSONPath is the JSONPath template used to identify the state data + // to be preserved from the original resource configuration. + // The JSONPath syntax follows the Kubernetes specification: + // https://kubernetes.io/docs/reference/kubectl/jsonpath/ + // + // Note: The JSONPath expression will start searching from the "status" field of + // the API resource object by default. For example, to extract the "availableReplicas" + // from a Deployment, the JSONPath expression should be "{.availableReplicas}", not + // "{.status.availableReplicas}". + // + // +required + JSONPath string `json:"jsonPath"` +} + // Placement represents the rule for select clusters. type Placement struct { // ClusterAffinity represents scheduling restrictions to a certain set of clusters. diff --git a/policy/v1alpha1/zz_generated.deepcopy.go b/policy/v1alpha1/zz_generated.deepcopy.go index 764fa32..2f50916 100644 --- a/policy/v1alpha1/zz_generated.deepcopy.go +++ b/policy/v1alpha1/zz_generated.deepcopy.go @@ -36,6 +36,11 @@ func (in *ApplicationFailoverBehavior) DeepCopyInto(out *ApplicationFailoverBeha *out = new(int32) **out = **in } + if in.StatePreservation != nil { + in, out := &in.StatePreservation, &out.StatePreservation + *out = new(StatePreservation) + (*in).DeepCopyInto(*out) + } return } @@ -453,6 +458,36 @@ func (in *FederatedResourceQuotaStatus) DeepCopy() *FederatedResourceQuotaStatus return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FieldOverrider) DeepCopyInto(out *FieldOverrider) { + *out = *in + if in.JSON != nil { + in, out := &in.JSON, &out.JSON + *out = make([]JSONPatchOperation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.YAML != nil { + in, out := &in.YAML, &out.YAML + *out = make([]YAMLPatchOperation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FieldOverrider. +func (in *FieldOverrider) DeepCopy() *FieldOverrider { + if in == nil { + return nil + } + out := new(FieldOverrider) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FieldSelector) DeepCopyInto(out *FieldSelector) { *out = *in @@ -513,6 +548,23 @@ func (in *ImagePredicate) DeepCopy() *ImagePredicate { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JSONPatchOperation) DeepCopyInto(out *JSONPatchOperation) { + *out = *in + in.Value.DeepCopyInto(&out.Value) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONPatchOperation. +func (in *JSONPatchOperation) DeepCopy() *JSONPatchOperation { + if in == nil { + return nil + } + out := new(JSONPatchOperation) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LabelAnnotationOverrider) DeepCopyInto(out *LabelAnnotationOverrider) { *out = *in @@ -677,6 +729,13 @@ func (in *Overriders) DeepCopyInto(out *Overriders) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.FieldOverrider != nil { + in, out := &in.FieldOverrider, &out.FieldOverrider + *out = make([]FieldOverrider, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -843,6 +902,11 @@ func (in *PropagationSpec) DeepCopyInto(out *PropagationSpec) { *out = new(Suspension) (*in).DeepCopyInto(*out) } + if in.PreserveResourcesOnDeletion != nil { + in, out := &in.PreserveResourcesOnDeletion, &out.PreserveResourcesOnDeletion + *out = new(bool) + **out = **in + } return } @@ -936,6 +1000,43 @@ func (in *SpreadConstraint) DeepCopy() *SpreadConstraint { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatePreservation) DeepCopyInto(out *StatePreservation) { + *out = *in + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]StatePreservationRule, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatePreservation. +func (in *StatePreservation) DeepCopy() *StatePreservation { + if in == nil { + return nil + } + out := new(StatePreservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatePreservationRule) DeepCopyInto(out *StatePreservationRule) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatePreservationRule. +func (in *StatePreservationRule) DeepCopy() *StatePreservationRule { + if in == nil { + return nil + } + out := new(StatePreservationRule) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StaticClusterAssignment) DeepCopyInto(out *StaticClusterAssignment) { *out = *in @@ -1022,3 +1123,20 @@ func (in *Suspension) DeepCopy() *Suspension { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *YAMLPatchOperation) DeepCopyInto(out *YAMLPatchOperation) { + *out = *in + in.Value.DeepCopyInto(&out.Value) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new YAMLPatchOperation. +func (in *YAMLPatchOperation) DeepCopy() *YAMLPatchOperation { + if in == nil { + return nil + } + out := new(YAMLPatchOperation) + in.DeepCopyInto(out) + return out +} diff --git a/work/v1alpha1/work_types.go b/work/v1alpha1/work_types.go index f1e03ee..4f136df 100644 --- a/work/v1alpha1/work_types.go +++ b/work/v1alpha1/work_types.go @@ -60,9 +60,17 @@ type WorkSpec struct { // SuspendDispatching controls whether dispatching should // be suspended, nil means not suspend. - // Note: true means stop propagating to all clusters. + // Note: true means stop propagating to the corresponding member cluster, and + // does not prevent status collection. // +optional SuspendDispatching *bool `json:"suspendDispatching,omitempty"` + + // PreserveResourcesOnDeletion controls whether resources should be preserved on the + // member cluster when the Work object is deleted. + // If set to true, resources will be preserved on the member cluster. + // Default is false, which means resources will be deleted along with the Work object. + // +optional + PreserveResourcesOnDeletion *bool `json:"preserveResourcesOnDeletion,omitempty"` } // WorkloadTemplate represents the manifest workload to be deployed on managed cluster. diff --git a/work/v1alpha1/zz_generated.deepcopy.go b/work/v1alpha1/zz_generated.deepcopy.go index 824f379..1adbecf 100644 --- a/work/v1alpha1/zz_generated.deepcopy.go +++ b/work/v1alpha1/zz_generated.deepcopy.go @@ -386,6 +386,11 @@ func (in *WorkSpec) DeepCopyInto(out *WorkSpec) { *out = new(bool) **out = **in } + if in.PreserveResourcesOnDeletion != nil { + in, out := &in.PreserveResourcesOnDeletion, &out.PreserveResourcesOnDeletion + *out = new(bool) + **out = **in + } return } diff --git a/work/v1alpha2/binding_types.go b/work/v1alpha2/binding_types.go index eadacb6..77d0591 100644 --- a/work/v1alpha2/binding_types.go +++ b/work/v1alpha2/binding_types.go @@ -151,6 +151,14 @@ type ResourceBindingSpec struct { // nil means no suspension. no default values. // +optional Suspension *policyv1alpha1.Suspension `json:"suspension,omitempty"` + + // PreserveResourcesOnDeletion controls whether resources should be preserved on the + // member clusters when the binding object is deleted. + // If set to true, resources will be preserved on the member clusters. + // Default is false, which means resources will be deleted along with the binding object. + // This setting applies to all Work objects created under this binding object. + // +optional + PreserveResourcesOnDeletion *bool `json:"preserveResourcesOnDeletion,omitempty"` } // ObjectReference contains enough information to locate the referenced object inside current cluster. @@ -232,6 +240,13 @@ type GracefulEvictionTask struct { // +required FromCluster string `json:"fromCluster"` + // PurgeMode represents how to deal with the legacy applications on the + // cluster from which the application is migrated. + // Valid options are "Immediately", "Graciously" and "Never". + // +kubebuilder:validation:Enum=Immediately;Graciously;Never + // +optional + PurgeMode policyv1alpha1.PurgeMode `json:"purgeMode,omitempty"` + // Replicas indicates the number of replicas should be evicted. // Should be ignored for resource type that doesn't have replica. // +optional @@ -272,6 +287,11 @@ type GracefulEvictionTask struct { // +optional SuppressDeletion *bool `json:"suppressDeletion,omitempty"` + // PreservedLabelState represents the application state information collected from the original cluster, + // and it will be injected into the new cluster in form of application labels. + // +optional + PreservedLabelState map[string]string `json:"preservedLabelState,omitempty"` + // CreationTimestamp is a timestamp representing the server time when this object was // created. // Clients should not set this value to avoid the time inconsistency issue. @@ -280,6 +300,9 @@ type GracefulEvictionTask struct { // Populated by the system. Read-only. // +optional CreationTimestamp *metav1.Time `json:"creationTimestamp,omitempty"` + + // ClustersBeforeFailover records the clusters where running the application before failover. + ClustersBeforeFailover []string `json:"clustersBeforeFailover,omitempty"` } // BindingSnapshot is a snapshot of a ResourceBinding or ClusterResourceBinding. diff --git a/work/v1alpha2/binding_types_helper.go b/work/v1alpha2/binding_types_helper.go index 7bf5369..e46e7fa 100644 --- a/work/v1alpha2/binding_types_helper.go +++ b/work/v1alpha2/binding_types_helper.go @@ -18,11 +18,14 @@ package v1alpha2 // TaskOptions represents options for GracefulEvictionTasks. type TaskOptions struct { - producer string - reason string - message string - gracePeriodSeconds *int32 - suppressDeletion *bool + purgeMode policyv1alpha1.PurgeMode + producer string + reason string + message string + gracePeriodSeconds *int32 + suppressDeletion *bool + preservedLabelState map[string]string + clustersBeforeFailover []string } // Option configures a TaskOptions @@ -38,6 +41,13 @@ func NewTaskOptions(opts ...Option) *TaskOptions { return &options } +// WithPurgeMode sets the purgeMode for TaskOptions +func WithPurgeMode(purgeMode policyv1alpha1.PurgeMode) Option { + return func(o *TaskOptions) { + o.purgeMode = purgeMode + } +} + // WithProducer sets the producer for TaskOptions func WithProducer(producer string) Option { return func(o *TaskOptions) { @@ -73,6 +83,20 @@ func WithSuppressDeletion(suppressDeletion *bool) Option { } } +// WithPreservedLabelState sets the preservedLabelState for TaskOptions +func WithPreservedLabelState(preservedLabelState map[string]string) Option { + return func(o *TaskOptions) { + o.preservedLabelState = preservedLabelState + } +} + +// WithClustersBeforeFailover sets the clustersBeforeFailover for TaskOptions +func WithClustersBeforeFailover(clustersBeforeFailover []string) Option { + return func(o *TaskOptions) { + o.clustersBeforeFailover = clustersBeforeFailover + } +} + // TargetContains checks if specific cluster present on the target list. func (s *ResourceBindingSpec) TargetContains(name string) bool { for i := range s.Clusters { @@ -153,12 +177,15 @@ func (s *ResourceBindingSpec) GracefulEvictCluster(name string, options *TaskOpt // build eviction task evictingCluster := evictCluster.DeepCopy() evictionTask := GracefulEvictionTask{ - FromCluster: evictingCluster.Name, - Reason: options.reason, - Message: options.message, - Producer: options.producer, - GracePeriodSeconds: options.gracePeriodSeconds, - SuppressDeletion: options.suppressDeletion, + FromCluster: evictingCluster.Name, + PurgeMode: options.purgeMode, + Reason: options.reason, + Message: options.message, + Producer: options.producer, + GracePeriodSeconds: options.gracePeriodSeconds, + SuppressDeletion: options.suppressDeletion, + PreservedLabelState: options.preservedLabelState, + ClustersBeforeFailover: options.clustersBeforeFailover, } if evictingCluster.Replicas > 0 { evictionTask.Replicas = &evictingCluster.Replicas diff --git a/work/v1alpha2/binding_types_helper_test.go b/work/v1alpha2/binding_types_helper_test.go index 9049580..07a8f11 100644 --- a/work/v1alpha2/binding_types_helper_test.go +++ b/work/v1alpha2/binding_types_helper_test.go @@ -172,6 +172,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { }, EvictEvent: GracefulEvictionTask{ FromCluster: "m1", + PurgeMode: policyv1alpha1.Immediately, Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", Producer: EvictionProducerTaintManager, @@ -181,6 +182,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { GracefulEvictionTasks: []GracefulEvictionTask{ { FromCluster: "m1", + PurgeMode: policyv1alpha1.Immediately, Replicas: ptr.To[int32](1), Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", @@ -196,6 +198,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { }, EvictEvent: GracefulEvictionTask{ FromCluster: "m2", + PurgeMode: policyv1alpha1.Never, Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", Producer: EvictionProducerTaintManager, @@ -205,6 +208,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { GracefulEvictionTasks: []GracefulEvictionTask{ { FromCluster: "m2", + PurgeMode: policyv1alpha1.Never, Replicas: ptr.To[int32](2), Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", @@ -220,6 +224,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { }, EvictEvent: GracefulEvictionTask{ FromCluster: "m3", + PurgeMode: policyv1alpha1.Graciously, Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", Producer: EvictionProducerTaintManager, @@ -229,6 +234,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { GracefulEvictionTasks: []GracefulEvictionTask{ { FromCluster: "m3", + PurgeMode: policyv1alpha1.Graciously, Replicas: ptr.To[int32](3), Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", @@ -245,6 +251,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { }, EvictEvent: GracefulEvictionTask{ FromCluster: "m3", + PurgeMode: policyv1alpha1.Graciously, Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", Producer: EvictionProducerTaintManager, @@ -257,6 +264,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { }, { FromCluster: "m3", + PurgeMode: policyv1alpha1.Graciously, Replicas: ptr.To[int32](3), Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction", @@ -286,6 +294,7 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { }, EvictEvent: GracefulEvictionTask{ FromCluster: "m1", + PurgeMode: policyv1alpha1.Graciously, Replicas: ptr.To[int32](1), Reason: EvictionReasonTaintUntolerated, Message: "graceful eviction v2", @@ -309,7 +318,11 @@ func TestResourceBindingSpec_GracefulEvictCluster(t *testing.T) { for _, test := range tests { tc := test t.Run(tc.Name, func(t *testing.T) { - tc.InputSpec.GracefulEvictCluster(tc.EvictEvent.FromCluster, NewTaskOptions(WithProducer(tc.EvictEvent.Producer), WithReason(tc.EvictEvent.Reason), WithMessage(tc.EvictEvent.Message))) + tc.InputSpec.GracefulEvictCluster(tc.EvictEvent.FromCluster, NewTaskOptions( + WithPurgeMode(tc.EvictEvent.PurgeMode), + WithProducer(tc.EvictEvent.Producer), + WithReason(tc.EvictEvent.Reason), + WithMessage(tc.EvictEvent.Message))) if !reflect.DeepEqual(tc.InputSpec.Clusters, tc.ExpectSpec.Clusters) { t.Fatalf("expect clusters: %v, but got: %v", tc.ExpectSpec.Clusters, tc.InputSpec.Clusters) diff --git a/work/v1alpha2/zz_generated.deepcopy.go b/work/v1alpha2/zz_generated.deepcopy.go index fe0e46c..238ee92 100644 --- a/work/v1alpha2/zz_generated.deepcopy.go +++ b/work/v1alpha2/zz_generated.deepcopy.go @@ -149,10 +149,22 @@ func (in *GracefulEvictionTask) DeepCopyInto(out *GracefulEvictionTask) { *out = new(bool) **out = **in } + if in.PreservedLabelState != nil { + in, out := &in.PreservedLabelState, &out.PreservedLabelState + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.CreationTimestamp != nil { in, out := &in.CreationTimestamp, &out.CreationTimestamp *out = (*in).DeepCopy() } + if in.ClustersBeforeFailover != nil { + in, out := &in.ClustersBeforeFailover, &out.ClustersBeforeFailover + *out = make([]string, len(*in)) + copy(*out, *in) + } return } @@ -353,6 +365,11 @@ func (in *ResourceBindingSpec) DeepCopyInto(out *ResourceBindingSpec) { *out = new(v1alpha1.Suspension) (*in).DeepCopyInto(*out) } + if in.PreserveResourcesOnDeletion != nil { + in, out := &in.PreserveResourcesOnDeletion, &out.PreserveResourcesOnDeletion + *out = new(bool) + **out = **in + } return } @@ -429,6 +446,18 @@ func (in *TaskOptions) DeepCopyInto(out *TaskOptions) { *out = new(bool) **out = **in } + if in.preservedLabelState != nil { + in, out := &in.preservedLabelState, &out.preservedLabelState + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.clustersBeforeFailover != nil { + in, out := &in.clustersBeforeFailover, &out.clustersBeforeFailover + *out = make([]string, len(*in)) + copy(*out, *in) + } return }