feat(karmada-search): Implement SearchRegistry reconcile logic
Co-authored-by: liys87x <liyasong1987x@gmail.com> Signed-off-by: huntsman_ly <huntsman_ly@sina.com>
This commit is contained in:
parent
58c0bc4887
commit
de186ea043
|
@ -90,6 +90,16 @@ func (o *Options) Run(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
server.GenericAPIServer.AddPostStartHookOrDie("start-karmada-search-controller", func(context genericapiserver.PostStartHookContext) error {
|
||||||
|
// start ResourceRegistry controller
|
||||||
|
ctl, err := search.NewController(restConfig, search.CachedResourceHandler())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctl.Start(context.StopCh)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
return server.GenericAPIServer.PrepareRun().Run(ctx.Done())
|
return server.GenericAPIServer.PrepareRun().Run(ctx.Done())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package search
|
package search
|
||||||
|
|
||||||
import (
|
import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
|
@ -24,9 +25,9 @@ type ResourceRegistry struct {
|
||||||
|
|
||||||
// ResourceRegistrySpec defines the desired state of ResourceRegistry.
|
// ResourceRegistrySpec defines the desired state of ResourceRegistry.
|
||||||
type ResourceRegistrySpec struct {
|
type ResourceRegistrySpec struct {
|
||||||
// ClusterSelectors represents the filter to select clusters.
|
// TargetCluster is the cluster that the resource registry is targeting.
|
||||||
// +required
|
// +required
|
||||||
ClusterSelectors []ClusterSelector
|
TargetCluster *policyv1alpha1.ClusterAffinity `json:"targetCluster"`
|
||||||
|
|
||||||
// ResourceSelectors used to select resources.
|
// ResourceSelectors used to select resources.
|
||||||
// +required
|
// +required
|
||||||
|
@ -38,42 +39,15 @@ type ResourceRegistrySpec struct {
|
||||||
StatusUpdatePeriodSeconds uint32
|
StatusUpdatePeriodSeconds uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterSelector represents the filter to select clusters.
|
|
||||||
type ClusterSelector struct {
|
|
||||||
// LabelSelector is a filter to select member clusters by labels.
|
|
||||||
// If non-nil and non-empty, only the clusters match this filter will be selected.
|
|
||||||
// +optional
|
|
||||||
LabelSelector *metav1.LabelSelector
|
|
||||||
|
|
||||||
// FieldSelector is a filter to select member clusters by fields.
|
|
||||||
// If non-nil and non-empty, only the clusters match this filter will be selected.
|
|
||||||
// +optional
|
|
||||||
FieldSelector *FieldSelector
|
|
||||||
|
|
||||||
// ClusterNames is the list of clusters to be selected.
|
|
||||||
// +optional
|
|
||||||
ClusterNames []string
|
|
||||||
|
|
||||||
// ExcludedClusters is the list of clusters to be ignored.
|
|
||||||
// +optional
|
|
||||||
ExcludeClusters []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// FieldSelector is a field filter.
|
|
||||||
type FieldSelector struct {
|
|
||||||
// A list of field selector requirements.
|
|
||||||
MatchExpressions []corev1.NodeSelectorRequirement
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceSelector the resources will be selected.
|
// ResourceSelector the resources will be selected.
|
||||||
type ResourceSelector struct {
|
type ResourceSelector struct {
|
||||||
// APIVersion represents the API version of the target resources.
|
// APIVersion represents the API version of the target resources.
|
||||||
// +required
|
// +required
|
||||||
APIVersion string
|
APIVersion string
|
||||||
|
|
||||||
// Kind represents the Kind of the target resources.
|
// Kind represents the kind of the target resources.
|
||||||
// +required
|
// +required
|
||||||
Kind string
|
Kind string `json:"kind"`
|
||||||
|
|
||||||
// Namespace of the target resource.
|
// Namespace of the target resource.
|
||||||
// Default is empty, which means all namespaces.
|
// Default is empty, which means all namespaces.
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ResourceKindResourceRegistry is the name of the resource registry
|
// ResourceKindResourceRegistry is the name of the resource registry
|
||||||
ResourceKindResourceRegistry = "ResourceRegistry"
|
ResourceKindResourceRegistry = "ResourceRegistry"
|
||||||
// ResourceSingularResourceRegistry is singular name of ResourceRegistry.
|
// ResourceSingularResourceRegistry is singular name of ResourceRegistry.
|
||||||
ResourceSingularResourceRegistry = "resourceRegistry"
|
ResourceSingularResourceRegistry = "resourceregistry"
|
||||||
// ResourcePluralResourceRegistry is plural name of ResourceRegistry.
|
// ResourcePluralResourceRegistry is plural name of ResourceRegistry.
|
||||||
ResourcePluralResourceRegistry = "resourceRegistries"
|
ResourcePluralResourceRegistry = "resourceregistries"
|
||||||
// ResourceNamespaceScopedResourceRegistry is the scope of the ResourceRegistry
|
// ResourceNamespaceScopedResourceRegistry is the scope of the ResourceRegistry
|
||||||
ResourceNamespaceScopedResourceRegistry = false
|
ResourceNamespaceScopedResourceRegistry = false
|
||||||
)
|
)
|
||||||
|
@ -35,9 +36,9 @@ type ResourceRegistry struct {
|
||||||
|
|
||||||
// ResourceRegistrySpec defines the desired state of ResourceRegistry.
|
// ResourceRegistrySpec defines the desired state of ResourceRegistry.
|
||||||
type ResourceRegistrySpec struct {
|
type ResourceRegistrySpec struct {
|
||||||
// ClusterSelectors represents the filter to select clusters.
|
// TargetCluster is the cluster that the resource registry is targeting.
|
||||||
// +required
|
// +required
|
||||||
ClusterSelectors []ClusterSelector `json:"clusterSelectors"`
|
TargetCluster *policyv1alpha1.ClusterAffinity `json:"targetCluster"`
|
||||||
|
|
||||||
// ResourceSelectors used to select resources.
|
// ResourceSelectors used to select resources.
|
||||||
// +required
|
// +required
|
||||||
|
@ -49,40 +50,13 @@ type ResourceRegistrySpec struct {
|
||||||
StatusUpdatePeriodSeconds uint32 `json:"statusUpdatePeriodSeconds,omitempty"`
|
StatusUpdatePeriodSeconds uint32 `json:"statusUpdatePeriodSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterSelector represents the filter to select clusters.
|
|
||||||
type ClusterSelector struct {
|
|
||||||
// LabelSelector is a filter to select member clusters by labels.
|
|
||||||
// If non-nil and non-empty, only the clusters match this filter will be selected.
|
|
||||||
// +optional
|
|
||||||
LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
|
|
||||||
|
|
||||||
// FieldSelector is a filter to select member clusters by fields.
|
|
||||||
// If non-nil and non-empty, only the clusters match this filter will be selected.
|
|
||||||
// +optional
|
|
||||||
FieldSelector *FieldSelector `json:"fieldSelector,omitempty"`
|
|
||||||
|
|
||||||
// ClusterNames is the list of clusters to be selected.
|
|
||||||
// +optional
|
|
||||||
ClusterNames []string `json:"clusterNames,omitempty"`
|
|
||||||
|
|
||||||
// ExcludedClusters is the list of clusters to be ignored.
|
|
||||||
// +optional
|
|
||||||
ExcludeClusters []string `json:"exclude,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// FieldSelector is a field filter.
|
|
||||||
type FieldSelector struct {
|
|
||||||
// A list of field selector requirements.
|
|
||||||
MatchExpressions []corev1.NodeSelectorRequirement `json:"matchExpressions,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceSelector the resources will be selected.
|
// ResourceSelector the resources will be selected.
|
||||||
type ResourceSelector struct {
|
type ResourceSelector struct {
|
||||||
// APIVersion represents the API version of the target resources.
|
// APIVersion represents the API version of the target resources.
|
||||||
// +required
|
// +required
|
||||||
APIVersion string `json:"apiVersion"`
|
APIVersion string `json:"apiVersion"`
|
||||||
|
|
||||||
// Kind represents the Kind of the target resources.
|
// Kind represents the kind of the target resources.
|
||||||
// +required
|
// +required
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ package v1alpha1
|
||||||
import (
|
import (
|
||||||
unsafe "unsafe"
|
unsafe "unsafe"
|
||||||
|
|
||||||
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
search "github.com/karmada-io/karmada/pkg/apis/search"
|
search "github.com/karmada-io/karmada/pkg/apis/search"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
@ -22,26 +22,6 @@ func init() {
|
||||||
// RegisterConversions adds conversion functions to the given scheme.
|
// RegisterConversions adds conversion functions to the given scheme.
|
||||||
// Public to allow building arbitrary schemes.
|
// Public to allow building arbitrary schemes.
|
||||||
func RegisterConversions(s *runtime.Scheme) error {
|
func RegisterConversions(s *runtime.Scheme) error {
|
||||||
if err := s.AddGeneratedConversionFunc((*ClusterSelector)(nil), (*search.ClusterSelector)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
||||||
return Convert_v1alpha1_ClusterSelector_To_search_ClusterSelector(a.(*ClusterSelector), b.(*search.ClusterSelector), scope)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.AddGeneratedConversionFunc((*search.ClusterSelector)(nil), (*ClusterSelector)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
||||||
return Convert_search_ClusterSelector_To_v1alpha1_ClusterSelector(a.(*search.ClusterSelector), b.(*ClusterSelector), scope)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.AddGeneratedConversionFunc((*FieldSelector)(nil), (*search.FieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
||||||
return Convert_v1alpha1_FieldSelector_To_search_FieldSelector(a.(*FieldSelector), b.(*search.FieldSelector), scope)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.AddGeneratedConversionFunc((*search.FieldSelector)(nil), (*FieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
||||||
return Convert_search_FieldSelector_To_v1alpha1_FieldSelector(a.(*search.FieldSelector), b.(*FieldSelector), scope)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.AddGeneratedConversionFunc((*ResourceRegistry)(nil), (*search.ResourceRegistry)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
if err := s.AddGeneratedConversionFunc((*ResourceRegistry)(nil), (*search.ResourceRegistry)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
return Convert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(a.(*ResourceRegistry), b.(*search.ResourceRegistry), scope)
|
return Convert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(a.(*ResourceRegistry), b.(*search.ResourceRegistry), scope)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -105,52 +85,6 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoConvert_v1alpha1_ClusterSelector_To_search_ClusterSelector(in *ClusterSelector, out *search.ClusterSelector, s conversion.Scope) error {
|
|
||||||
out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector))
|
|
||||||
out.FieldSelector = (*search.FieldSelector)(unsafe.Pointer(in.FieldSelector))
|
|
||||||
out.ClusterNames = *(*[]string)(unsafe.Pointer(&in.ClusterNames))
|
|
||||||
out.ExcludeClusters = *(*[]string)(unsafe.Pointer(&in.ExcludeClusters))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert_v1alpha1_ClusterSelector_To_search_ClusterSelector is an autogenerated conversion function.
|
|
||||||
func Convert_v1alpha1_ClusterSelector_To_search_ClusterSelector(in *ClusterSelector, out *search.ClusterSelector, s conversion.Scope) error {
|
|
||||||
return autoConvert_v1alpha1_ClusterSelector_To_search_ClusterSelector(in, out, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autoConvert_search_ClusterSelector_To_v1alpha1_ClusterSelector(in *search.ClusterSelector, out *ClusterSelector, s conversion.Scope) error {
|
|
||||||
out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector))
|
|
||||||
out.FieldSelector = (*FieldSelector)(unsafe.Pointer(in.FieldSelector))
|
|
||||||
out.ClusterNames = *(*[]string)(unsafe.Pointer(&in.ClusterNames))
|
|
||||||
out.ExcludeClusters = *(*[]string)(unsafe.Pointer(&in.ExcludeClusters))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert_search_ClusterSelector_To_v1alpha1_ClusterSelector is an autogenerated conversion function.
|
|
||||||
func Convert_search_ClusterSelector_To_v1alpha1_ClusterSelector(in *search.ClusterSelector, out *ClusterSelector, s conversion.Scope) error {
|
|
||||||
return autoConvert_search_ClusterSelector_To_v1alpha1_ClusterSelector(in, out, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autoConvert_v1alpha1_FieldSelector_To_search_FieldSelector(in *FieldSelector, out *search.FieldSelector, s conversion.Scope) error {
|
|
||||||
out.MatchExpressions = *(*[]corev1.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert_v1alpha1_FieldSelector_To_search_FieldSelector is an autogenerated conversion function.
|
|
||||||
func Convert_v1alpha1_FieldSelector_To_search_FieldSelector(in *FieldSelector, out *search.FieldSelector, s conversion.Scope) error {
|
|
||||||
return autoConvert_v1alpha1_FieldSelector_To_search_FieldSelector(in, out, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autoConvert_search_FieldSelector_To_v1alpha1_FieldSelector(in *search.FieldSelector, out *FieldSelector, s conversion.Scope) error {
|
|
||||||
out.MatchExpressions = *(*[]corev1.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert_search_FieldSelector_To_v1alpha1_FieldSelector is an autogenerated conversion function.
|
|
||||||
func Convert_search_FieldSelector_To_v1alpha1_FieldSelector(in *search.FieldSelector, out *FieldSelector, s conversion.Scope) error {
|
|
||||||
return autoConvert_search_FieldSelector_To_v1alpha1_FieldSelector(in, out, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autoConvert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(in *ResourceRegistry, out *search.ResourceRegistry, s conversion.Scope) error {
|
func autoConvert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(in *ResourceRegistry, out *search.ResourceRegistry, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(&in.Spec, &out.Spec, s); err != nil {
|
if err := Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(&in.Spec, &out.Spec, s); err != nil {
|
||||||
|
@ -206,7 +140,7 @@ func Convert_search_ResourceRegistryList_To_v1alpha1_ResourceRegistryList(in *se
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoConvert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(in *ResourceRegistrySpec, out *search.ResourceRegistrySpec, s conversion.Scope) error {
|
func autoConvert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(in *ResourceRegistrySpec, out *search.ResourceRegistrySpec, s conversion.Scope) error {
|
||||||
out.ClusterSelectors = *(*[]search.ClusterSelector)(unsafe.Pointer(&in.ClusterSelectors))
|
out.TargetCluster = (*policyv1alpha1.ClusterAffinity)(unsafe.Pointer(in.TargetCluster))
|
||||||
out.ResourceSelectors = *(*[]search.ResourceSelector)(unsafe.Pointer(&in.ResourceSelectors))
|
out.ResourceSelectors = *(*[]search.ResourceSelector)(unsafe.Pointer(&in.ResourceSelectors))
|
||||||
out.StatusUpdatePeriodSeconds = in.StatusUpdatePeriodSeconds
|
out.StatusUpdatePeriodSeconds = in.StatusUpdatePeriodSeconds
|
||||||
return nil
|
return nil
|
||||||
|
@ -218,7 +152,7 @@ func Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(in *Re
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoConvert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(in *search.ResourceRegistrySpec, out *ResourceRegistrySpec, s conversion.Scope) error {
|
func autoConvert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(in *search.ResourceRegistrySpec, out *ResourceRegistrySpec, s conversion.Scope) error {
|
||||||
out.ClusterSelectors = *(*[]ClusterSelector)(unsafe.Pointer(&in.ClusterSelectors))
|
out.TargetCluster = (*policyv1alpha1.ClusterAffinity)(unsafe.Pointer(in.TargetCluster))
|
||||||
out.ResourceSelectors = *(*[]ResourceSelector)(unsafe.Pointer(&in.ResourceSelectors))
|
out.ResourceSelectors = *(*[]ResourceSelector)(unsafe.Pointer(&in.ResourceSelectors))
|
||||||
out.StatusUpdatePeriodSeconds = in.StatusUpdatePeriodSeconds
|
out.StatusUpdatePeriodSeconds = in.StatusUpdatePeriodSeconds
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,70 +6,11 @@
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
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 *ClusterSelector) DeepCopyInto(out *ClusterSelector) {
|
|
||||||
*out = *in
|
|
||||||
if in.LabelSelector != nil {
|
|
||||||
in, out := &in.LabelSelector, &out.LabelSelector
|
|
||||||
*out = new(v1.LabelSelector)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.FieldSelector != nil {
|
|
||||||
in, out := &in.FieldSelector, &out.FieldSelector
|
|
||||||
*out = new(FieldSelector)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.ClusterNames != nil {
|
|
||||||
in, out := &in.ClusterNames, &out.ClusterNames
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.ExcludeClusters != nil {
|
|
||||||
in, out := &in.ExcludeClusters, &out.ExcludeClusters
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSelector.
|
|
||||||
func (in *ClusterSelector) DeepCopy() *ClusterSelector {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(ClusterSelector)
|
|
||||||
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
|
|
||||||
if in.MatchExpressions != nil {
|
|
||||||
in, out := &in.MatchExpressions, &out.MatchExpressions
|
|
||||||
*out = make([]corev1.NodeSelectorRequirement, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FieldSelector.
|
|
||||||
func (in *FieldSelector) DeepCopy() *FieldSelector {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(FieldSelector)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ResourceRegistry) DeepCopyInto(out *ResourceRegistry) {
|
func (in *ResourceRegistry) DeepCopyInto(out *ResourceRegistry) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -134,12 +75,10 @@ func (in *ResourceRegistryList) DeepCopyObject() runtime.Object {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ResourceRegistrySpec) DeepCopyInto(out *ResourceRegistrySpec) {
|
func (in *ResourceRegistrySpec) DeepCopyInto(out *ResourceRegistrySpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.ClusterSelectors != nil {
|
if in.TargetCluster != nil {
|
||||||
in, out := &in.ClusterSelectors, &out.ClusterSelectors
|
in, out := &in.TargetCluster, &out.TargetCluster
|
||||||
*out = make([]ClusterSelector, len(*in))
|
*out = new(policyv1alpha1.ClusterAffinity)
|
||||||
for i := range *in {
|
(*in).DeepCopyInto(*out)
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if in.ResourceSelectors != nil {
|
if in.ResourceSelectors != nil {
|
||||||
in, out := &in.ResourceSelectors, &out.ResourceSelectors
|
in, out := &in.ResourceSelectors, &out.ResourceSelectors
|
||||||
|
|
|
@ -6,70 +6,11 @@
|
||||||
package search
|
package search
|
||||||
|
|
||||||
import (
|
import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
v1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
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 *ClusterSelector) DeepCopyInto(out *ClusterSelector) {
|
|
||||||
*out = *in
|
|
||||||
if in.LabelSelector != nil {
|
|
||||||
in, out := &in.LabelSelector, &out.LabelSelector
|
|
||||||
*out = new(v1.LabelSelector)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.FieldSelector != nil {
|
|
||||||
in, out := &in.FieldSelector, &out.FieldSelector
|
|
||||||
*out = new(FieldSelector)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.ClusterNames != nil {
|
|
||||||
in, out := &in.ClusterNames, &out.ClusterNames
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.ExcludeClusters != nil {
|
|
||||||
in, out := &in.ExcludeClusters, &out.ExcludeClusters
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSelector.
|
|
||||||
func (in *ClusterSelector) DeepCopy() *ClusterSelector {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(ClusterSelector)
|
|
||||||
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
|
|
||||||
if in.MatchExpressions != nil {
|
|
||||||
in, out := &in.MatchExpressions, &out.MatchExpressions
|
|
||||||
*out = make([]corev1.NodeSelectorRequirement, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FieldSelector.
|
|
||||||
func (in *FieldSelector) DeepCopy() *FieldSelector {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(FieldSelector)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ResourceRegistry) DeepCopyInto(out *ResourceRegistry) {
|
func (in *ResourceRegistry) DeepCopyInto(out *ResourceRegistry) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -134,12 +75,10 @@ func (in *ResourceRegistryList) DeepCopyObject() runtime.Object {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ResourceRegistrySpec) DeepCopyInto(out *ResourceRegistrySpec) {
|
func (in *ResourceRegistrySpec) DeepCopyInto(out *ResourceRegistrySpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.ClusterSelectors != nil {
|
if in.TargetCluster != nil {
|
||||||
in, out := &in.ClusterSelectors, &out.ClusterSelectors
|
in, out := &in.TargetCluster, &out.TargetCluster
|
||||||
*out = make([]ClusterSelector, len(*in))
|
*out = new(v1alpha1.ClusterAffinity)
|
||||||
for i := range *in {
|
(*in).DeepCopyInto(*out)
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if in.ResourceSelectors != nil {
|
if in.ResourceSelectors != nil {
|
||||||
in, out := &in.ResourceSelectors, &out.ResourceSelectors
|
in, out := &in.ResourceSelectors, &out.ResourceSelectors
|
||||||
|
|
|
@ -69,8 +69,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||||
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.SpreadConstraint": schema_pkg_apis_policy_v1alpha1_SpreadConstraint(ref),
|
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.SpreadConstraint": schema_pkg_apis_policy_v1alpha1_SpreadConstraint(ref),
|
||||||
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.StaticClusterAssignment": schema_pkg_apis_policy_v1alpha1_StaticClusterAssignment(ref),
|
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.StaticClusterAssignment": schema_pkg_apis_policy_v1alpha1_StaticClusterAssignment(ref),
|
||||||
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.StaticClusterWeight": schema_pkg_apis_policy_v1alpha1_StaticClusterWeight(ref),
|
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.StaticClusterWeight": schema_pkg_apis_policy_v1alpha1_StaticClusterWeight(ref),
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ClusterSelector": schema_pkg_apis_search_v1alpha1_ClusterSelector(ref),
|
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.FieldSelector": schema_pkg_apis_search_v1alpha1_FieldSelector(ref),
|
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistry": schema_pkg_apis_search_v1alpha1_ResourceRegistry(ref),
|
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistry": schema_pkg_apis_search_v1alpha1_ResourceRegistry(ref),
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistryList": schema_pkg_apis_search_v1alpha1_ResourceRegistryList(ref),
|
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistryList": schema_pkg_apis_search_v1alpha1_ResourceRegistryList(ref),
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistrySpec": schema_pkg_apis_search_v1alpha1_ResourceRegistrySpec(ref),
|
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistrySpec": schema_pkg_apis_search_v1alpha1_ResourceRegistrySpec(ref),
|
||||||
|
@ -2979,92 +2977,6 @@ func schema_pkg_apis_policy_v1alpha1_StaticClusterWeight(ref common.ReferenceCal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func schema_pkg_apis_search_v1alpha1_ClusterSelector(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
|
||||||
return common.OpenAPIDefinition{
|
|
||||||
Schema: spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "ClusterSelector represents the filter to select clusters.",
|
|
||||||
Type: []string{"object"},
|
|
||||||
Properties: map[string]spec.Schema{
|
|
||||||
"labelSelector": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "LabelSelector is a filter to select member clusters by labels. If non-nil and non-empty, only the clusters match this filter will be selected.",
|
|
||||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"fieldSelector": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "FieldSelector is a filter to select member clusters by fields. If non-nil and non-empty, only the clusters match this filter will be selected.",
|
|
||||||
Ref: ref("github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.FieldSelector"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"clusterNames": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "ClusterNames is the list of clusters to be selected.",
|
|
||||||
Type: []string{"array"},
|
|
||||||
Items: &spec.SchemaOrArray{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: "",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"exclude": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "ExcludedClusters is the list of clusters to be ignored.",
|
|
||||||
Type: []string{"array"},
|
|
||||||
Items: &spec.SchemaOrArray{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: "",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Dependencies: []string{
|
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.FieldSelector", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func schema_pkg_apis_search_v1alpha1_FieldSelector(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
|
||||||
return common.OpenAPIDefinition{
|
|
||||||
Schema: spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "FieldSelector is a field filter.",
|
|
||||||
Type: []string{"object"},
|
|
||||||
Properties: map[string]spec.Schema{
|
|
||||||
"matchExpressions": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "A list of field selector requirements.",
|
|
||||||
Type: []string{"array"},
|
|
||||||
Items: &spec.SchemaOrArray{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: map[string]interface{}{},
|
|
||||||
Ref: ref("k8s.io/api/core/v1.NodeSelectorRequirement"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Dependencies: []string{
|
|
||||||
"k8s.io/api/core/v1.NodeSelectorRequirement"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func schema_pkg_apis_search_v1alpha1_ResourceRegistry(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
func schema_pkg_apis_search_v1alpha1_ResourceRegistry(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
Schema: spec.Schema{
|
||||||
|
@ -3171,18 +3083,10 @@ func schema_pkg_apis_search_v1alpha1_ResourceRegistrySpec(ref common.ReferenceCa
|
||||||
Description: "ResourceRegistrySpec defines the desired state of ResourceRegistry.",
|
Description: "ResourceRegistrySpec defines the desired state of ResourceRegistry.",
|
||||||
Type: []string{"object"},
|
Type: []string{"object"},
|
||||||
Properties: map[string]spec.Schema{
|
Properties: map[string]spec.Schema{
|
||||||
"clusterSelectors": {
|
"targetCluster": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "ClusterSelectors represents the filter to select clusters.",
|
Description: "TargetCluster is the cluster that the resource registry is targeting.",
|
||||||
Type: []string{"array"},
|
Ref: ref("github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.ClusterAffinity"),
|
||||||
Items: &spec.SchemaOrArray{
|
|
||||||
Schema: &spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: map[string]interface{}{},
|
|
||||||
Ref: ref("github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ClusterSelector"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"resourceSelectors": {
|
"resourceSelectors": {
|
||||||
|
@ -3207,11 +3111,11 @@ func schema_pkg_apis_search_v1alpha1_ResourceRegistrySpec(ref common.ReferenceCa
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Required: []string{"clusterSelectors", "resourceSelectors"},
|
Required: []string{"targetCluster", "resourceSelectors"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []string{
|
Dependencies: []string{
|
||||||
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ClusterSelector", "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceSelector"},
|
"github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1.ClusterAffinity", "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceSelector"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3261,7 +3165,7 @@ func schema_pkg_apis_search_v1alpha1_ResourceSelector(ref common.ReferenceCallba
|
||||||
},
|
},
|
||||||
"kind": {
|
"kind": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "Kind represents the Kind of the target resources.",
|
Description: "Kind represents the kind of the target resources.",
|
||||||
Default: "",
|
Default: "",
|
||||||
Type: []string{"string"},
|
Type: []string{"string"},
|
||||||
Format: "",
|
Format: "",
|
||||||
|
|
|
@ -105,8 +105,8 @@ func (c completedConfig) New(kubeClient kubernetes.Interface) (*APIServer, error
|
||||||
searchREST := searchstorage.NewSearchREST(kubeClient)
|
searchREST := searchstorage.NewSearchREST(kubeClient)
|
||||||
|
|
||||||
v1alpha1search := map[string]rest.Storage{}
|
v1alpha1search := map[string]rest.Storage{}
|
||||||
v1alpha1search["resourceRegistry"] = resourceRegistryStorage.ResourceRegistry
|
v1alpha1search["resourceregistries"] = resourceRegistryStorage.ResourceRegistry
|
||||||
v1alpha1search["resourceRegistry/status"] = resourceRegistryStorage.Status
|
v1alpha1search["resourceregistries/status"] = resourceRegistryStorage.Status
|
||||||
v1alpha1search["search"] = searchREST
|
v1alpha1search["search"] = searchREST
|
||||||
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1search
|
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1search
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,391 @@
|
||||||
|
package search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
"k8s.io/client-go/util/workqueue"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||||
|
|
||||||
|
clusterV1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
|
||||||
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
|
"github.com/karmada-io/karmada/pkg/apis/search/v1alpha1"
|
||||||
|
karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
|
||||||
|
informerfactory "github.com/karmada-io/karmada/pkg/generated/informers/externalversions"
|
||||||
|
clusterlister "github.com/karmada-io/karmada/pkg/generated/listers/cluster/v1alpha1"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util/gclient"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util/informermanager"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util/restmapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clusterRegistry struct {
|
||||||
|
registries map[string]struct{}
|
||||||
|
resources map[schema.GroupVersionResource]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *clusterRegistry) unregistry() bool {
|
||||||
|
return len(c.registries) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller ResourceRegistry controller
|
||||||
|
type Controller struct {
|
||||||
|
restConfig *rest.Config
|
||||||
|
restMapper meta.RESTMapper
|
||||||
|
informerFactory informerfactory.SharedInformerFactory
|
||||||
|
clusterLister clusterlister.ClusterLister
|
||||||
|
queue workqueue.RateLimitingInterface
|
||||||
|
|
||||||
|
clusterRegistry sync.Map
|
||||||
|
|
||||||
|
resourceHandler cache.ResourceEventHandler
|
||||||
|
InformerManager informermanager.MultiClusterInformerManager
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewController returns a new ResourceRegistry controller
|
||||||
|
func NewController(restConfig *rest.Config, rh cache.ResourceEventHandler) (*Controller, error) {
|
||||||
|
karmadaClient := karmadaclientset.NewForConfigOrDie(restConfig)
|
||||||
|
factory := informerfactory.NewSharedInformerFactory(karmadaClient, 0)
|
||||||
|
clusterLister := factory.Cluster().V1alpha1().Clusters().Lister()
|
||||||
|
restMapper, err := apiutil.NewDynamicRESTMapper(restConfig)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("Failed to create REST mapper: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||||
|
|
||||||
|
c := &Controller{
|
||||||
|
restConfig: restConfig,
|
||||||
|
informerFactory: factory,
|
||||||
|
clusterLister: clusterLister,
|
||||||
|
queue: queue,
|
||||||
|
restMapper: restMapper,
|
||||||
|
|
||||||
|
resourceHandler: rh,
|
||||||
|
InformerManager: informermanager.GetInstance(),
|
||||||
|
}
|
||||||
|
c.addAllEventHandlers()
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addAllEventHandlers adds all event handlers to the informer
|
||||||
|
func (c *Controller) addAllEventHandlers() {
|
||||||
|
clusterInformer := c.informerFactory.Cluster().V1alpha1().Clusters().Informer()
|
||||||
|
clusterInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: c.addCluster,
|
||||||
|
UpdateFunc: c.updateCluster,
|
||||||
|
DeleteFunc: c.deleteCluster,
|
||||||
|
})
|
||||||
|
|
||||||
|
resourceRegistryInformer := c.informerFactory.Search().V1alpha1().ResourceRegistries().Informer()
|
||||||
|
resourceRegistryInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: c.addResourceRegistry,
|
||||||
|
UpdateFunc: c.updateResourceRegistry,
|
||||||
|
DeleteFunc: c.deleteResourceRegistry,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the controller
|
||||||
|
func (c *Controller) Start(stopCh <-chan struct{}) {
|
||||||
|
klog.Infof("Starting karmada search controller")
|
||||||
|
|
||||||
|
defer runtime.HandleCrash()
|
||||||
|
|
||||||
|
c.informerFactory.Start(stopCh)
|
||||||
|
c.informerFactory.WaitForCacheSync(stopCh)
|
||||||
|
|
||||||
|
go wait.Until(c.worker, time.Second, stopCh)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-stopCh
|
||||||
|
informermanager.StopInstance()
|
||||||
|
klog.Infof("Shutting down karmada search controller")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// worker processes the queue of resourceRegistry objects.
|
||||||
|
func (c *Controller) worker() {
|
||||||
|
for c.cacheNext() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheNext processes the next cluster object in the queue.
|
||||||
|
func (c *Controller) cacheNext() bool {
|
||||||
|
// Wait until there is a new item in the working queue
|
||||||
|
key, shutdown := c.queue.Get()
|
||||||
|
if shutdown {
|
||||||
|
klog.Errorf("Fail to pop item from queue")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the queue that we are done with processing this key. This unblocks the key for other workers
|
||||||
|
// This allows safe parallel processing because two pods with the same key are never processed in
|
||||||
|
// parallel.
|
||||||
|
defer c.queue.Done(key)
|
||||||
|
|
||||||
|
err := c.doCacheCluster(key.(string))
|
||||||
|
// Handle the error if something went wrong during the execution of the business logic
|
||||||
|
c.handleErr(err, key)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleErr checks if an error happened and makes sure we will retry later.
|
||||||
|
func (c *Controller) handleErr(err error, key interface{}) {
|
||||||
|
if err == nil {
|
||||||
|
c.queue.Forget(key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
klog.Errorf("Error cache memeber cluster %v, %v", key, err)
|
||||||
|
c.queue.AddRateLimited(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// doCacheCluster processes the resourceRegistry object
|
||||||
|
// TODO: update status
|
||||||
|
func (c *Controller) doCacheCluster(cluster string) error {
|
||||||
|
// STEP0: stop informer manager for the cluster which is not referenced by any `SearchRegistry` object.
|
||||||
|
v, ok := c.clusterRegistry.Load(cluster)
|
||||||
|
if !ok {
|
||||||
|
klog.Infof("Cluster %s is not registered", cluster)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cr := v.(clusterRegistry)
|
||||||
|
if cr.unregistry() {
|
||||||
|
klog.Infof("try to stop cluster informer %s", cluster)
|
||||||
|
c.InformerManager.Stop(cluster)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP1: stop informer manager for the cluster which does not exist anymore.
|
||||||
|
cls, err := c.clusterLister.Get(cluster)
|
||||||
|
if err != nil {
|
||||||
|
if apierrors.IsNotFound(err) {
|
||||||
|
klog.Infof("try to stop cluster informer %s", cluster)
|
||||||
|
c.InformerManager.Stop(cluster)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cls.DeletionTimestamp.IsZero() {
|
||||||
|
klog.Infof("try to stop cluster informer %s", cluster)
|
||||||
|
c.InformerManager.Stop(cluster)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP2: added/updated cluster, builds an informer manager for a specific cluster.
|
||||||
|
if !c.InformerManager.IsManagerExist(cluster) {
|
||||||
|
klog.Info("try to build informer manager for cluster ", cluster)
|
||||||
|
controlPlaneClient := gclient.NewForConfigOrDie(c.restConfig)
|
||||||
|
|
||||||
|
clusterDynamicClient, err := util.NewClusterDynamicClientSet(cluster, controlPlaneClient)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = c.InformerManager.ForCluster(cluster, clusterDynamicClient.DynamicClientSet, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.resourceHandler != nil {
|
||||||
|
sci := c.InformerManager.GetSingleClusterManager(cluster)
|
||||||
|
for gvr := range cr.resources {
|
||||||
|
klog.Infof("try to start informer for %s, %v", cluster, gvr)
|
||||||
|
// TODO: gvr exists check
|
||||||
|
sci.ForResource(gvr, c.resourceHandler)
|
||||||
|
}
|
||||||
|
sci.Start()
|
||||||
|
_ = sci.WaitForCacheSync()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addResourceRegistry parse the resourceRegistry object and add Cluster to the queue
|
||||||
|
func (c *Controller) addResourceRegistry(obj interface{}) {
|
||||||
|
rr := obj.(*v1alpha1.ResourceRegistry)
|
||||||
|
resources := c.getResources(rr.Spec.ResourceSelectors)
|
||||||
|
|
||||||
|
for _, cluster := range c.getClusters(*rr.Spec.TargetCluster) {
|
||||||
|
v, _ := c.clusterRegistry.LoadOrStore(cluster, clusterRegistry{
|
||||||
|
resources: make(map[schema.GroupVersionResource]struct{}),
|
||||||
|
registries: make(map[string]struct{})})
|
||||||
|
cr := v.(clusterRegistry)
|
||||||
|
|
||||||
|
for _, r := range resources {
|
||||||
|
cr.resources[r] = struct{}{}
|
||||||
|
}
|
||||||
|
cr.registries[rr.GetName()] = struct{}{}
|
||||||
|
c.clusterRegistry.Store(cluster, cr)
|
||||||
|
|
||||||
|
c.queue.Add(cluster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateResourceRegistry parse the resourceRegistry object and add (added/deleted) Cluster to the queue
|
||||||
|
func (c *Controller) updateResourceRegistry(oldObj, newObj interface{}) {
|
||||||
|
oldRR := oldObj.(*v1alpha1.ResourceRegistry)
|
||||||
|
newRR := newObj.(*v1alpha1.ResourceRegistry)
|
||||||
|
|
||||||
|
// TODO: stop resource informers if it is not in the new resource registry
|
||||||
|
resources := c.getResources(newRR.Spec.ResourceSelectors)
|
||||||
|
|
||||||
|
clusters := c.getClusters(*newRR.Spec.TargetCluster)
|
||||||
|
clusterSets := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, cls := range clusters {
|
||||||
|
v, _ := c.clusterRegistry.LoadOrStore(cls, clusterRegistry{
|
||||||
|
resources: make(map[schema.GroupVersionResource]struct{}),
|
||||||
|
registries: make(map[string]struct{})})
|
||||||
|
cr := v.(clusterRegistry)
|
||||||
|
|
||||||
|
for _, r := range resources {
|
||||||
|
cr.resources[r] = struct{}{}
|
||||||
|
}
|
||||||
|
cr.registries[newRR.GetName()] = struct{}{}
|
||||||
|
c.clusterRegistry.Store(cls, cr)
|
||||||
|
|
||||||
|
clusterSets[cls] = struct{}{}
|
||||||
|
c.queue.Add(cls)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cls := range c.getClusters(*oldRR.Spec.TargetCluster) {
|
||||||
|
if _, ok := clusterSets[cls]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := c.clusterRegistry.Load(cls)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cr := v.(clusterRegistry)
|
||||||
|
delete(cr.registries, oldRR.GetName())
|
||||||
|
c.clusterRegistry.Store(cls, cr)
|
||||||
|
|
||||||
|
c.queue.Add(cls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteResourceRegistry parse the resourceRegistry object and add deleted Cluster to the queue
|
||||||
|
func (c *Controller) deleteResourceRegistry(obj interface{}) {
|
||||||
|
rr := obj.(*v1alpha1.ResourceRegistry)
|
||||||
|
|
||||||
|
for _, cluster := range c.getClusters(*rr.Spec.TargetCluster) {
|
||||||
|
v, ok := c.clusterRegistry.Load(cluster)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cr := v.(clusterRegistry)
|
||||||
|
delete(cr.registries, rr.GetName())
|
||||||
|
c.clusterRegistry.Store(cluster, cr)
|
||||||
|
|
||||||
|
c.queue.Add(cluster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addCluster adds a cluster object to the queue if needed
|
||||||
|
func (c *Controller) addCluster(obj interface{}) {
|
||||||
|
cluster, ok := obj.(*clusterV1alpha1.Cluster)
|
||||||
|
if !ok {
|
||||||
|
klog.Errorf("cannot convert to *clusterV1alpha1.Cluster: %v", obj)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = c.clusterRegistry.Load(cluster.GetName())
|
||||||
|
if ok {
|
||||||
|
// unregistered cluster, do nothing.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.queue.Add(cluster.GetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateCluster TODO: rebuild informer if Cluster.Spec is changed
|
||||||
|
func (c *Controller) updateCluster(oldObj, newObj interface{}) {}
|
||||||
|
|
||||||
|
// deleteCluster set cluster to not exists
|
||||||
|
func (c *Controller) deleteCluster(obj interface{}) {
|
||||||
|
cluster, ok := obj.(*clusterV1alpha1.Cluster)
|
||||||
|
if !ok {
|
||||||
|
klog.Errorf("cannot convert to *clusterV1alpha1.Cluster: %v", obj)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = c.clusterRegistry.Load(cluster.GetName())
|
||||||
|
if !ok {
|
||||||
|
// unregistered cluster, do nothing.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.queue.Add(cluster.GetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClusterAndResource returns the cluster and resources from the resourceRegistry object
|
||||||
|
func (c *Controller) getClusters(affinity policyv1alpha1.ClusterAffinity) []string {
|
||||||
|
clusters := make([]string, 0)
|
||||||
|
lst, err := c.clusterLister.List(labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("failed to list clusters: %v", err)
|
||||||
|
return clusters
|
||||||
|
}
|
||||||
|
for _, cls := range lst {
|
||||||
|
if util.ClusterMatches(cls, affinity) {
|
||||||
|
clusters = append(clusters, cls.GetName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clusters
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClusterAndResource returns the cluster and resources from the resourceRegistry object
|
||||||
|
func (c *Controller) getResources(selectors []v1alpha1.ResourceSelector) []schema.GroupVersionResource {
|
||||||
|
resources := make([]schema.GroupVersionResource, 0)
|
||||||
|
for _, rs := range selectors {
|
||||||
|
gvr, err := restmapper.GetGroupVersionResource(
|
||||||
|
c.restMapper, schema.FromAPIVersionAndKind(rs.APIVersion, rs.Kind),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("failed to get gvr: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resources = append(resources, gvr)
|
||||||
|
}
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
|
||||||
|
// CachedResourceHandler is the default handler for resource events
|
||||||
|
func CachedResourceHandler() cache.ResourceEventHandler {
|
||||||
|
return &cache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: func(obj interface{}) {
|
||||||
|
us, ok := obj.(*unstructured.Unstructured)
|
||||||
|
if !ok {
|
||||||
|
klog.Errorf("cannot convert to Unstructured: %v", obj)
|
||||||
|
}
|
||||||
|
klog.V(4).Infof("add resource %s, %s, %s, %s", us.GetAPIVersion(), us.GetKind(), us.GetNamespace(), us.GetName())
|
||||||
|
},
|
||||||
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||||
|
us, ok := newObj.(*unstructured.Unstructured)
|
||||||
|
if !ok {
|
||||||
|
klog.Errorf("cannot convert to Unstructured: %v", newObj)
|
||||||
|
}
|
||||||
|
klog.V(4).Infof("update resource %s, %s, %s, %s", us.GetAPIVersion(), us.GetKind(), us.GetNamespace(), us.GetName())
|
||||||
|
},
|
||||||
|
DeleteFunc: func(obj interface{}) {
|
||||||
|
us, ok := obj.(*unstructured.Unstructured)
|
||||||
|
if !ok {
|
||||||
|
klog.Errorf("cannot convert to Unstructured: %v", obj)
|
||||||
|
}
|
||||||
|
klog.V(4).Infof("delete resource %s, %s, %s, %s", us.GetAPIVersion(), us.GetKind(), us.GetNamespace(), us.GetName())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue