diff --git a/app/kumactl/cmd/delete/delete.go b/app/kumactl/cmd/delete/delete.go new file mode 100644 index 000000000000..73a20afb9ea0 --- /dev/null +++ b/app/kumactl/cmd/delete/delete.go @@ -0,0 +1,82 @@ +package delete + +import ( + "context" + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + "github.com/Kong/kuma/pkg/core/resources/apis/mesh" + "github.com/Kong/kuma/pkg/core/resources/model" + "github.com/Kong/kuma/pkg/core/resources/registry" + "github.com/Kong/kuma/pkg/core/resources/store" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +func NewDeleteCmd(pctx *kumactl_cmd.RootContext) *cobra.Command { + cmd := &cobra.Command{ + Use: "delete TYPE NAME", + Short: "Delete Kuma resources", + Long: `Delete Kuma resources.`, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + rs, err := pctx.CurrentResourceStore() + if err != nil { + return err + } + resourceTypeArg := args[0] + name := args[1] + + var resource model.Resource + var resourceType model.ResourceType + switch resourceTypeArg { + case "mesh": + resourceType = mesh.MeshType + case "dataplane": + resourceType = mesh.DataplaneType + case "proxytemplate": + resourceType = mesh.ProxyTemplateType + case "traffic-log": + resourceType = mesh.TrafficLogType + case "traffic-permission": + resourceType = mesh.TrafficPermissionType + + default: + return errors.Errorf("unknown TYPE: %s. Allowed values: mesh, dataplane, proxytemplate, traffic-log, traffic-permission", resourceTypeArg) + } + + currentMesh := pctx.CurrentMesh() + if resourceType == mesh.MeshType { + currentMesh = name + } + + if resource, err = registry.Global().NewObject(resourceType); err != nil { + return err + } + + if err := deleteResource(name, currentMesh, resource, resourceType, rs); err != nil { + return err + } + + cmd.Printf("deleted %s %q\n", resourceType, name) + return nil + }, + } + + return cmd +} + +func deleteResource(name string, currentMesh string, resource model.Resource, resourceType model.ResourceType, rs store.ResourceStore) error { + getOptions := store.GetByKey(model.DefaultNamespace, name, currentMesh) + if err := rs.Get(context.Background(), resource, getOptions); err != nil { + if store.IsResourceNotFound(err) { + return errors.Errorf("there is no %s with name %q", resourceType, name) + } + return errors.Wrapf(err, "failed to get %s with the name %q", resourceType, name) + } + + deleteOptions := store.DeleteByKey(model.DefaultNamespace, name, currentMesh) + if err := rs.Delete(context.Background(), resource, deleteOptions); err != nil { + return errors.Wrapf(err, "failed to delete %s with the name %q", resourceType, name) + } + + return nil +} diff --git a/app/kumactl/cmd/delete/delete_dataplane_test.go b/app/kumactl/cmd/delete/delete_dataplane_test.go new file mode 100644 index 000000000000..4e9554c2afcf --- /dev/null +++ b/app/kumactl/cmd/delete/delete_dataplane_test.go @@ -0,0 +1,151 @@ +package delete_test + +import ( + "bytes" + "context" + mesh_proto "github.com/Kong/kuma/api/mesh/v1alpha1" + "github.com/Kong/kuma/app/kumactl/cmd" + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1" + mesh_core "github.com/Kong/kuma/pkg/core/resources/apis/mesh" + core_model "github.com/Kong/kuma/pkg/core/resources/model" + core_store "github.com/Kong/kuma/pkg/core/resources/store" + memory_resources "github.com/Kong/kuma/pkg/plugins/resources/memory" + test_model "github.com/Kong/kuma/pkg/test/resources/model" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + "path/filepath" +) + +var _ = Describe("kumactl delete dataplane", func() { + var dataplanes []*mesh_core.DataplaneResource + + BeforeEach(func() { + dataplanes = []*mesh_core.DataplaneResource{ + { + Meta: &test_model.ResourceMeta{ + Namespace: "default", + Mesh: "demo", + Name: "web-01", + }, + Spec: mesh_proto.Dataplane{ + Networking: &mesh_proto.Dataplane_Networking{ + Inbound: []*mesh_proto.Dataplane_Networking_Inbound{ + { + Interface: "127.0.0.1:8080:80", + Tags: map[string]string{ + "service": "mobile", + "version": "v1", + }, + }, + { + Interface: "127.0.0.1:8090:90", + Tags: map[string]string{ + "service": "metrics", + "version": "v1", + }, + }, + }, + }, + }, + }, + { + Meta: &test_model.ResourceMeta{ + Namespace: "default", + Mesh: "demo1", + Name: "web-02", + }, + Spec: mesh_proto.Dataplane{ + Networking: &mesh_proto.Dataplane_Networking{ + Inbound: []*mesh_proto.Dataplane_Networking_Inbound{ + { + Interface: "127.0.0.2:8080:80", + Tags: map[string]string{ + "service": "web", + "version": "v2", + }, + }, + }, + }, + }, + }, + } + }) + + Describe("Delete dataplane", func() { + var rootCtx *kumactl_cmd.RootContext + var rootCmd *cobra.Command + var outbuf, errbuf *bytes.Buffer + var store core_store.ResourceStore + + BeforeEach(func() { + // setup + + rootCtx = &kumactl_cmd.RootContext{ + Runtime: kumactl_cmd.RootRuntime{ + NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) { + return store, nil + }, + }, + } + + store = memory_resources.NewStore() + + for _, pt := range dataplanes { + key := core_model.MetaToResourceKey(pt.Meta) + err := store.Create(context.Background(), pt, core_store.CreateBy(key)) + Expect(err).ToNot(HaveOccurred()) + } + + rootCmd = cmd.NewRootCmd(rootCtx) + outbuf = &bytes.Buffer{} + errbuf = &bytes.Buffer{} + rootCmd.SetOut(outbuf) + rootCmd.SetErr(errbuf) + }) + + It("should throw an error in case of a non existing dataplane", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "dataplane", "some-non-existing-dataplane"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("there is no Dataplane with name \"some-non-existing-dataplane\"")) + // and + Expect(outbuf.String()).To(Equal("Error: there is no Dataplane with name \"some-non-existing-dataplane\"\n")) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should delete the dataplane if exists", func() { + + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "dataplane", "web-01", "--mesh", "demo"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).ToNot(HaveOccurred()) + + // and + list := &mesh_core.DataplaneResourceList{} + err = store.List(context.Background(), list, core_store.ListByNamespace("default")) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).To(HaveLen(1)) + // and + Expect(errbuf.String()).To(BeEmpty()) + // and + Expect(outbuf.String()).To(Equal("deleted Dataplane \"web-01\"\n")) + }) + }) +}) diff --git a/app/kumactl/cmd/delete/delete_meshes_test.go b/app/kumactl/cmd/delete/delete_meshes_test.go new file mode 100644 index 000000000000..878bfc0e44cd --- /dev/null +++ b/app/kumactl/cmd/delete/delete_meshes_test.go @@ -0,0 +1,165 @@ +package delete_test + +import ( + "bytes" + "context" + "path/filepath" + "time" + + "github.com/Kong/kuma/api/mesh/v1alpha1" + "github.com/Kong/kuma/app/kumactl/cmd" + config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1" + "github.com/Kong/kuma/pkg/core/resources/apis/mesh" + core_model "github.com/Kong/kuma/pkg/core/resources/model" + core_store "github.com/Kong/kuma/pkg/core/resources/store" + memory_resources "github.com/Kong/kuma/pkg/plugins/resources/memory" + test_model "github.com/Kong/kuma/pkg/test/resources/model" + + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" +) + +var _ = Describe("kumactl delete mesh", func() { + + sampleMeshes := []*mesh.MeshResource{ + { + Spec: v1alpha1.Mesh{ + Mtls: &v1alpha1.Mesh_Mtls{ + Enabled: true, + Ca: &v1alpha1.CertificateAuthority{ + Type: &v1alpha1.CertificateAuthority_Builtin_{ + Builtin: &v1alpha1.CertificateAuthority_Builtin{}, + }, + }, + }, + Logging: &v1alpha1.Logging{ + AccessLogs: &v1alpha1.Logging_AccessLogs{ + Enabled: true, + FilePath: "/tmp/access.log", + }, + }, + }, + Meta: &test_model.ResourceMeta{ + Mesh: "mesh1", + Name: "mesh1", + Namespace: "default", + }, + }, + { + Spec: v1alpha1.Mesh{ + Mtls: &v1alpha1.Mesh_Mtls{ + Enabled: false, + Ca: &v1alpha1.CertificateAuthority{ + Type: &v1alpha1.CertificateAuthority_Builtin_{ + Builtin: &v1alpha1.CertificateAuthority_Builtin{}, + }, + }, + }, + }, + Meta: &test_model.ResourceMeta{ + Mesh: "mesh2", + Name: "mesh2", + Namespace: "default", + }, + }, + } + + Describe("Delete Mesh", func() { + + var rootCtx *kumactl_cmd.RootContext + var rootCmd *cobra.Command + var outbuf, errbuf *bytes.Buffer + var store core_store.ResourceStore + + BeforeEach(func() { + // setup + rootCtx = &kumactl_cmd.RootContext{ + Runtime: kumactl_cmd.RootRuntime{ + Now: func() time.Time { return time.Now() }, + NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) { + return store, nil + }, + }, + } + + store = memory_resources.NewStore() + + for _, ds := range sampleMeshes { + key := core_model.MetaToResourceKey(ds.Meta) + err := store.Create(context.Background(), ds, core_store.CreateBy(key)) + Expect(err).ToNot(HaveOccurred()) + } + + rootCmd = cmd.NewRootCmd(rootCtx) + outbuf = &bytes.Buffer{} + errbuf = &bytes.Buffer{} + rootCmd.SetOut(outbuf) + rootCmd.SetErr(errbuf) + }) + + It("should throw an error in case of no args", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "mesh"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("accepts 2 arg(s), received 1")) + // and + Expect(outbuf.String()).To(MatchRegexp(`Error: accepts 2 arg\(s\), received 1`)) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should throw an error in case of a non existing mesh", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "mesh", "some-non-existing-mesh"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("there is no Mesh with name \"some-non-existing-mesh\"")) + // and + Expect(outbuf.String()).To(Equal("Error: there is no Mesh with name \"some-non-existing-mesh\"\n")) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should delete the mesh if exists", func() { + + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "mesh", "mesh2"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).ToNot(HaveOccurred()) + + // and + list := &mesh.MeshResourceList{} + err = store.List(context.Background(), list, core_store.ListByNamespace("default")) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).To(HaveLen(1)) + // and + Expect(errbuf.String()).To(BeEmpty()) + // and + Expect(outbuf.String()).To(Equal("deleted Mesh \"mesh2\"\n")) + }) + }) + +}) diff --git a/app/kumactl/cmd/delete/delete_proxytemplate_test.go b/app/kumactl/cmd/delete/delete_proxytemplate_test.go new file mode 100644 index 000000000000..a94c7af55f15 --- /dev/null +++ b/app/kumactl/cmd/delete/delete_proxytemplate_test.go @@ -0,0 +1,134 @@ +package delete_test + +import ( + "bytes" + "context" + "github.com/Kong/kuma/app/kumactl/cmd" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + "path/filepath" + + mesh_proto "github.com/Kong/kuma/api/mesh/v1alpha1" + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1" + mesh_core "github.com/Kong/kuma/pkg/core/resources/apis/mesh" + core_model "github.com/Kong/kuma/pkg/core/resources/model" + core_store "github.com/Kong/kuma/pkg/core/resources/store" + memory_resources "github.com/Kong/kuma/pkg/plugins/resources/memory" + + test_model "github.com/Kong/kuma/pkg/test/resources/model" +) + +var _ = Describe("kumactl delete proxytemplates", func() { + + var sampleProxyTemplates []*mesh_core.ProxyTemplateResource + + BeforeEach(func() { + sampleProxyTemplates = []*mesh_core.ProxyTemplateResource{ + { + Meta: &test_model.ResourceMeta{ + Namespace: "default", + Mesh: "Mesh1", + Name: "custom-template", + }, + Spec: mesh_proto.ProxyTemplate{}, + }, + { + Meta: &test_model.ResourceMeta{ + Namespace: "default", + Mesh: "Mesh2", + Name: "another-template", + }, + Spec: mesh_proto.ProxyTemplate{}, + }, + { + Meta: &test_model.ResourceMeta{ + Namespace: "default", + Mesh: "Mesh3", + Name: "simple-template", + }, + Spec: mesh_proto.ProxyTemplate{}, + }, + } + }) + + Describe("Delete ProxyTemplate", func() { + + var rootCtx *kumactl_cmd.RootContext + var rootCmd *cobra.Command + var outbuf, errbuf *bytes.Buffer + var store core_store.ResourceStore + + BeforeEach(func() { + // setup + + rootCtx = &kumactl_cmd.RootContext{ + Runtime: kumactl_cmd.RootRuntime{ + NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) { + return store, nil + }, + }, + } + + store = memory_resources.NewStore() + + for _, pt := range sampleProxyTemplates { + key := core_model.MetaToResourceKey(pt.Meta) + err := store.Create(context.Background(), pt, core_store.CreateBy(key)) + Expect(err).ToNot(HaveOccurred()) + } + + rootCmd = cmd.NewRootCmd(rootCtx) + outbuf = &bytes.Buffer{} + errbuf = &bytes.Buffer{} + rootCmd.SetOut(outbuf) + rootCmd.SetErr(errbuf) + }) + + It("should throw an error in case of a non existing proxytemplate", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "proxytemplate", "some-non-existing-proxytemplate"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("there is no ProxyTemplate with name \"some-non-existing-proxytemplate\"")) + // and + Expect(outbuf.String()).To(Equal("Error: there is no ProxyTemplate with name \"some-non-existing-proxytemplate\"\n")) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should delete the proxytemplate if exists", func() { + + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "proxytemplate", "custom-template", "--mesh", "Mesh1"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).ToNot(HaveOccurred()) + + // and + list := &mesh_core.ProxyTemplateResourceList{} + err = store.List(context.Background(), list, core_store.ListByNamespace("default")) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).To(HaveLen(2)) + // and + Expect(errbuf.String()).To(BeEmpty()) + Expect(errbuf.String()).To(BeEmpty()) + // and + Expect(outbuf.String()).To(Equal("deleted ProxyTemplate \"custom-template\"\n")) + }) + + }) +}) diff --git a/app/kumactl/cmd/delete/delete_suite_test.go b/app/kumactl/cmd/delete/delete_suite_test.go new file mode 100644 index 000000000000..d50e69234715 --- /dev/null +++ b/app/kumactl/cmd/delete/delete_suite_test.go @@ -0,0 +1,13 @@ +package delete_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestDeleteCmd(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Delete Cmd Suite") +} diff --git a/app/kumactl/cmd/delete/delete_test.go b/app/kumactl/cmd/delete/delete_test.go new file mode 100644 index 000000000000..8e66e4268cd4 --- /dev/null +++ b/app/kumactl/cmd/delete/delete_test.go @@ -0,0 +1,78 @@ +package delete_test + +import ( + "bytes" + "github.com/Kong/kuma/app/kumactl/cmd" + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1" + core_store "github.com/Kong/kuma/pkg/core/resources/store" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + "path/filepath" + "time" +) + +var _ = Describe("kumactl delete ", func() { + Describe("Delete Command", func() { + var rootCtx *kumactl_cmd.RootContext + var rootCmd *cobra.Command + var outbuf, errbuf *bytes.Buffer + var store core_store.ResourceStore + + BeforeEach(func() { + // setup + rootCtx = &kumactl_cmd.RootContext{ + Runtime: kumactl_cmd.RootRuntime{ + Now: func() time.Time { return time.Now() }, + NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) { + return store, nil + }, + }, + } + rootCmd = cmd.NewRootCmd(rootCtx) + outbuf = &bytes.Buffer{} + errbuf = &bytes.Buffer{} + rootCmd.SetOut(outbuf) + rootCmd.SetErr(errbuf) + }) + + It("should throw an error in case of no args", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("accepts 2 arg(s), received 0")) + // and + Expect(outbuf.String()).To(MatchRegexp(`Error: accepts 2 arg\(s\), received 0`)) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should throw an error in case of unsupported resource type", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "some-type", "some-name"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("unknown TYPE: some-type. Allowed values: mesh, dataplane, proxytemplate, traffic-log, traffic-permission")) + // and + Expect(outbuf.String()).To(MatchRegexp(`unknown TYPE: some-type. Allowed values: mesh, dataplane, proxytemplate, traffic-log, traffic-permission`)) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + }) +}) diff --git a/app/kumactl/cmd/delete/delete_trafficlog_test.go b/app/kumactl/cmd/delete/delete_trafficlog_test.go new file mode 100644 index 000000000000..34ae130541c2 --- /dev/null +++ b/app/kumactl/cmd/delete/delete_trafficlog_test.go @@ -0,0 +1,174 @@ +package delete_test + +import ( + "bytes" + "context" + "github.com/Kong/kuma/app/kumactl/cmd" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + "path/filepath" + "time" + + mesh_proto "github.com/Kong/kuma/api/mesh/v1alpha1" + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1" + mesh_core "github.com/Kong/kuma/pkg/core/resources/apis/mesh" + core_model "github.com/Kong/kuma/pkg/core/resources/model" + core_store "github.com/Kong/kuma/pkg/core/resources/store" + memory_resources "github.com/Kong/kuma/pkg/plugins/resources/memory" + + test_model "github.com/Kong/kuma/pkg/test/resources/model" +) + +var _ = Describe("kumactl delete trafficlog", func() { + + trafficLoggingResources := []*mesh_core.TrafficLogResource{ + { + Spec: mesh_proto.TrafficLog{ + Rules: []*mesh_proto.TrafficLog_Rule{ + { + Sources: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "web1", + "version": "1.0", + }, + }, + }, + Destinations: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "backend1", + "env": "dev", + }, + }, + }, + Conf: &mesh_proto.TrafficLog_Rule_Conf{ + Backend: "file", + }, + }, + }, + }, + Meta: &test_model.ResourceMeta{ + Mesh: "Mesh1", + Name: "web1-to-backend1", + Namespace: "default", + }, + }, + { + Spec: mesh_proto.TrafficLog{ + Rules: []*mesh_proto.TrafficLog_Rule{ + { + Sources: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "web2", + "version": "1.0", + }, + }, + }, + Destinations: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "backend2", + "env": "dev", + }, + }, + }, + Conf: &mesh_proto.TrafficLog_Rule_Conf{ + Backend: "logstash", + }, + }, + }, + }, + Meta: &test_model.ResourceMeta{ + Mesh: "Mesh2", + Name: "web2-to-backend2", + Namespace: "default", + }, + }, + } + + Describe("delete trafficlog", func() { + + var rootCtx *kumactl_cmd.RootContext + var rootCmd *cobra.Command + var outbuf, errbuf *bytes.Buffer + var store core_store.ResourceStore + + BeforeEach(func() { + // setup + rootCtx = &kumactl_cmd.RootContext{ + Runtime: kumactl_cmd.RootRuntime{ + Now: func() time.Time { return time.Now() }, + NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) { + return store, nil + }, + }, + } + + store = memory_resources.NewStore() + + for _, ds := range trafficLoggingResources { + err := store.Create(context.Background(), ds, core_store.CreateBy(core_model.MetaToResourceKey(ds.GetMeta()))) + Expect(err).ToNot(HaveOccurred()) + } + + rootCmd = cmd.NewRootCmd(rootCtx) + outbuf = &bytes.Buffer{} + errbuf = &bytes.Buffer{} + rootCmd.SetOut(outbuf) + rootCmd.SetErr(errbuf) + }) + + Describe("Delete TrafficLog", func() { + + It("should throw an error in case of a non existing trafficlog", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "traffic-log", "some-non-existing-trafficlog"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("there is no TrafficLog with name \"some-non-existing-trafficlog\"")) + // and + Expect(outbuf.String()).To(Equal("Error: there is no TrafficLog with name \"some-non-existing-trafficlog\"\n")) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should delete the trafficlog if exists", func() { + + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "traffic-log", "web1-to-backend1", "--mesh", "Mesh1"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).ToNot(HaveOccurred()) + + // and + list := &mesh_core.TrafficLogResourceList{} + err = store.List(context.Background(), list, core_store.ListByNamespace("default")) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).To(HaveLen(1)) + // and + Expect(errbuf.String()).To(BeEmpty()) + Expect(errbuf.String()).To(BeEmpty()) + // and + Expect(outbuf.String()).To(Equal("deleted TrafficLog \"web1-to-backend1\"\n")) + }) + + }) + }) + +}) diff --git a/app/kumactl/cmd/delete/delete_trafficpermission_test.go b/app/kumactl/cmd/delete/delete_trafficpermission_test.go new file mode 100644 index 000000000000..874d14918129 --- /dev/null +++ b/app/kumactl/cmd/delete/delete_trafficpermission_test.go @@ -0,0 +1,164 @@ +package delete_test + +import ( + "bytes" + "context" + "github.com/Kong/kuma/app/kumactl/cmd" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + "path/filepath" + "time" + + mesh_proto "github.com/Kong/kuma/api/mesh/v1alpha1" + kumactl_cmd "github.com/Kong/kuma/app/kumactl/pkg/cmd" + config_proto "github.com/Kong/kuma/pkg/config/app/kumactl/v1alpha1" + mesh_core "github.com/Kong/kuma/pkg/core/resources/apis/mesh" + core_model "github.com/Kong/kuma/pkg/core/resources/model" + core_store "github.com/Kong/kuma/pkg/core/resources/store" + memory_resources "github.com/Kong/kuma/pkg/plugins/resources/memory" + + test_model "github.com/Kong/kuma/pkg/test/resources/model" +) + +var _ = Describe("kumactl delete traffic permission", func() { + + trafficPermissionResources := []*mesh_core.TrafficPermissionResource{ + { + Spec: mesh_proto.TrafficPermission{ + Rules: []*mesh_proto.TrafficPermission_Rule{ + { + Sources: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "web1", + "version": "1.0", + }, + }, + }, + Destinations: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "backend1", + "env": "dev", + }, + }, + }, + }, + }, + }, + Meta: &test_model.ResourceMeta{ + Mesh: "Mesh1", + Name: "web1-to-backend1", + Namespace: "default", + }, + }, + { + Spec: mesh_proto.TrafficPermission{ + Rules: []*mesh_proto.TrafficPermission_Rule{ + { + Sources: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "web2", + "version": "1.0", + }, + }, + }, + Destinations: []*mesh_proto.Selector{ + { + Match: map[string]string{ + "service": "backend2", + "env": "dev", + }, + }, + }, + }, + }, + }, + Meta: &test_model.ResourceMeta{ + Mesh: "Mesh2", + Name: "web2-to-backend2", + Namespace: "default", + }, + }, + } + + Describe("Delete TrafficPermission", func() { + + var rootCtx *kumactl_cmd.RootContext + var rootCmd *cobra.Command + var outbuf, errbuf *bytes.Buffer + var store core_store.ResourceStore + + BeforeEach(func() { + // setup + rootCtx = &kumactl_cmd.RootContext{ + Runtime: kumactl_cmd.RootRuntime{ + Now: func() time.Time { return time.Now() }, + NewResourceStore: func(*config_proto.ControlPlaneCoordinates_ApiServer) (core_store.ResourceStore, error) { + return store, nil + }, + }, + } + + store = memory_resources.NewStore() + + for _, ds := range trafficPermissionResources { + err := store.Create(context.Background(), ds, core_store.CreateBy(core_model.MetaToResourceKey(ds.GetMeta()))) + Expect(err).ToNot(HaveOccurred()) + } + + rootCmd = cmd.NewRootCmd(rootCtx) + outbuf = &bytes.Buffer{} + errbuf = &bytes.Buffer{} + rootCmd.SetOut(outbuf) + rootCmd.SetErr(errbuf) + }) + + It("should throw an error in case of a non existing traffic permission", func() { + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "traffic-permission", "some-non-existing-trafficpermission"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).To(HaveOccurred()) + // and + Expect(err.Error()).To(Equal("there is no TrafficPermission with name \"some-non-existing-trafficpermission\"")) + // and + Expect(outbuf.String()).To(Equal("Error: there is no TrafficPermission with name \"some-non-existing-trafficpermission\"\n")) + // and + Expect(errbuf.Bytes()).To(BeEmpty()) + }) + + It("should delete the traffic permission if exists", func() { + + // given + rootCmd.SetArgs([]string{ + "--config-file", filepath.Join("..", "testdata", "sample-kumactl.config.yaml"), + "delete", "traffic-permission", "web2-to-backend2", "--mesh", "Mesh2"}) + + // when + err := rootCmd.Execute() + + // then + Expect(err).ToNot(HaveOccurred()) + + // and + list := &mesh_core.TrafficPermissionResourceList{} + err = store.List(context.Background(), list, core_store.ListByNamespace("default")) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).To(HaveLen(1)) + // and + Expect(errbuf.String()).To(BeEmpty()) + Expect(errbuf.String()).To(BeEmpty()) + // and + Expect(outbuf.String()).To(Equal("deleted TrafficPermission \"web2-to-backend2\"\n")) + }) + + }) +}) diff --git a/app/kumactl/cmd/root.go b/app/kumactl/cmd/root.go index c78834512e02..d53471727c2f 100644 --- a/app/kumactl/cmd/root.go +++ b/app/kumactl/cmd/root.go @@ -6,6 +6,7 @@ import ( "github.com/Kong/kuma/app/kumactl/cmd/apply" "github.com/Kong/kuma/app/kumactl/cmd/config" + "github.com/Kong/kuma/app/kumactl/cmd/delete" "github.com/Kong/kuma/app/kumactl/cmd/generate" "github.com/Kong/kuma/app/kumactl/cmd/get" "github.com/Kong/kuma/app/kumactl/cmd/inspect" @@ -60,6 +61,7 @@ func NewRootCmd(root *kumactl_cmd.RootContext) *cobra.Command { cmd.AddCommand(install.NewInstallCmd(root)) cmd.AddCommand(config.NewConfigCmd(root)) cmd.AddCommand(get.NewGetCmd(root)) + cmd.AddCommand(delete.NewDeleteCmd(root)) cmd.AddCommand(inspect.NewInspectCmd(root)) cmd.AddCommand(apply.NewApplyCmd(root)) cmd.AddCommand(version.NewVersionCmd()) diff --git a/docs/cmd/kumactl/HELP.md b/docs/cmd/kumactl/HELP.md index 52f61988c6b6..b7f32d983e16 100644 --- a/docs/cmd/kumactl/HELP.md +++ b/docs/cmd/kumactl/HELP.md @@ -9,6 +9,7 @@ Usage: Available Commands: apply Create or modify Kuma resources config Manage kumactl config + delete Delete Kuma resources generate Generate resources, tokens, etc get Show Kuma resources help Help about any command