diff --git a/apps/v1alpha1/zz_generated.register.go b/apps/v1alpha1/zz_generated.register.go index 29f864e..577e4ab 100644 --- a/apps/v1alpha1/zz_generated.register.go +++ b/apps/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/autoscaling/v1alpha1/zz_generated.register.go b/autoscaling/v1alpha1/zz_generated.register.go index b51d07e..9faabae 100644 --- a/autoscaling/v1alpha1/zz_generated.register.go +++ b/autoscaling/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/cluster/v1alpha1/well_known_constants.go b/cluster/v1alpha1/well_known_constants.go index e79323e..d60d4b2 100644 --- a/cluster/v1alpha1/well_known_constants.go +++ b/cluster/v1alpha1/well_known_constants.go @@ -27,8 +27,6 @@ const ( // (corresponding to ClusterConditionReady status ConditionUnknown) // and removed when cluster becomes reachable (ClusterConditionReady status ConditionTrue). TaintClusterUnreachable = "cluster.karmada.io/unreachable" - // TaintClusterTerminating will be added when cluster is terminating. - TaintClusterTerminating = "cluster.karmada.io/terminating" // CacheSourceAnnotationKey is the annotation that added to a resource to // represent which cluster it cached from. diff --git a/cluster/v1alpha1/zz_generated.register.go b/cluster/v1alpha1/zz_generated.register.go index bcdfd11..5c7c15f 100644 --- a/cluster/v1alpha1/zz_generated.register.go +++ b/cluster/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/config/v1alpha1/resourceinterpreterwebhook_types.go b/config/v1alpha1/resourceinterpreterwebhook_types.go index d1edef1..eae94dd 100644 --- a/config/v1alpha1/resourceinterpreterwebhook_types.go +++ b/config/v1alpha1/resourceinterpreterwebhook_types.go @@ -56,6 +56,24 @@ type ResourceInterpreterWebhook struct { Name string `json:"name"` // ClientConfig defines how to communicate with the hook. + // It supports two mutually exclusive configuration modes: + // + // 1. URL - Directly specify the webhook URL with format `scheme://host:port/path`. + // Example: https://webhook.example.com:8443/my-interpreter + // + // 2. Service - Reference a Kubernetes Service that exposes the webhook. + // When using Service reference, Karmada resolves the endpoint through following steps: + // a) First attempts to locate the Service in karmada-apiserver + // b) If found, constructs URL based on Service type: + // - ClusterIP/LoadBalancer/NodePort: Uses ClusterIP with port from Service spec + // (Note: Services with ClusterIP "None" are rejected), Example: + // `https://:` + // - ExternalName: Uses external DNS name format: `https://:` + // c) If NOT found in karmada-apiserver, falls back to standard Kubernetes + // service DNS name format: `https://..svc:` + // + // Note: When both URL and Service are specified, the Service reference takes precedence + // and the URL configuration will be ignored. // +required ClientConfig admissionregistrationv1.WebhookClientConfig `json:"clientConfig"` diff --git a/config/v1alpha1/zz_generated.register.go b/config/v1alpha1/zz_generated.register.go index ce9b6fd..0aba07f 100644 --- a/config/v1alpha1/zz_generated.register.go +++ b/config/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/go.mod b/go.mod index 76a1014..41af652 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/karmada-io/api -go 1.22.12 +go 1.23.8 require ( - k8s.io/api v0.31.3 - k8s.io/apiextensions-apiserver v0.31.3 - k8s.io/apimachinery v0.31.3 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.1 + k8s.io/api v0.32.3 + k8s.io/apiextensions-apiserver v0.32.3 + k8s.io/apimachinery v0.32.3 + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 + sigs.k8s.io/controller-runtime v0.20.4 ) require ( @@ -16,15 +16,15 @@ require ( 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/kr/text v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // 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 + golang.org/x/net v0.39.0 // indirect + golang.org/x/text v0.24.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // 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/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index d89e1ab..741f558 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -51,8 +52,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.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= 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= @@ -61,8 +62,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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 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= @@ -76,29 +77,23 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -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.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= -k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -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/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= +k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= +k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY= +k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= 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= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= +sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/networking/v1alpha1/zz_generated.register.go b/networking/v1alpha1/zz_generated.register.go index 7c40fdf..46cb9fa 100644 --- a/networking/v1alpha1/zz_generated.register.go +++ b/networking/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/operator/v1alpha1/type.go b/operator/v1alpha1/type.go index 9055ba4..931ab1a 100644 --- a/operator/v1alpha1/type.go +++ b/operator/v1alpha1/type.go @@ -120,6 +120,12 @@ type KarmadaSpec struct { // Currently, it only supports customizing the CA certificate for limited components. // +optional CustomCertificate *CustomCertificate `json:"customCertificate,omitempty"` + + // Suspend indicates that the operator should suspend reconciliation + // for this Karmada control plane and all its managed resources. + // Karmada instances for which this field is not explicitly set to `true` will continue to be reconciled as usual. + // +optional + Suspend *bool `json:"suspend,omitempty"` } // CustomCertificate holds the configuration for generating the certificate. @@ -133,6 +139,12 @@ type CustomCertificate struct { // all components that access the APIServer as clients. // +optional APIServerCACert *LocalSecretReference `json:"apiServerCACert,omitempty"` + + // LeafCertValidityDays specifies the validity period of leaf certificates (e.g., API Server certificate) in days. + // If not specified, the default validity period of 1 year will be used. + // +kubebuilder:validation:Minimum=1 + // +optional + LeafCertValidityDays *int32 `json:"leafCertValidityDays,omitempty"` } // ImageRegistry represents an image registry as well as the @@ -306,6 +318,17 @@ type KarmadaAPIServer struct { // +optional ServiceType corev1.ServiceType `json:"serviceType,omitempty"` + // LoadBalancerClass specifies the load balancer implementation class for the Karmada API server. + // This field is applicable only when ServiceType is set to LoadBalancer. + // If specified, the service will be processed by the load balancer implementation that matches the specified class. + // By default, this is not set and the LoadBalancer type of Service uses the cloud provider's default load balancer + // implementation. + // Once set, it cannot be changed. The value must be a label-style identifier, with an optional prefix such as + // "internal-vip" or "example.com/internal-vip". + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#load-balancer-class + // +optional + LoadBalancerClass *string `json:"loadBalancerClass,omitempty"` + // ServiceAnnotations is an extra set of annotations for service of karmada apiserver. // more info: https://github.com/karmada-io/karmada/issues/4634 // +optional diff --git a/operator/v1alpha1/zz_generated.deepcopy.go b/operator/v1alpha1/zz_generated.deepcopy.go index 3bbb0ce..69c643e 100644 --- a/operator/v1alpha1/zz_generated.deepcopy.go +++ b/operator/v1alpha1/zz_generated.deepcopy.go @@ -114,6 +114,11 @@ func (in *CustomCertificate) DeepCopyInto(out *CustomCertificate) { *out = new(LocalSecretReference) **out = **in } + if in.LeafCertValidityDays != nil { + in, out := &in.LeafCertValidityDays, &out.LeafCertValidityDays + *out = new(int32) + **out = **in + } return } @@ -301,6 +306,11 @@ func (in *KarmadaAPIServer) DeepCopyInto(out *KarmadaAPIServer) { *out = new(string) **out = **in } + if in.LoadBalancerClass != nil { + in, out := &in.LoadBalancerClass, &out.LoadBalancerClass + *out = new(string) + **out = **in + } if in.ServiceAnnotations != nil { in, out := &in.ServiceAnnotations, &out.ServiceAnnotations *out = make(map[string]string, len(*in)) @@ -670,6 +680,11 @@ func (in *KarmadaSpec) DeepCopyInto(out *KarmadaSpec) { *out = new(CustomCertificate) (*in).DeepCopyInto(*out) } + if in.Suspend != nil { + in, out := &in.Suspend, &out.Suspend + *out = new(bool) + **out = **in + } return } diff --git a/policy/v1alpha1/clustertaint_types.go b/policy/v1alpha1/clustertaint_types.go new file mode 100644 index 0000000..d2faf18 --- /dev/null +++ b/policy/v1alpha1/clustertaint_types.go @@ -0,0 +1,129 @@ +/* +Copyright 2025 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 ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +// +kubebuilder:resource:path=clustertaintpolicies,scope="Cluster" +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ClusterTaintPolicy automates taint management on Cluster objects based +// on declarative conditions. +// The system evaluates AddOnConditions to determine when to add taints, +// and RemoveOnConditions to determine when to remove taints. +// AddOnConditions are evaluated before RemoveOnConditions. +// Taints are NEVER automatically removed when the ClusterTaintPolicy is deleted. +type ClusterTaintPolicy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec represents the desired behavior of ClusterTaintPolicy. + // +required + Spec ClusterTaintPolicySpec `json:"spec"` +} + +// ClusterTaintPolicySpec represents the desired behavior of ClusterTaintPolicy. +type ClusterTaintPolicySpec struct { + // TargetClusters specifies the clusters that ClusterTaintPolicy needs + // to pay attention to. + // For clusters that no longer match the TargetClusters, the taints + // will be kept unchanged. + // If targetClusters is not set, any cluster can be selected. + // +optional + TargetClusters *ClusterAffinity `json:"targetClusters,omitempty"` + + // AddOnConditions defines the conditions to match for triggering + // the controller to add taints on the cluster object. + // The match conditions are ANDed. + // If AddOnConditions is empty, no taints will be added. + // +optional + AddOnConditions []MatchCondition `json:"addOnConditions,omitempty"` + + // RemoveOnConditions defines the conditions to match for triggering + // the controller to remove taints from the cluster object. + // The match conditions are ANDed. + // If RemoveOnConditions is empty, no taints will be removed. + // +optional + RemoveOnConditions []MatchCondition `json:"removeOnConditions,omitempty"` + + // Taints specifies the taints that need to be added or removed on + // the cluster object which match with TargetClusters. + // If the Taints is modified, the system will process the taints based on + // the latest value of Taints during the next condition-triggered execution, + // regardless of whether the taint has been added or removed. + // +kubebuilder:validation:MinItems=1 + // +required + Taints []Taint `json:"taints"` +} + +// MatchCondition represents the condition match detail of activating the failover +// relevant taints on target clusters. +type MatchCondition struct { + // ConditionType specifies the ClusterStatus condition type. + // +required + ConditionType string `json:"conditionType"` + + // Operator represents a relationship to a set of values. + // Valid operators are In, NotIn. + // +required + Operator MatchConditionOperator `json:"operator"` + + // StatusValues is an array of metav1.ConditionStatus values. + // The item specifies the ClusterStatus condition status. + // +required + StatusValues []metav1.ConditionStatus `json:"statusValues"` +} + +// A MatchConditionOperator operator is the set of operators that can be used in the match condition. +type MatchConditionOperator string + +const ( + // MatchConditionOpIn represents the operator In. + MatchConditionOpIn MatchConditionOperator = "In" + // MatchConditionOpNotIn represents the operator NotIn. + MatchConditionOpNotIn MatchConditionOperator = "NotIn" +) + +// Taint describes the taint that needs to be applied to the cluster. +type Taint struct { + // Key represents the taint key to be applied to a cluster. + // +required + Key string `json:"key"` + + // Effect represents the taint effect to be applied to a cluster. + // +required + Effect corev1.TaintEffect `json:"effect"` + + // Value represents the taint value corresponding to the taint key. + // +optional + Value string `json:"value,omitempty"` +} + +// +kubebuilder:resource:scope="Cluster" +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ClusterTaintPolicyList contains a list of ClusterTaintPolicy +type ClusterTaintPolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterTaintPolicy `json:"items"` +} diff --git a/policy/v1alpha1/federatedresourcequota_types.go b/policy/v1alpha1/federatedresourcequota_types.go index 21690cf..4c04381 100644 --- a/policy/v1alpha1/federatedresourcequota_types.go +++ b/policy/v1alpha1/federatedresourcequota_types.go @@ -37,6 +37,8 @@ const ( // +kubebuilder:resource:path=federatedresourcequotas,scope=Namespaced,categories={karmada-io} // +kubebuilder:subresource:status // +kubebuilder:storageversion +// +kubebuilder:printcolumn:JSONPath=`.status.overall`,name=`OVERALL`,type=string +// +kubebuilder:printcolumn:JSONPath=`.status.overallUsed`,name=`OVERALL_USED`,type=string // FederatedResourceQuota sets aggregate quota restrictions enforced per namespace across all clusters. type FederatedResourceQuota struct { @@ -58,9 +60,16 @@ type FederatedResourceQuotaSpec struct { // +required Overall corev1.ResourceList `json:"overall"` - // StaticAssignments represents the subset of desired hard limits for each cluster. - // Note: for clusters not present in this list, Karmada will set an empty ResourceQuota to them, which means these - // clusters will have no quotas in the referencing namespace. + // StaticAssignments specifies ResourceQuota settings for specific clusters. + // If non-empty, Karmada will create ResourceQuotas in the corresponding clusters. + // Clusters not listed here or when StaticAssignments is empty will have no ResourceQuotas created. + // + // This field addresses multi-cluster configuration management challenges by allowing centralized + // control over ResourceQuotas across clusters. + // + // Note: The Karmada scheduler currently does NOT use this configuration for scheduling decisions. + // Future updates may integrate it into the scheduling logic. + // // +optional StaticAssignments []StaticClusterAssignment `json:"staticAssignments,omitempty"` diff --git a/policy/v1alpha1/zz_generated.deepcopy.go b/policy/v1alpha1/zz_generated.deepcopy.go index 6d86fad..2688536 100644 --- a/policy/v1alpha1/zz_generated.deepcopy.go +++ b/policy/v1alpha1/zz_generated.deepcopy.go @@ -267,6 +267,106 @@ func (in *ClusterQuotaStatus) DeepCopy() *ClusterQuotaStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTaintPolicy) DeepCopyInto(out *ClusterTaintPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTaintPolicy. +func (in *ClusterTaintPolicy) DeepCopy() *ClusterTaintPolicy { + if in == nil { + return nil + } + out := new(ClusterTaintPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTaintPolicy) 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 *ClusterTaintPolicyList) DeepCopyInto(out *ClusterTaintPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTaintPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTaintPolicyList. +func (in *ClusterTaintPolicyList) DeepCopy() *ClusterTaintPolicyList { + if in == nil { + return nil + } + out := new(ClusterTaintPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTaintPolicyList) 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 *ClusterTaintPolicySpec) DeepCopyInto(out *ClusterTaintPolicySpec) { + *out = *in + if in.TargetClusters != nil { + in, out := &in.TargetClusters, &out.TargetClusters + *out = new(ClusterAffinity) + (*in).DeepCopyInto(*out) + } + if in.AddOnConditions != nil { + in, out := &in.AddOnConditions, &out.AddOnConditions + *out = make([]MatchCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RemoveOnConditions != nil { + in, out := &in.RemoveOnConditions, &out.RemoveOnConditions + *out = make([]MatchCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Taints != nil { + in, out := &in.Taints, &out.Taints + *out = make([]Taint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTaintPolicySpec. +func (in *ClusterTaintPolicySpec) DeepCopy() *ClusterTaintPolicySpec { + if in == nil { + return nil + } + out := new(ClusterTaintPolicySpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CommandArgsOverrider) DeepCopyInto(out *CommandArgsOverrider) { *out = *in @@ -588,6 +688,27 @@ func (in *LabelAnnotationOverrider) DeepCopy() *LabelAnnotationOverrider { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MatchCondition) DeepCopyInto(out *MatchCondition) { + *out = *in + if in.StatusValues != nil { + in, out := &in.StatusValues, &out.StatusValues + *out = make([]v1.ConditionStatus, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchCondition. +func (in *MatchCondition) DeepCopy() *MatchCondition { + if in == nil { + return nil + } + out := new(MatchCondition) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OverridePolicy) DeepCopyInto(out *OverridePolicy) { *out = *in @@ -1145,6 +1266,22 @@ func (in *Suspension) DeepCopy() *Suspension { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Taint) DeepCopyInto(out *Taint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Taint. +func (in *Taint) DeepCopy() *Taint { + if in == nil { + return nil + } + out := new(Taint) + 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 diff --git a/policy/v1alpha1/zz_generated.register.go b/policy/v1alpha1/zz_generated.register.go index 852c2eb..ab577f0 100644 --- a/policy/v1alpha1/zz_generated.register.go +++ b/policy/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. @@ -65,6 +65,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &ClusterOverridePolicyList{}, &ClusterPropagationPolicy{}, &ClusterPropagationPolicyList{}, + &ClusterTaintPolicy{}, + &ClusterTaintPolicyList{}, &FederatedResourceQuota{}, &FederatedResourceQuotaList{}, &OverridePolicy{}, diff --git a/remedy/v1alpha1/zz_generated.register.go b/remedy/v1alpha1/zz_generated.register.go index a79dcd8..d9e1caf 100644 --- a/remedy/v1alpha1/zz_generated.register.go +++ b/remedy/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/search/v1alpha1/zz_generated.register.go b/search/v1alpha1/zz_generated.register.go index ef37629..bfafa6b 100644 --- a/search/v1alpha1/zz_generated.register.go +++ b/search/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/work/v1alpha1/zz_generated.register.go b/work/v1alpha1/zz_generated.register.go index 248d47f..93991f3 100644 --- a/work/v1alpha1/zz_generated.register.go +++ b/work/v1alpha1/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects. diff --git a/work/v1alpha2/zz_generated.register.go b/work/v1alpha2/zz_generated.register.go index 98f26b1..9ed2d7d 100644 --- a/work/v1alpha2/zz_generated.register.go +++ b/work/v1alpha2/zz_generated.register.go @@ -23,8 +23,8 @@ package v1alpha2 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName specifies the group name used to register the objects.