propagate dependencies support propagate sa
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
This commit is contained in:
parent
62a4b4391f
commit
92fff3163d
|
@ -49,6 +49,7 @@ const (
|
||||||
var supportedTypes = []schema.GroupVersionResource{
|
var supportedTypes = []schema.GroupVersionResource{
|
||||||
corev1.SchemeGroupVersion.WithResource("configmaps"),
|
corev1.SchemeGroupVersion.WithResource("configmaps"),
|
||||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||||
|
corev1.SchemeGroupVersion.WithResource("serviceaccounts"),
|
||||||
corev1.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
|
corev1.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,5 +277,53 @@ var _ = ginkgo.Describe("[DependenciesDistributor] automatically propagate relev
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ginkgo.When("serviceAccount propagate automatically", func() {
|
||||||
|
var saName string
|
||||||
|
var sa *corev1.ServiceAccount
|
||||||
|
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
saName = saNamePrefix + rand.String(RandomStrLength)
|
||||||
|
sa = testhelper.NewServiceaccount(testNamespace, saName)
|
||||||
|
|
||||||
|
deployment = testhelper.NewDeploymentWithServiceAccount(testNamespace, deploymentName, saName)
|
||||||
|
|
||||||
|
policy = testhelper.NewPropagationPolicy(testNamespace, policyName, []policyv1alpha1.ResourceSelector{
|
||||||
|
{
|
||||||
|
APIVersion: deployment.APIVersion,
|
||||||
|
Kind: deployment.Kind,
|
||||||
|
Name: deployment.Name,
|
||||||
|
},
|
||||||
|
}, policyv1alpha1.Placement{
|
||||||
|
ClusterAffinity: &policyv1alpha1.ClusterAffinity{
|
||||||
|
ClusterNames: initClusterNames,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
policy.Spec.PropagateDeps = true
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("serviceAccount automatically propagation testing", func() {
|
||||||
|
framework.CreateServiceAccount(kubeClient, sa)
|
||||||
|
ginkgo.DeferCleanup(func() {
|
||||||
|
framework.RemoveServiceAccount(kubeClient, sa.GetNamespace(), sa.GetName())
|
||||||
|
})
|
||||||
|
ginkgo.By("check if the serviceAccount is propagated automatically", func() {
|
||||||
|
framework.WaitDeploymentPresentOnClustersFitWith(initClusterNames, deployment.Namespace, deployment.Name,
|
||||||
|
func(deployment *appsv1.Deployment) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
framework.WaitServiceAccountPresentOnClustersFitWith(initClusterNames, sa.GetNamespace(), sa.GetName(),
|
||||||
|
func(sa *corev1.ServiceAccount) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("make the sa is not referenced by the deployment ", func() {
|
||||||
|
framework.UpdateDeploymentServiceAccountName(kubeClient, deployment, "default")
|
||||||
|
framework.WaitServiceAccountDisappearOnClusters(initClusterNames, sa.GetNamespace(), sa.GetName())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -122,6 +122,17 @@ func UpdateDeploymentVolumes(client kubernetes.Interface, deployment *appsv1.Dep
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateDeploymentServiceAccountName update Deployment's serviceAccountName.
|
||||||
|
func UpdateDeploymentServiceAccountName(client kubernetes.Interface, deployment *appsv1.Deployment, serviceAccountName string) {
|
||||||
|
ginkgo.By(fmt.Sprintf("Updating Deployment(%s/%s)'s serviceAccountName", deployment.Namespace, deployment.Name), func() {
|
||||||
|
deployment.Spec.Template.Spec.ServiceAccountName = serviceAccountName
|
||||||
|
gomega.Eventually(func() error {
|
||||||
|
_, err := client.AppsV1().Deployments(deployment.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
|
||||||
|
return err
|
||||||
|
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ExtractTargetClustersFrom extract the target cluster names from deployment's related resourceBinding Information.
|
// ExtractTargetClustersFrom extract the target cluster names from deployment's related resourceBinding Information.
|
||||||
func ExtractTargetClustersFrom(c client.Client, deployment *appsv1.Deployment) []string {
|
func ExtractTargetClustersFrom(c client.Client, deployment *appsv1.Deployment) []string {
|
||||||
bindingName := names.GenerateBindingName(deployment.Kind, deployment.Name)
|
bindingName := names.GenerateBindingName(deployment.Kind, deployment.Name)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateClusterRole create clusterRole.
|
// CreateClusterRole create clusterRole.
|
||||||
|
@ -69,3 +70,56 @@ func RemoveServiceAccount(client kubernetes.Interface, namespace, name string) {
|
||||||
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitServiceAccountPresentOnClusterFitWith wait sa present on member clusters sync with fit func.
|
||||||
|
func WaitServiceAccountPresentOnClusterFitWith(cluster, namespace, name string, fit func(sa *corev1.ServiceAccount) bool) {
|
||||||
|
clusterClient := GetClusterClient(cluster)
|
||||||
|
gomega.Expect(clusterClient).ShouldNot(gomega.BeNil())
|
||||||
|
|
||||||
|
klog.Infof("Waiting for serviceAccount(%s/%s) synced on cluster(%s)", namespace, name, cluster)
|
||||||
|
gomega.Eventually(func() bool {
|
||||||
|
sa, err := clusterClient.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fit(sa)
|
||||||
|
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitServiceAccountPresentOnClustersFitWith wait sa present on cluster sync with fit func.
|
||||||
|
func WaitServiceAccountPresentOnClustersFitWith(clusters []string, namespace, name string, fit func(sa *corev1.ServiceAccount) bool) {
|
||||||
|
ginkgo.By(fmt.Sprintf("Waiting for pod(%s/%s) synced on member clusters", namespace, name), func() {
|
||||||
|
for _, clusterName := range clusters {
|
||||||
|
WaitServiceAccountPresentOnClusterFitWith(clusterName, namespace, name, fit)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitServiceAccountDisappearOnCluster wait sa disappear on cluster until timeout.
|
||||||
|
func WaitServiceAccountDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
clusterClient := GetClusterClient(cluster)
|
||||||
|
gomega.Expect(clusterClient).ShouldNot(gomega.BeNil())
|
||||||
|
|
||||||
|
klog.Infof("Waiting for sa(%s/%s) disappear on cluster(%s)", namespace, name, cluster)
|
||||||
|
gomega.Eventually(func() bool {
|
||||||
|
_, err := clusterClient.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if apierrors.IsNotFound(err) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
klog.Errorf("Failed to get sa(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
|
return false
|
||||||
|
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitServiceAccountDisappearOnClusters wait sa disappear on member clusters until timeout.
|
||||||
|
func WaitServiceAccountDisappearOnClusters(clusters []string, namespace, name string) {
|
||||||
|
ginkgo.By(fmt.Sprintf("Check if sa(%s/%s) diappeare on member clusters", namespace, name), func() {
|
||||||
|
for _, clusterName := range clusters {
|
||||||
|
WaitServiceAccountDisappearOnCluster(clusterName, namespace, name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ const (
|
||||||
configMapNamePrefix = "configmap-"
|
configMapNamePrefix = "configmap-"
|
||||||
secretNamePrefix = "secret-"
|
secretNamePrefix = "secret-"
|
||||||
pvcNamePrefix = "pvc-"
|
pvcNamePrefix = "pvc-"
|
||||||
|
saNamePrefix = "sa-"
|
||||||
ingressNamePrefix = "ingress-"
|
ingressNamePrefix = "ingress-"
|
||||||
daemonSetNamePrefix = "daemonset-"
|
daemonSetNamePrefix = "daemonset-"
|
||||||
statefulSetNamePrefix = "statefulset-"
|
statefulSetNamePrefix = "statefulset-"
|
||||||
|
|
|
@ -559,6 +559,41 @@ func NewDeploymentWithVolumes(namespace, deploymentName string, volumes []corev1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDeploymentWithServiceAccount will build a deployment object that with serviceAccount.
|
||||||
|
func NewDeploymentWithServiceAccount(namespace, deploymentName string, serviceAccountName string) *appsv1.Deployment {
|
||||||
|
podLabels := map[string]string{"app": "nginx"}
|
||||||
|
|
||||||
|
return &appsv1.Deployment{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "apps/v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: deploymentName,
|
||||||
|
},
|
||||||
|
Spec: appsv1.DeploymentSpec{
|
||||||
|
|
||||||
|
Replicas: pointer.Int32Ptr(3),
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: podLabels,
|
||||||
|
},
|
||||||
|
Template: corev1.PodTemplateSpec{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: podLabels,
|
||||||
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{{
|
||||||
|
Name: "nginx",
|
||||||
|
Image: "nginx:1.19.0",
|
||||||
|
}},
|
||||||
|
ServiceAccountName: serviceAccountName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewSecret will build a secret object.
|
// NewSecret will build a secret object.
|
||||||
func NewSecret(namespace string, name string, data map[string][]byte) *corev1.Secret {
|
func NewSecret(namespace string, name string, data map[string][]byte) *corev1.Secret {
|
||||||
return &corev1.Secret{
|
return &corev1.Secret{
|
||||||
|
|
Loading…
Reference in New Issue