package mesh_test import ( "context" "fmt" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appmesh "github.com/aws/aws-app-mesh-controller-for-k8s/apis/appmesh/v1beta2" "github.com/aws/aws-app-mesh-controller-for-k8s/test/framework" "github.com/aws/aws-app-mesh-controller-for-k8s/test/framework/k8s" "github.com/aws/aws-app-mesh-controller-for-k8s/test/framework/utils" "github.com/aws/aws-app-mesh-controller-for-k8s/test/integration/mesh" "github.com/aws/aws-sdk-go/aws" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "time" ) var _ = Describe("Mesh", func() { var ( ctx context.Context f *framework.Framework ) BeforeEach(func() { ctx = context.Background() if f == nil { f = framework.New(framework.GlobalOptions) } if f.Options.ControllerImage != "" { By("Reset cluster with default controller", func() { f.HelmManager.ResetAppMeshController() }) } if f.Options.InjectorImage != "" { By("Reset cluster with default injector", func() { f.HelmManager.ResetAppMeshInjector() }) } }) Context("Mesh create scenarios", func() { var meshTest mesh.MeshTest meshTest = mesh.MeshTest{ Meshes: make(map[string]*appmesh.Mesh), } AfterEach(func() { meshTest.Cleanup(ctx, f) }) It("should create a mesh in AWS", func() { meshName := fmt.Sprintf("%s-%s", f.Options.ClusterName, utils.RandomDNS1123Label(6)) mesh := &appmesh.Mesh{ ObjectMeta: metav1.ObjectMeta{ Name: meshName, }, Spec: appmesh.MeshSpec{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "mesh": meshName, }, }, }, } By("creating a mesh resource in k8s", func() { err := meshTest.Create(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) for _, mesh := range meshTest.Meshes { By("validating the resources in AWS", func() { err := meshTest.CheckInAWS(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) } }) It("should show errors if the mesh cannot be created in AWS", func() { meshName := fmt.Sprintf("mesh-%s", utils.RandomDNS1123Label(8)) mesh := &appmesh.Mesh{ ObjectMeta: metav1.ObjectMeta{ Name: meshName, }, Spec: appmesh.MeshSpec{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "mesh": meshName, }, }, AWSName: aws.String(fmt.Sprintf("mesh-%s", utils.RandomDNS1123Label(256))), }, } By("Creating a mesh resource in k8s with a name exceeding the character limit", func() { // Not using meshTest.Create as it hangs err := f.K8sClient.Create(ctx, mesh) // sometimes there's a delay in the resource showing up observedMesh := &appmesh.Mesh{} for i := 0; i < 5; i++ { if err := f.K8sClient.Get(ctx, k8s.NamespacedName(mesh), observedMesh); err != nil { if i >= 5 { Expect(err).NotTo(HaveOccurred()) } } time.Sleep(100 * time.Millisecond) } meshTest.Meshes[mesh.Name] = mesh Expect(err).NotTo(HaveOccurred()) }) By("Check mesh in AWS - it should not exist", func() { err := meshTest.CheckInAWS(ctx, f, mesh) Expect(err).To(HaveOccurred()) }) By("checking events for the BadRequestException", func() { clientset, err := kubernetes.NewForConfig(f.RestCfg) Expect(err).NotTo(HaveOccurred()) events, err := clientset.CoreV1().Events(mesh.Namespace).List(ctx, metav1.ListOptions{ FieldSelector: fmt.Sprintf("involvedObject.name=%s", mesh.Name), TypeMeta: metav1.TypeMeta{ Kind: "Pod", }, }) Expect(err).NotTo(HaveOccurred()) Expect(events.Items).NotTo(BeEmpty()) }) }) It("should create a mesh with MeshDiscoverySpec", func() { meshName := fmt.Sprintf("%s-%s", f.Options.ClusterName, utils.RandomDNS1123Label(6)) mesh := &appmesh.Mesh{ ObjectMeta: metav1.ObjectMeta{ Name: meshName, }, Spec: appmesh.MeshSpec{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "mesh": meshName, }, }, ServiceDiscovery: &appmesh.MeshServiceDiscovery{ IpPreference: aws.String(appmesh.IpPreferenceIPv4), }, }, } By("creating a mesh resource in k8s", func() { err := meshTest.Create(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) for _, mesh := range meshTest.Meshes { By("validating the resources in AWS", func() { err := meshTest.CheckInAWS(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) } }) }) Context("Mesh update scenarios", func() { var meshTest mesh.MeshTest meshTest = mesh.MeshTest{ Meshes: make(map[string]*appmesh.Mesh), } AfterEach(func() { meshTest.Cleanup(ctx, f) }) It("should update egress filter for a mesh in AWS", func() { meshName := fmt.Sprintf("%s-%s", f.Options.ClusterName, utils.RandomDNS1123Label(6)) mesh := &appmesh.Mesh{ ObjectMeta: metav1.ObjectMeta{ Name: meshName, }, Spec: appmesh.MeshSpec{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "mesh": meshName, }, }, EgressFilter: &appmesh.EgressFilter{ Type: appmesh.EgressFilterTypeDropAll}, }, } By("creating a mesh resource in k8s", func() { err := meshTest.Create(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) By("validating the resources in AWS", func() { err := meshTest.CheckInAWS(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) By("updating the egress filter to ALLOW_ALL and validating the change", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.EgressFilter = &appmesh.EgressFilter{ Type: appmesh.EgressFilterTypeAllowAll} err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) Expect(err).NotTo(HaveOccurred()) err = meshTest.CheckInAWS(ctx, f, meshTest.Meshes[mesh.Name]) Expect(err).NotTo(HaveOccurred()) }) By("updating the egress filter to DROP_ALL and validating the change", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.EgressFilter = &appmesh.EgressFilter{ Type: appmesh.EgressFilterTypeDropAll} err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) Expect(err).NotTo(HaveOccurred()) err = meshTest.CheckInAWS(ctx, f, meshTest.Meshes[mesh.Name]) Expect(err).NotTo(HaveOccurred()) }) By("updating AWSName and validating it cannot be updated", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.AWSName = aws.String("testMesh") err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) Expect(err).To(HaveOccurred()) }) By("updating the egress filter with an invalid value", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.EgressFilter = &appmesh.EgressFilter{ Type: "DENY"} err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) Expect(err).To(HaveOccurred()) }) }) It("should update Ip Preference for a mesh in AWS", func() { meshName := fmt.Sprintf("%s-%s", f.Options.ClusterName, utils.RandomDNS1123Label(6)) mesh := &appmesh.Mesh{ ObjectMeta: metav1.ObjectMeta{ Name: meshName, }, Spec: appmesh.MeshSpec{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "mesh": meshName, }, }, ServiceDiscovery: &appmesh.MeshServiceDiscovery{ IpPreference: aws.String(appmesh.IpPreferenceIPv4), }, }, } By("creating a mesh resource in k8s", func() { err := meshTest.Create(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) By("validating the resources in AWS", func() { err := meshTest.CheckInAWS(ctx, f, mesh) Expect(err).NotTo(HaveOccurred()) }) By("updating the ipPreference and validating the change", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.ServiceDiscovery = &appmesh.MeshServiceDiscovery{ IpPreference: aws.String(appmesh.IpPreferenceIPv6), } err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) if f.Options.IpFamily == utils.IPv6 { Expect(meshTest.Meshes[mesh.Name].Spec.ServiceDiscovery.IpPreference).To(Equal(aws.String(appmesh.IpPreferenceIPv6))) } else { Expect(meshTest.Meshes[mesh.Name].Spec.ServiceDiscovery.IpPreference).To(Equal(aws.String(appmesh.IpPreferenceIPv4))) } Expect(err).NotTo(HaveOccurred()) err = meshTest.CheckInAWS(ctx, f, meshTest.Meshes[mesh.Name]) Expect(err).NotTo(HaveOccurred()) }) By("updating to not have Service Discovery for mesh and validating the change", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.ServiceDiscovery = nil err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) if f.Options.IpFamily == utils.IPv6 { Expect(meshTest.Meshes[mesh.Name].Spec.ServiceDiscovery.IpPreference).To(Equal(aws.String(appmesh.IpPreferenceIPv6))) } else { Expect(meshTest.Meshes[mesh.Name].Spec.ServiceDiscovery).To(BeNil()) } Expect(err).NotTo(HaveOccurred()) err = meshTest.CheckInAWS(ctx, f, meshTest.Meshes[mesh.Name]) Expect(err).NotTo(HaveOccurred()) }) By("updating AWSName and validating it cannot be updated", func() { oldMesh := meshTest.Meshes[mesh.Name].DeepCopy() meshTest.Meshes[mesh.Name].Spec.AWSName = aws.String("testMesh") err := meshTest.Update(ctx, f, meshTest.Meshes[mesh.Name], oldMesh) Expect(err).To(HaveOccurred()) }) }) }) })