package nodeagent import ( "context" "os" "testing" "time" "github.com/stretchr/testify/require" "gotest.tools/v3/assert/cmp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "edge-infra.dev/pkg/k8s/runtime/conditions" "edge-infra.dev/pkg/k8s/runtime/events" "edge-infra.dev/pkg/k8s/testing/kmp" "edge-infra.dev/pkg/lib/fog" v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1" "edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/config" "edge-infra.dev/test/f2" "edge-infra.dev/test/f2/x/ktest" ) var f f2.Framework var ( ienodeName = "edge-worker" ) var sdsNamespaceTest = corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "sds", }, } var ( flagsTest = config.Flags{ WatchAllNamespaces: &watchAllNamespaces, PluginsConfigMap: &pluginsConfigMapNamespacedName, ThinclientConfigMap: &thinclientConfigMapNotSet, Pprof: nil, NodeRootPath: &nodeRootPath, } watchAllNamespaces = false pluginsConfigMapNamespacedName = "nodeagent-plugins" thinclientConfigMapNotSet = "" nodeRootPath = "/" nodeAgentConfigMapTest = corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "nodeagent-plugins", Namespace: "sds", }, Data: map[string]string{ "suspendAll": "false", "exampleIENode": "true", "exampleSecret": "false", "exampleConfigMap": "true", "exampleNodeFirewall": "true", }, } nodeInfo = corev1.Node{ ObjectMeta: metav1.ObjectMeta{ Name: "edge-worker", }, } ) var secretTest = corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: "sds", Name: "example-secret"}} var ( clusterFirewall = v1ien.NewClusterFirewall("testClusterFirewall", []v1ien.ClusterRule{}) ownerRef = *metav1.NewControllerRef(clusterFirewall, v1ien.ClusterFirewallGVK) nodefirewallTest = v1ien.NewNodeFirewall("edge-worker-example-nodefirewall", []v1ien.NodeRule{}, ownerRef) ) func TestMain(m *testing.M) { ctrl.SetLogger(fog.New()) os.Setenv("HOSTNAME", ienodeName) f = f2.New( context.Background(), f2.WithExtensions( ktest.New( ktest.WithCtrlManager(createControllerManager), ), )). Setup(func(ctx f2.Context) (f2.Context, error) { k, err := ktest.FromContext(ctx) if err != nil { return ctx, err } // Override timeouts if we aren't using a live cluster if !*k.Env.UseExistingCluster { k.Timeout = 5 * time.Second k.Tick = 10 * time.Millisecond } return ctx, nil }) os.Exit(f.Run(m)) } func TestControllerEntersReadyState(t *testing.T) { status := f2.NewFeature("Reconciles its Status"). Setup("Register Controllers", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) eventRecorder := events.NewRecorder(k.Manager, ctrl.Log, "nodeagent") _, err := registerControllers(flagsTest, k.Manager, eventRecorder) require.NoError(t, err) ns := sdsNamespaceTest.DeepCopy() require.NoError(t, k.Client.Create(ctx, ns)) node := nodeInfo.DeepCopy() require.NoError(t, k.Client.Create(ctx, node)) cm := nodeAgentConfigMapTest.DeepCopy() require.NoError(t, k.Client.Create(ctx, cm)) secret := secretTest.DeepCopy() require.NoError(t, k.Client.Create(ctx, secret)) nodefirewall := nodefirewallTest.DeepCopy() require.NoError(t, k.Client.Create(ctx, nodefirewall)) return ctx }). Test("Check IEN becomes ready after reconciling", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) ienode := IENodeMock() require.NoError(t, k.Client.Create(ctx, ienode)) k.WaitOn(t, k.Check(ienode, kmp.IsReady())) return ctx }). Test("Check ConfigMap plugin is ready", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) ienode := IENodeMock() k.WaitOn(t, k.Check(ienode, func(o client.Object) cmp.Result { ienode, _ := o.(*v1ien.IENode) if conditions.IsTrue(ienode, "exampleConfigMap") { return cmp.ResultSuccess } return cmp.ResultFailure("exampleConfigMap conditions not true") })) return ctx }). Test("Check Secrets plugin is ready", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) ienode := IENodeMock() k.WaitOn(t, k.Check(ienode, func(o client.Object) cmp.Result { ienode, _ := o.(*v1ien.IENode) if conditions.IsTrue(ienode, "exampleSecret") { return cmp.ResultSuccess } return cmp.ResultFailure("exampleSecret conditions not true") })) return ctx }). Test("Check NodeFirewall plugin is ready", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) ienode := IENodeMock() k.WaitOn(t, k.Check(ienode, func(o client.Object) cmp.Result { ienode, _ := o.(*v1ien.IENode) if conditions.IsTrue(ienode, "exampleNodeFirewall") { return cmp.ResultSuccess } return cmp.ResultFailure("exampleNodeFirewall conditions not true") })) return ctx }). Feature() f.Test(t, status) } func IENodeMock() *v1ien.IENode { return &v1ien.IENode{ ObjectMeta: metav1.ObjectMeta{ Name: ienodeName, }, Spec: v1ien.IENodeSpec{ Role: "worker", Lane: "1", Network: []v1ien.Network{ { MacAddress: "90:74:c2:0f:d8:77", Addresses: make([]string, 0), Gateway4: "192.168.1.1", DHCP4: false, DHCP6: false, }, }, PrimaryInterface: &v1ien.PrimaryInterface{ InterfaceID: "9647e74f-aba3-447f-b327-31ecce7f8d4c", MacAddresses: []string{"90:74:c2:0f:d8:77"}, }, }, } }