update propagation policy api, make namespace and name singular in resourceSelector (#107)
* update propagation policy api, make namespace and name singular in resourceSelector Signed-off-by: Kevin Wang <kevinwzf0126@gmail.com>
This commit is contained in:
parent
abae19c212
commit
b3b08d6d70
|
@ -71,18 +71,12 @@ spec:
|
||||||
description: APIVersion represents the API version of the target
|
description: APIVersion represents the API version of the target
|
||||||
resources.
|
resources.
|
||||||
type: string
|
type: string
|
||||||
excludeNamespaces:
|
|
||||||
description: ExcludeNamespaces is a list of namespaces that
|
|
||||||
the ResourceSelector will ignore. Default is empty, which
|
|
||||||
means don't ignore any namespace.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
kind:
|
kind:
|
||||||
description: Kind represents the Kind of the target resources.
|
description: Kind represents the Kind of the target resources.
|
||||||
type: string
|
type: string
|
||||||
labelSelector:
|
labelSelector:
|
||||||
description: A label query over a set of resources.
|
description: A label query over a set of resources. If name
|
||||||
|
is not empty, labelSelector will be ignored.
|
||||||
properties:
|
properties:
|
||||||
matchExpressions:
|
matchExpressions:
|
||||||
description: matchExpressions is a list of label selector
|
description: matchExpressions is a list of label selector
|
||||||
|
@ -125,21 +119,14 @@ spec:
|
||||||
only "value". The requirements are ANDed.
|
only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
names:
|
name:
|
||||||
description: Names restricts a list of referent names that the
|
description: Name of the target resource. Default is empty,
|
||||||
ResourceSelector will only select. Default is empty, which
|
which means selecting all resources.
|
||||||
means selecting all resources.
|
|
||||||
items:
|
|
||||||
type: string
|
type: string
|
||||||
type: array
|
namespace:
|
||||||
namespaces:
|
description: Namespace of the target resource. Default is empty,
|
||||||
description: Namespaces restricts a list of namespaces that
|
which means inherit from the parent object scope.
|
||||||
the ResourceSelector will only select. If set, only resources
|
|
||||||
in the listed namespaces will be selected. Default is empty,
|
|
||||||
which means selecting all namespaces.
|
|
||||||
items:
|
|
||||||
type: string
|
type: string
|
||||||
type: array
|
|
||||||
required:
|
required:
|
||||||
- apiVersion
|
- apiVersion
|
||||||
- kind
|
- kind
|
||||||
|
|
|
@ -219,7 +219,7 @@ spec:
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
resourceSelector:
|
resourceSelectors:
|
||||||
description: ResourceSelectors used to select resources. nil represents
|
description: ResourceSelectors used to select resources. nil represents
|
||||||
all resources.
|
all resources.
|
||||||
items:
|
items:
|
||||||
|
@ -229,18 +229,12 @@ spec:
|
||||||
description: APIVersion represents the API version of the target
|
description: APIVersion represents the API version of the target
|
||||||
resources.
|
resources.
|
||||||
type: string
|
type: string
|
||||||
excludeNamespaces:
|
|
||||||
description: ExcludeNamespaces is a list of namespaces that
|
|
||||||
the ResourceSelector will ignore. Default is empty, which
|
|
||||||
means don't ignore any namespace.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
kind:
|
kind:
|
||||||
description: Kind represents the Kind of the target resources.
|
description: Kind represents the Kind of the target resources.
|
||||||
type: string
|
type: string
|
||||||
labelSelector:
|
labelSelector:
|
||||||
description: A label query over a set of resources.
|
description: A label query over a set of resources. If name
|
||||||
|
is not empty, labelSelector will be ignored.
|
||||||
properties:
|
properties:
|
||||||
matchExpressions:
|
matchExpressions:
|
||||||
description: matchExpressions is a list of label selector
|
description: matchExpressions is a list of label selector
|
||||||
|
@ -283,21 +277,14 @@ spec:
|
||||||
only "value". The requirements are ANDed.
|
only "value". The requirements are ANDed.
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
names:
|
name:
|
||||||
description: Names restricts a list of referent names that the
|
description: Name of the target resource. Default is empty,
|
||||||
ResourceSelector will only select. Default is empty, which
|
which means selecting all resources.
|
||||||
means selecting all resources.
|
|
||||||
items:
|
|
||||||
type: string
|
type: string
|
||||||
type: array
|
namespace:
|
||||||
namespaces:
|
description: Namespace of the target resource. Default is empty,
|
||||||
description: Namespaces restricts a list of namespaces that
|
which means inherit from the parent object scope.
|
||||||
the ResourceSelector will only select. If set, only resources
|
|
||||||
in the listed namespaces will be selected. Default is empty,
|
|
||||||
which means selecting all namespaces.
|
|
||||||
items:
|
|
||||||
type: string
|
type: string
|
||||||
type: array
|
|
||||||
required:
|
required:
|
||||||
- apiVersion
|
- apiVersion
|
||||||
- kind
|
- kind
|
||||||
|
|
|
@ -4,16 +4,10 @@ metadata:
|
||||||
name: example-policy
|
name: example-policy
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
resourceSelector:
|
resourceSelectors:
|
||||||
- apiVersion: apps/v1
|
- apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
names:
|
name: nginx
|
||||||
- nginx
|
|
||||||
namespaces:
|
|
||||||
- default
|
|
||||||
- exclude
|
|
||||||
excludeNamespaces:
|
|
||||||
- exclude
|
|
||||||
labelSelector:
|
labelSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
a: b
|
a: b
|
||||||
|
|
|
@ -2,25 +2,19 @@ apiVersion: propagationstrategy.karmada.io/v1alpha1
|
||||||
kind: PropagationPolicy
|
kind: PropagationPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: example-policy
|
name: example-policy
|
||||||
namespace: default
|
|
||||||
spec:
|
spec:
|
||||||
resourceSelector:
|
resourceSelector:
|
||||||
- apiVersion: apps/v1
|
- apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
names:
|
name: deployment-1
|
||||||
- nginx
|
labelSelector: # standard labelSelector
|
||||||
namespaces:
|
propagateDependensies: false
|
||||||
- default
|
|
||||||
excludeNamespaces:
|
|
||||||
- exclude
|
|
||||||
association: false
|
|
||||||
placement:
|
placement:
|
||||||
clusterAffinity:
|
clusterAffinity:
|
||||||
clusterNames:
|
clusterNames:
|
||||||
- cluster1
|
- cluster1
|
||||||
- cluster3
|
- cluster3
|
||||||
exclude:
|
clusterTolerations: # like pod tolerations
|
||||||
- cluster2
|
|
||||||
spreadConstraints:
|
spreadConstraints:
|
||||||
- spreadByLabel: failuredomain.kubernetes.io/zone
|
- spreadByLabel: failuredomain.kubernetes.io/zone
|
||||||
maximum: 3
|
maximum: 3
|
||||||
|
|
|
@ -22,7 +22,7 @@ type PropagationPolicy struct {
|
||||||
type PropagationSpec struct {
|
type PropagationSpec struct {
|
||||||
// ResourceSelectors used to select resources.
|
// ResourceSelectors used to select resources.
|
||||||
// nil represents all resources.
|
// nil represents all resources.
|
||||||
ResourceSelectors []ResourceSelector `json:"resourceSelector,omitempty"`
|
ResourceSelectors []ResourceSelector `json:"resourceSelectors,omitempty"`
|
||||||
|
|
||||||
// Association tells if relevant resources should be selected automatically.
|
// Association tells if relevant resources should be selected automatically.
|
||||||
// e.g. a ConfigMap referred by a Deployment.
|
// e.g. a ConfigMap referred by a Deployment.
|
||||||
|
@ -47,28 +47,20 @@ type ResourceSelector struct {
|
||||||
// Kind represents the Kind of the target resources.
|
// Kind represents the Kind of the target resources.
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
|
|
||||||
// Names restricts a list of referent names that the ResourceSelector will only select.
|
// Namespace of the target resource.
|
||||||
|
// Default is empty, which means inherit from the parent object scope.
|
||||||
|
// +optional
|
||||||
|
Namespace string `json:"namespace,omitempty"`
|
||||||
|
|
||||||
|
// Name of the target resource.
|
||||||
// Default is empty, which means selecting all resources.
|
// Default is empty, which means selecting all resources.
|
||||||
// +optional
|
// +optional
|
||||||
Names []string `json:"names,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
|
||||||
// Namespaces restricts a list of namespaces that the ResourceSelector will only select.
|
|
||||||
// If set, only resources in the listed namespaces will be selected.
|
|
||||||
// Default is empty, which means selecting all namespaces.
|
|
||||||
// +optional
|
|
||||||
Namespaces []string `json:"namespaces,omitempty"`
|
|
||||||
|
|
||||||
// ExcludeNamespaces is a list of namespaces that the ResourceSelector will ignore.
|
|
||||||
// Default is empty, which means don't ignore any namespace.
|
|
||||||
// +optional
|
|
||||||
ExcludeNamespaces []string `json:"excludeNamespaces,omitempty"`
|
|
||||||
|
|
||||||
// A label query over a set of resources.
|
// A label query over a set of resources.
|
||||||
|
// If name is not empty, labelSelector will be ignored.
|
||||||
// +optional
|
// +optional
|
||||||
LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
|
LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
|
||||||
|
|
||||||
// FieldSelector is a field filter.
|
|
||||||
//FieldSelector *FieldSelector `json:"fieldSelector,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldSelector is a field filter.
|
// FieldSelector is a field filter.
|
||||||
|
|
|
@ -635,21 +635,6 @@ func (in *ResourceIdentifier) DeepCopy() *ResourceIdentifier {
|
||||||
// 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 *ResourceSelector) DeepCopyInto(out *ResourceSelector) {
|
func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Names != nil {
|
|
||||||
in, out := &in.Names, &out.Names
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.Namespaces != nil {
|
|
||||||
in, out := &in.Namespaces, &out.Namespaces
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.ExcludeNamespaces != nil {
|
|
||||||
in, out := &in.ExcludeNamespaces, &out.ExcludeNamespaces
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.LabelSelector != nil {
|
if in.LabelSelector != nil {
|
||||||
in, out := &in.LabelSelector, &out.LabelSelector
|
in, out := &in.LabelSelector, &out.LabelSelector
|
||||||
*out = new(v1.LabelSelector)
|
*out = new(v1.LabelSelector)
|
||||||
|
|
|
@ -71,7 +71,7 @@ func (c *PropagationPolicyController) Reconcile(req controllerruntime.Request) (
|
||||||
|
|
||||||
// syncPolicy will fetch matched resource by policy, then transform them to propagationBindings.
|
// syncPolicy will fetch matched resource by policy, then transform them to propagationBindings.
|
||||||
func (c *PropagationPolicyController) syncPolicy(policy *v1alpha1.PropagationPolicy) (controllerruntime.Result, error) {
|
func (c *PropagationPolicyController) syncPolicy(policy *v1alpha1.PropagationPolicy) (controllerruntime.Result, error) {
|
||||||
workloads, err := c.fetchWorkloads(policy.Spec.ResourceSelectors)
|
workloads, err := c.fetchWorkloads(policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return controllerruntime.Result{Requeue: true}, err
|
return controllerruntime.Result{Requeue: true}, err
|
||||||
}
|
}
|
||||||
|
@ -93,29 +93,19 @@ func (c *PropagationPolicyController) syncPolicy(policy *v1alpha1.PropagationPol
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchWorkloads fetches all matched resources via resource selectors.
|
// fetchWorkloads fetches all matched resources via resource selectors.
|
||||||
// TODO(RainbowMango): the implementation is old and too complicated, need refactor later.
|
func (c *PropagationPolicyController) fetchWorkloads(policy *v1alpha1.PropagationPolicy) ([]*unstructured.Unstructured, error) {
|
||||||
func (c *PropagationPolicyController) fetchWorkloads(resourceSelectors []v1alpha1.ResourceSelector) ([]*unstructured.Unstructured, error) {
|
|
||||||
var workloads []*unstructured.Unstructured
|
var workloads []*unstructured.Unstructured
|
||||||
// todo: if resources repetitive, deduplication.
|
|
||||||
// todo: if namespaces, names, labelSelector is nil, need to do something
|
for _, resourceSelector := range policy.Spec.ResourceSelectors {
|
||||||
for _, resourceSelector := range resourceSelectors {
|
if resourceSelector.Namespace == "" {
|
||||||
names := util.GetUniqueElements(resourceSelector.Names)
|
resourceSelector.Namespace = policy.Namespace
|
||||||
namespaces := util.GetDifferenceSet(resourceSelector.Namespaces, resourceSelector.ExcludeNamespaces)
|
}
|
||||||
for _, namespace := range namespaces {
|
tmpWorkloads, err := c.fetchWorkloadsByResourceSelector(resourceSelector)
|
||||||
if resourceSelector.LabelSelector == nil {
|
|
||||||
err := c.fetchWorkloadsWithOutLabelSelector(resourceSelector, namespace, names, &workloads)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to fetch workloads by names in namespace %s. Error: %v.", namespace, err)
|
klog.Errorf("Failed to fetch workloads with labelSelector in namespace %s. Error: %v.", policy.Namespace, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
workloads = append(workloads, tmpWorkloads...)
|
||||||
err := c.fetchWorkloadsWithLabelSelector(resourceSelector, namespace, names, &workloads)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("Failed to fetch workloads with labelSelector in namespace %s. Error: %v.", namespace, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return workloads, nil
|
return workloads, nil
|
||||||
}
|
}
|
||||||
|
@ -237,65 +227,64 @@ func (c *PropagationPolicyController) ignoreIrrelevantWorkload(policy *v1alpha1.
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchWorkloadsWithLabelSelector query workloads by labelSelector and names
|
// fetchWorkloadsByResourceSelector query workloads by labelSelector and names
|
||||||
func (c *PropagationPolicyController) fetchWorkloadsWithLabelSelector(resourceSelector v1alpha1.ResourceSelector,
|
func (c *PropagationPolicyController) fetchWorkloadsByResourceSelector(resourceSelector v1alpha1.ResourceSelector) ([]*unstructured.Unstructured, error) {
|
||||||
namespace string, names []string, workloads *[]*unstructured.Unstructured) error {
|
|
||||||
dynamicResource, err := restmapper.GetGroupVersionResource(c.RESTMapper,
|
dynamicResource, err := restmapper.GetGroupVersionResource(c.RESTMapper,
|
||||||
schema.FromAPIVersionAndKind(resourceSelector.APIVersion, resourceSelector.Kind))
|
schema.FromAPIVersionAndKind(resourceSelector.APIVersion, resourceSelector.Kind))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to get GVR from GVK %s %s. Error: %v", resourceSelector.APIVersion, resourceSelector.Kind, err)
|
klog.Errorf("Failed to get GVR from GVK %s %s. Error: %v", resourceSelector.APIVersion, resourceSelector.Kind, err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
unstructuredWorkLoadList, err := c.DynamicClient.Resource(dynamicResource).Namespace(namespace).List(context.TODO(),
|
|
||||||
metav1.ListOptions{LabelSelector: labels.Set(resourceSelector.LabelSelector.MatchLabels).String()})
|
if resourceSelector.Name != "" {
|
||||||
|
workload, err := c.fetchWorkload(resourceSelector)
|
||||||
|
if err != nil || workload == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*unstructured.Unstructured{workload}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
unstructuredWorkLoadList, err := c.DynamicClient.Resource(dynamicResource).Namespace(resourceSelector.Namespace).List(context.TODO(),
|
||||||
|
metav1.ListOptions{LabelSelector: resourceSelector.LabelSelector.String()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resourceSelector.Names == nil {
|
|
||||||
|
var workloads []*unstructured.Unstructured
|
||||||
for _, unstructuredWorkLoad := range unstructuredWorkLoadList.Items {
|
for _, unstructuredWorkLoad := range unstructuredWorkLoadList.Items {
|
||||||
if unstructuredWorkLoad.GetDeletionTimestamp() == nil {
|
if unstructuredWorkLoad.GetDeletionTimestamp() == nil {
|
||||||
*workloads = append(*workloads, &unstructuredWorkLoad)
|
workloads = append(workloads, &unstructuredWorkLoad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for _, unstructuredWorkLoad := range unstructuredWorkLoadList.Items {
|
return workloads, nil
|
||||||
for _, name := range names {
|
|
||||||
if unstructuredWorkLoad.GetName() == name && unstructuredWorkLoad.GetDeletionTimestamp() == nil {
|
|
||||||
*workloads = append(*workloads, &unstructuredWorkLoad)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchWorkloadsWithOutLabelSelector query workloads by names
|
func (c *PropagationPolicyController) fetchWorkload(resourceSelector v1alpha1.ResourceSelector) (*unstructured.Unstructured, error) {
|
||||||
func (c *PropagationPolicyController) fetchWorkloadsWithOutLabelSelector(resourceSelector v1alpha1.ResourceSelector, namespace string, names []string, workloads *[]*unstructured.Unstructured) error {
|
|
||||||
for _, name := range names {
|
|
||||||
dynamicResource, err := restmapper.GetGroupVersionResource(c.RESTMapper,
|
dynamicResource, err := restmapper.GetGroupVersionResource(c.RESTMapper,
|
||||||
schema.FromAPIVersionAndKind(resourceSelector.APIVersion, resourceSelector.Kind))
|
schema.FromAPIVersionAndKind(resourceSelector.APIVersion, resourceSelector.Kind))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Failed to get GVR from GVK %s %s. Error: %v", resourceSelector.APIVersion,
|
klog.Errorf("Failed to get GVR from GVK %s %s. Error: %v", resourceSelector.APIVersion,
|
||||||
resourceSelector.Kind, err)
|
resourceSelector.Kind, err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
workload, err := c.DynamicClient.Resource(dynamicResource).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
workload, err := c.DynamicClient.Resource(dynamicResource).Namespace(resourceSelector.Namespace).Get(context.TODO(), resourceSelector.Name, metav1.GetOptions{})
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
klog.Warningf("Workload does not exist, kind: %s, namespace: %s, name: %s",
|
||||||
|
resourceSelector.Kind, resourceSelector.Namespace, resourceSelector.Name)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
klog.Errorf("Failed to get workload, kind: %s, namespace: %s, name: %s. Error: %v",
|
klog.Errorf("Failed to get workload, kind: %s, namespace: %s, name: %s. Error: %v",
|
||||||
resourceSelector.Kind, namespace, name, err)
|
resourceSelector.Kind, resourceSelector.Namespace, resourceSelector.Name, err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err != nil && errors.IsNotFound(err) {
|
if workload.GetDeletionTimestamp() != nil {
|
||||||
klog.Warningf("Workload is not exist, kind: %s, namespace: %s, name: %s",
|
return nil, nil
|
||||||
resourceSelector.Kind, namespace, name)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if workload.GetDeletionTimestamp() == nil {
|
return workload, nil
|
||||||
*workloads = append(*workloads, workload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTargetClusters get targetClusters by placement.
|
// getTargetClusters get targetClusters by placement.
|
||||||
|
|
|
@ -19,8 +19,7 @@ func NewPolicyWithSingleDeployment(namespace string, name string, deployment *ap
|
||||||
{
|
{
|
||||||
APIVersion: deployment.APIVersion,
|
APIVersion: deployment.APIVersion,
|
||||||
Kind: deployment.Kind,
|
Kind: deployment.Kind,
|
||||||
Names: []string{deployment.Name},
|
Name: deployment.Name,
|
||||||
Namespaces: []string{deployment.Namespace},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Placement: propagationapi.Placement{
|
Placement: propagationapi.Placement{
|
||||||
|
|
Loading…
Reference in New Issue