package edgeinjector import ( "context" "fmt" "reflect" "testing" "time" dsapi "edge-infra.dev/pkg/edge/datasync/apis/v1alpha1" "edge-infra.dev/pkg/edge/datasync/couchdb" "edge-infra.dev/pkg/edge/k8objectsutils/ownerref" "edge-infra.dev/pkg/k8s/runtime/controller" "edge-infra.dev/pkg/lib/fog" v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1" nodemeta "edge-infra.dev/pkg/sds/ien/node" "edge-infra.dev/test/framework/k8s/envtest" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ) var ( namespace = "default" timeout = 5 * time.Second interval = time.Second log = fog.New() testEnv *envtest.Environment cfg = &Config{ EnableWebhook: false, ReconcileConcurrency: 1, PollingInterval: timeout, RequeueTime: interval, } mgr ctrl.Manager ) func TestMain(m *testing.M) { testEnv = envtest.Setup() defer func() { err := testEnv.Stop() if err != nil { panic(fmt.Errorf("failed to stop test environment, %w", err)) } }() var err error mgr, err = create(log, cfg, controller.WithCfg(testEnv.Config)) if err != nil { panic(fmt.Errorf("failed to create manager, %w", err)) } go func() { err = mgr.Start(ctrl.SetupSignalHandler()) if err != nil { panic(fmt.Errorf("failed to start manager, %w", err)) } }() m.Run() } func TestCouchDBUserSecret(t *testing.T) { ctx := context.Background() uid := uuid.New().String() cl := mgr.GetClient() nodeName := fmt.Sprintf("node-%s", uid) node := &corev1.Node{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Node", }, ObjectMeta: metav1.ObjectMeta{ UID: types.UID(uid), Name: nodeName, Labels: map[string]string{ nodemeta.RoleLabel: string(v1ien.ControlPlane), nodemeta.ClassLabel: string(v1ien.Server), }, }, } require.NoError(t, cl.Create(ctx, node), "fail to create node") deployment := basicDeployment(namespace, fmt.Sprintf("deploy-%s", uid)) require.NoError(t, cl.Create(ctx, deployment), "fail to create deployment") pod := basicPod(namespace, deployment.Name, nodeName, ownerReference(deployment)) require.NoError(t, cl.Create(ctx, pod), "fail to create pod") require.Eventually(t, func() bool { err := cl.Get(ctx, client.ObjectKeyFromObject(pod), pod) return err == nil }, timeout, interval, "pod does not exist") if len(pod.Labels) == 0 { pod.Labels = map[string]string{} } secretName := fmt.Sprintf("%s-%s", CouchDBSecret, uid) pod.Labels[SecretLabel(CouchDBSecret)] = secretName require.NoError(t, cl.Update(ctx, pod), "fail to update pod") require.Eventually(t, func() bool { // Note: secret label triggers reconcile loop err := cl.Get(ctx, client.ObjectKeyFromObject(pod), pod) return err == nil && pod.Labels[SecretLabel(CouchDBSecret)] == secretName }, timeout, interval, "pod does not contain secret label") ref := metav1.OwnerReference{Name: fmt.Sprintf("deploy-%s", uid)} username := ownerref.ResourceName(fmt.Sprintf("%s-%s", couchdb.CouchDBName, node.UID), ref, namespace, nodeName, false) user := &dsapi.CouchDBUser{ TypeMeta: metav1.TypeMeta{ APIVersion: dsapi.GroupVersion.String(), Kind: "CouchDBUser", }, ObjectMeta: metav1.ObjectMeta{ Name: username, Namespace: namespace, }, } // pod reconciler create CouchDBUser require.Eventually(t, func() bool { err := cl.Get(ctx, client.ObjectKeyFromObject(user), user) return err == nil }, timeout, interval, "CouchDBUser does not exist: %s", user.Name) assert.Equal(t, user.Spec.Type, dsapi.UserCredentials) assert.Equal(t, user.Spec.User.Name, "") assert.Equal(t, user.Spec.User.Secret.Namespace, namespace) assert.Equal(t, user.Spec.User.Secret.Name, secretName) assert.Equal(t, ref.Name, user.OwnerReferences[0].Name) } func TestNodeSecret(t *testing.T) { ctx := context.Background() uid := uuid.New().String() cl := mgr.GetClient() nodeName := fmt.Sprintf("node-%s", uid) node := &corev1.Node{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Node", }, ObjectMeta: metav1.ObjectMeta{ Name: nodeName, Labels: map[string]string{ nodemeta.HostnameLabel: "localhost", nodemeta.LaneLabel: "1", nodemeta.ClassLabel: "server", nodemeta.RoleLabel: "controlplane", }, }, } require.NoError(t, cl.Create(ctx, node), "fail to create node") deployment := basicDeployment(namespace, fmt.Sprintf("deploy-%s", uid)) require.NoError(t, cl.Create(ctx, deployment), "fail to create deployment") pod := basicPod(namespace, deployment.Name, nodeName, ownerReference(deployment)) require.NoError(t, cl.Create(ctx, pod), "fail to create pod") require.Eventually(t, func() bool { err := cl.Get(ctx, client.ObjectKeyFromObject(pod), pod) return err == nil }, timeout, interval, "pod does not exist") if len(pod.Labels) == 0 { pod.Labels = map[string]string{} } secretName := fmt.Sprintf("%s-%s", NodeSecret, uid) pod.Labels[SecretLabel(NodeSecret)] = secretName require.NoError(t, cl.Update(ctx, pod), "fail to update pod") ref := metav1.OwnerReference{Name: deployment.Name} secret := &corev1.Secret{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Secret", }, ObjectMeta: metav1.ObjectMeta{ Name: secretName, Namespace: namespace, }, } // pod reconciler create CouchDBUser require.Eventually(t, func() bool { err := cl.Get(ctx, client.ObjectKeyFromObject(secret), secret) return err == nil }, timeout, interval, "Secret does not exist: %s", secret.Name) assert.Equal(t, string(secret.Data[string(Hostname)]), "localhost") assert.Equal(t, string(secret.Data[string(Lane)]), "1") assert.Equal(t, string(secret.Data[string(Role)]), string(v1ien.ControlPlane)) assert.Equal(t, string(secret.Data[string(Class)]), string(v1ien.Server)) assert.Equal(t, ref.Name, secret.OwnerReferences[0].Name) } func basicPod(namespace, name, nodeName string, reference []metav1.OwnerReference) *corev1.Pod { pod := &corev1.Pod{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Pod", }, ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: name, Labels: map[string]string{}, OwnerReferences: reference, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ { Name: "podinfo", Image: "podinfo:10.4", }, }, NodeName: nodeName, }, } return pod } func basicDeployment(namespace, name string) *appsv1.Deployment { label := "hola" replica := int32(1) return &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ Kind: "Deployment", APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: name, }, Spec: appsv1.DeploymentSpec{ Replicas: &replica, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "app": label, }, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ "app": label, }, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ { Name: "nginx", Image: "nginx", }, }, }, }, }, } } func ownerReference(obj *appsv1.Deployment) []metav1.OwnerReference { return []metav1.OwnerReference{ *metav1.NewControllerRef(obj, appsv1.SchemeGroupVersion.WithKind(reflect.TypeOf(appsv1.Deployment{}).Name())), } }