add policy resource label selector (#36)
This commit is contained in:
parent
395b4da4f8
commit
be32c34b69
|
@ -0,0 +1,31 @@
|
||||||
|
apiVersion: propagationstrategy.karmada.io/v1alpha1
|
||||||
|
kind: PropagationPolicy
|
||||||
|
metadata:
|
||||||
|
name: example-policy
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
resourceSelector:
|
||||||
|
- apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
names:
|
||||||
|
- nginx
|
||||||
|
namespaces:
|
||||||
|
- default
|
||||||
|
- exclude
|
||||||
|
excludeNamespaces:
|
||||||
|
- exclude
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
a: b
|
||||||
|
association: false
|
||||||
|
placement:
|
||||||
|
clusterAffinity:
|
||||||
|
clusterNames:
|
||||||
|
- cluster1
|
||||||
|
- cluster3
|
||||||
|
exclude:
|
||||||
|
- cluster1
|
||||||
|
spreadConstraints:
|
||||||
|
- maximumClusters: 3
|
||||||
|
minimumClusters: 3
|
||||||
|
schedulerName: default
|
|
@ -220,29 +220,69 @@ func (c *Controller) processNextWorkItem() bool {
|
||||||
func (c *Controller) fetchWorkloads(resourceSelectors []v1alpha1.ResourceSelector) ([]*unstructured.Unstructured, error) {
|
func (c *Controller) fetchWorkloads(resourceSelectors []v1alpha1.ResourceSelector) ([]*unstructured.Unstructured, error) {
|
||||||
var workloads []*unstructured.Unstructured
|
var workloads []*unstructured.Unstructured
|
||||||
// todo: if resources repetitive, deduplication.
|
// todo: if resources repetitive, deduplication.
|
||||||
|
// todo: if namespaces, names, labelSelector is nil, need to do something
|
||||||
for _, resourceSelector := range resourceSelectors {
|
for _, resourceSelector := range resourceSelectors {
|
||||||
matchNamespaces := util.GetMatchItems(resourceSelector.Namespaces, resourceSelector.ExcludeNamespaces)
|
matchNamespaces := util.GetMatchItems(resourceSelector.Namespaces, resourceSelector.ExcludeNamespaces)
|
||||||
klog.V(2).Infof("matchNamespaces: %v", matchNamespaces)
|
deduplicationNames := util.GetDeduplicationArray(resourceSelector.Names)
|
||||||
for _, namespace := range matchNamespaces {
|
for _, namespace := range matchNamespaces {
|
||||||
for _, name := range resourceSelector.Names {
|
if resourceSelector.LabelSelector == nil {
|
||||||
|
err := c.fetchWorkloadsWithOutLabelSelector(resourceSelector, namespace, deduplicationNames, &workloads)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("failed to fetch workloads by names in namespace %s. error: %v", namespace, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := c.fetchWorkloadsWithLabelSelector(resourceSelector, namespace, deduplicationNames, &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
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchWorkloadsWithOutLabelSelector query workloads by names
|
||||||
|
func (c *Controller) fetchWorkloadsWithOutLabelSelector(resourceSelector v1alpha1.ResourceSelector, namespace string, names []string, workloads *[]*unstructured.Unstructured) error {
|
||||||
|
for _, name := range names {
|
||||||
workload, err := util.GetResourceStructure(c.dynamicClientSet, resourceSelector.APIVersion,
|
workload, err := util.GetResourceStructure(c.dynamicClientSet, resourceSelector.APIVersion,
|
||||||
resourceSelector.Kind, namespace, name)
|
resourceSelector.Kind, namespace, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("failed to get resource. error: %v", err)
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
workloads = append(workloads, workload)
|
*workloads = append(*workloads, workload)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchWorkloadsWithLabelSelector query workloads by labelSelector and names
|
||||||
|
func (c *Controller) fetchWorkloadsWithLabelSelector(resourceSelector v1alpha1.ResourceSelector, namespace string, names []string, workloads *[]*unstructured.Unstructured) error {
|
||||||
|
unstructuredWorkLoadList, err := util.GetResourcesStructureByFilter(c.dynamicClientSet, resourceSelector.APIVersion,
|
||||||
|
resourceSelector.Kind, namespace, resourceSelector.LabelSelector)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resourceSelector.Names == nil {
|
||||||
|
for _, unstructuredWorkLoad := range unstructuredWorkLoadList.Items {
|
||||||
|
*workloads = append(*workloads, &unstructuredWorkLoad)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, unstructuredWorkLoad := range unstructuredWorkLoadList.Items {
|
||||||
|
for _, name := range names {
|
||||||
|
if unstructuredWorkLoad.GetName() == name {
|
||||||
|
*workloads = append(*workloads, &unstructuredWorkLoad)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// todo: resource labelSelector
|
}
|
||||||
return workloads, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTargetClusters get targetClusters by placement
|
// getTargetClusters get targetClusters by placement
|
||||||
func (c *Controller) getTargetClusters(placement v1alpha1.Placement) []v1alpha1.TargetCluster {
|
func (c *Controller) getTargetClusters(placement v1alpha1.Placement) []v1alpha1.TargetCluster {
|
||||||
matchClusterNames := util.GetMatchItems(placement.ClusterAffinity.ClusterNames, placement.ClusterAffinity.ExcludeClusters)
|
matchClusterNames := util.GetMatchItems(placement.ClusterAffinity.ClusterNames, placement.ClusterAffinity.ExcludeClusters)
|
||||||
klog.V(2).Infof("matchClusterNames: %v", matchClusterNames)
|
|
||||||
|
|
||||||
// todo: cluster labelSelector, fieldSelector, clusterTolerations
|
// todo: cluster labelSelector, fieldSelector, clusterTolerations
|
||||||
// todo: calc spread contraints. such as maximumClusters, minimumClusters
|
// todo: calc spread contraints. such as maximumClusters, minimumClusters
|
||||||
|
@ -268,7 +308,6 @@ func (c *Controller) transformPolicyToBinding(propagationPolicy *v1alpha1.Propag
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
|
@ -31,24 +31,51 @@ var ResourceKindMap = map[string]string{
|
||||||
"Ingress": "ingresses",
|
"Ingress": "ingresses",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResourceStructure get resource yaml from kubernetes
|
//
|
||||||
func GetResourceStructure(client dynamic.Interface, apiVersion, kind, namespace, name string) (*unstructured.Unstructured, error) {
|
func generateGroupVersionResource(apiVersion, kind string) (schema.GroupVersionResource, error) {
|
||||||
groupVersion, err := schema.ParseGroupVersion(apiVersion)
|
groupVersion, err := schema.ParseGroupVersion(apiVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't get parse groupVersion[namespace: %s name: %s kind: %s]. error: %v", namespace,
|
return schema.GroupVersionResource{}, err
|
||||||
name, ResourceKindMap[kind], err)
|
|
||||||
}
|
}
|
||||||
dynamicResource := schema.GroupVersionResource{Group: groupVersion.Group, Version: groupVersion.Version, Resource: ResourceKindMap[kind]}
|
dynamicResource := schema.GroupVersionResource{Group: groupVersion.Group, Version: groupVersion.Version, Resource: ResourceKindMap[kind]}
|
||||||
|
return dynamicResource, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceStructure get resource yaml from kubernetes
|
||||||
|
func GetResourceStructure(client dynamic.Interface, apiVersion, kind, namespace, name string) (*unstructured.Unstructured, error) {
|
||||||
|
dynamicResource, err := generateGroupVersionResource(apiVersion, kind)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
result, err := client.Resource(dynamicResource).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
result, err := client.Resource(dynamicResource).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't get resource[namespace: %s name: %s kind: %s]. error: %v", namespace,
|
return nil, err
|
||||||
name, ResourceKindMap[kind], err)
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourcesStructureByFilter get resources yaml from kubernetes by filter
|
||||||
|
func GetResourcesStructureByFilter(client dynamic.Interface, apiVersion, kind, namespace string, labelSelector *metav1.LabelSelector) (*unstructured.UnstructuredList, error) {
|
||||||
|
dynamicResource, err := generateGroupVersionResource(apiVersion, kind)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, err := client.Resource(dynamicResource).Namespace(namespace).List(context.TODO(),
|
||||||
|
metav1.ListOptions{LabelSelector: labels.Set(labelSelector.MatchLabels).String()})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMatchItems get match item by compare include items and exclude items
|
// GetMatchItems get match item by compare include items and exclude items
|
||||||
func GetMatchItems(includeItems, excludeItems []string) []string {
|
func GetMatchItems(includeItems, excludeItems []string) []string {
|
||||||
|
if includeItems == nil {
|
||||||
|
includeItems = []string{}
|
||||||
|
}
|
||||||
|
if excludeItems == nil {
|
||||||
|
excludeItems = []string{}
|
||||||
|
}
|
||||||
includeSet := sets.NewString()
|
includeSet := sets.NewString()
|
||||||
excludeSet := sets.NewString()
|
excludeSet := sets.NewString()
|
||||||
for _, targetItem := range excludeItems {
|
for _, targetItem := range excludeItems {
|
||||||
|
@ -62,3 +89,15 @@ func GetMatchItems(includeItems, excludeItems []string) []string {
|
||||||
|
|
||||||
return matchItems.List()
|
return matchItems.List()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDeduplicationArray get deduplication array
|
||||||
|
func GetDeduplicationArray(list []string) []string {
|
||||||
|
if list == nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
result := sets.String{}
|
||||||
|
for _, item := range list {
|
||||||
|
result.Insert(item)
|
||||||
|
}
|
||||||
|
return result.List()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue