From 7bb2c7cf139fbd1ca5ec6aad9acbd8c26be49291 Mon Sep 17 00:00:00 2001 From: wangxinyi7 <121973291+wangxinyi7@users.noreply.github.com> Date: Wed, 24 Jan 2024 15:17:54 -0800 Subject: [PATCH] Xw/net 5724 grpc client delete (#20309) * delete commmand works --- Dockerfile | 2 +- command/registry.go | 2 + command/resource/apply-grpc/apply.go | 2 +- command/resource/apply-grpc/apply_test.go | 4 +- .../resource/client/grpc-resource-flags.go | 16 +- command/resource/delete-grpc/delete.go | 164 ++++++++++++++++++ command/resource/delete-grpc/delete_test.go | 164 ++++++++++++++++++ command/resource/delete/delete.go | 14 +- command/resource/delete/delete_test.go | 2 +- command/resource/helper.go | 4 +- command/resource/list-grpc/list.go | 4 +- command/resource/list-grpc/list_test.go | 8 +- command/resource/list/list.go | 2 +- command/resource/list/list_test.go | 7 +- command/resource/read-grpc/read.go | 4 +- command/resource/read-grpc/read_test.go | 2 +- command/resource/read/read_test.go | 2 +- command/resource/resource-grpc.go | 26 +++ command/resource/testdata/demo.hcl | 2 +- command/resource/testdata/invalid.hcl | 2 +- command/resource/testdata/invalid_type.hcl | 2 +- .../connect/config-entries/proxy-defaults.mdx | 92 +++++----- 22 files changed, 442 insertions(+), 85 deletions(-) create mode 100644 command/resource/delete-grpc/delete.go create mode 100644 command/resource/delete-grpc/delete_test.go diff --git a/Dockerfile b/Dockerfile index 5d973446f3..faeb85810f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -233,7 +233,7 @@ COPY LICENSE /licenses/mozilla.txt # Set up certificates and base tools. # dumb-init is downloaded directly from GitHub because there's no RPM package. -# Its shasum is hardcoded. If you upgrade the dumb-init verion you'll need to +# Its shasum is hardcoded. If you upgrade the dumb-init version you'll need to # also update the shasum. RUN set -eux && \ microdnf install -y ca-certificates shadow-utils gnupg libcap openssl iputils jq iptables wget unzip tar && \ diff --git a/command/registry.go b/command/registry.go index d3369e3cd8..0375787022 100644 --- a/command/registry.go +++ b/command/registry.go @@ -117,6 +117,7 @@ import ( resourceapply "github.com/hashicorp/consul/command/resource/apply" resourceapplygrpc "github.com/hashicorp/consul/command/resource/apply-grpc" resourcedelete "github.com/hashicorp/consul/command/resource/delete" + resourcedeletegrpc "github.com/hashicorp/consul/command/resource/delete-grpc" resourcelist "github.com/hashicorp/consul/command/resource/list" resourcelistgrpc "github.com/hashicorp/consul/command/resource/list-grpc" resourceread "github.com/hashicorp/consul/command/resource/read" @@ -265,6 +266,7 @@ func RegisteredCommands(ui cli.Ui) map[string]mcli.CommandFactory { entry{"resource apply-grpc", func(ui cli.Ui) (cli.Command, error) { return resourceapplygrpc.New(ui), nil }}, entry{"resource read-grpc", func(ui cli.Ui) (cli.Command, error) { return resourcereadgrpc.New(ui), nil }}, entry{"resource list-grpc", func(ui cli.Ui) (cli.Command, error) { return resourcelistgrpc.New(ui), nil }}, + entry{"resource delete-grpc", func(ui cli.Ui) (cli.Command, error) { return resourcedeletegrpc.New(ui), nil }}, entry{"resource list", func(ui cli.Ui) (cli.Command, error) { return resourcelist.New(ui), nil }}, entry{"rtt", func(ui cli.Ui) (cli.Command, error) { return rtt.New(ui), nil }}, entry{"services", func(cli.Ui) (cli.Command, error) { return services.New(), nil }}, diff --git a/command/resource/apply-grpc/apply.go b/command/resource/apply-grpc/apply.go index a4e94b41f0..1819730c48 100644 --- a/command/resource/apply-grpc/apply.go +++ b/command/resource/apply-grpc/apply.go @@ -134,8 +134,8 @@ Usage: consul resource apply [options] Type = gvk("group.version.kind") Name = "resource-name" Tenancy { - Namespace = "default" Partition = "default" + Namespace = "default" PeerName = "local" } } diff --git a/command/resource/apply-grpc/apply_test.go b/command/resource/apply-grpc/apply_test.go index 6be23c491d..e4e0cbbb23 100644 --- a/command/resource/apply-grpc/apply_test.go +++ b/command/resource/apply-grpc/apply_test.go @@ -94,8 +94,8 @@ func TestResourceApplyCommand_StdIn(t *testing.T) { Type = gvk("demo.v2.Artist") Name = "korn" Tenancy { - Namespace = "default" Partition = "default" + Namespace = "default" PeerName = "local" } } @@ -145,8 +145,8 @@ func TestResourceApplyCommand_StdIn(t *testing.T) { "id": { "name": "korn", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" }, "type": { diff --git a/command/resource/client/grpc-resource-flags.go b/command/resource/client/grpc-resource-flags.go index f0146f6da6..0671b0be82 100644 --- a/command/resource/client/grpc-resource-flags.go +++ b/command/resource/client/grpc-resource-flags.go @@ -6,21 +6,21 @@ package client import "flag" type ResourceFlags struct { - namespace TValue[string] partition TValue[string] + namespace TValue[string] peername TValue[string] stale TValue[bool] } func (f *ResourceFlags) ResourceFlags() *flag.FlagSet { fs := flag.NewFlagSet("", flag.ContinueOnError) - fs.Var(&f.namespace, "namespace", - "Specifies the namespace to query. If not provided, the namespace will be inferred "+ - "from the request's ACL token, or will default to the `default` namespace.") fs.Var(&f.partition, "partition", "Specifies the admin partition to query. If not provided, the admin partition will be inferred "+ "from the request's ACL token, or will default to the `default` admin partition. "+ "Admin Partitions are a Consul Enterprise feature.") + fs.Var(&f.namespace, "namespace", + "Specifies the namespace to query. If not provided, the namespace will be inferred "+ + "from the request's ACL token, or will default to the `default` namespace.") fs.Var(&f.peername, "peer", "Specifies the name of peer to query. By default, it is `local`.") fs.Var(&f.stale, "stale", "Permit any Consul server (non-leader) to respond to this request. This "+ @@ -30,14 +30,14 @@ func (f *ResourceFlags) ResourceFlags() *flag.FlagSet { return fs } -func (f *ResourceFlags) Namespace() string { - return f.namespace.String() -} - func (f *ResourceFlags) Partition() string { return f.partition.String() } +func (f *ResourceFlags) Namespace() string { + return f.namespace.String() +} + func (f *ResourceFlags) Peername() string { return f.peername.String() } diff --git a/command/resource/delete-grpc/delete.go b/command/resource/delete-grpc/delete.go new file mode 100644 index 0000000000..af2a5c7fb4 --- /dev/null +++ b/command/resource/delete-grpc/delete.go @@ -0,0 +1,164 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package delete + +import ( + "errors" + "flag" + "fmt" + + "github.com/mitchellh/cli" + + "github.com/hashicorp/consul/command/flags" + "github.com/hashicorp/consul/command/resource" + "github.com/hashicorp/consul/command/resource/client" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +func New(ui cli.Ui) *cmd { + c := &cmd{UI: ui} + c.init() + return c +} + +type cmd struct { + UI cli.Ui + flags *flag.FlagSet + grpcFlags *client.GRPCFlags + resourceFlags *client.ResourceFlags + help string + + filePath string +} + +func (c *cmd) init() { + c.flags = flag.NewFlagSet("", flag.ContinueOnError) + c.flags.StringVar(&c.filePath, "f", "", + "File path with resource definition") + + c.grpcFlags = &client.GRPCFlags{} + c.resourceFlags = &client.ResourceFlags{} + client.MergeFlags(c.flags, c.grpcFlags.ClientFlags()) + client.MergeFlags(c.flags, c.resourceFlags.ResourceFlags()) + c.help = client.Usage(help, c.flags) +} + +func (c *cmd) Run(args []string) int { + var resourceType *pbresource.Type + var resourceTenancy *pbresource.Tenancy + var resourceName string + + if err := c.flags.Parse(args); err != nil { + if !errors.Is(err, flag.ErrHelp) { + c.UI.Error(fmt.Sprintf("Failed to parse args: %v", err)) + return 1 + } + c.UI.Error(fmt.Sprintf("Failed to run delete command: %v", err)) + return 1 + } + + // collect resource type, name and tenancy + if c.flags.Lookup("f").Value.String() != "" { + if c.filePath == "" { + c.UI.Error(fmt.Sprintf("Please provide an input file with resource definition")) + return 1 + } + parsedResource, err := resource.ParseResourceFromFile(c.filePath) + if err != nil { + c.UI.Error(fmt.Sprintf("Failed to decode resource from input file: %v", err)) + return 1 + } + + if parsedResource == nil { + c.UI.Error("Unable to parse the file argument") + return 1 + } + + resourceType = parsedResource.Id.Type + resourceTenancy = parsedResource.Id.Tenancy + resourceName = parsedResource.Id.Name + } else { + var err error + resourceType, resourceName, err = resource.GetTypeAndResourceName(args) + if err != nil { + c.UI.Error(fmt.Sprintf("Incorrect argument format: %s", err)) + return 1 + } + + inputArgs := args[2:] + err = resource.ParseInputParams(inputArgs, c.flags) + if err != nil { + c.UI.Error(fmt.Sprintf("Error parsing input arguments: %v", err)) + return 1 + } + if c.filePath != "" { + c.UI.Error("Incorrect argument format: File argument is not needed when resource information is provided with the command") + return 1 + } + resourceTenancy = &pbresource.Tenancy{ + Partition: c.resourceFlags.Partition(), + Namespace: c.resourceFlags.Namespace(), + PeerName: c.resourceFlags.Peername(), + } + } + + // initialize client + config, err := client.LoadGRPCConfig(nil) + if err != nil { + c.UI.Error(fmt.Sprintf("Error loading config: %s", err)) + return 1 + } + c.grpcFlags.MergeFlagsIntoGRPCConfig(config) + resourceClient, err := client.NewGRPCClient(config) + if err != nil { + c.UI.Error(fmt.Sprintf("Error connect to Consul agent: %s", err)) + return 1 + } + + // delete resource + res := resource.ResourceGRPC{C: resourceClient} + err = res.Delete(resourceType, resourceTenancy, resourceName) + if err != nil { + c.UI.Error(fmt.Sprintf("Error deleting resource %s/%s: %v", resourceType, resourceName, err)) + return 1 + } + + c.UI.Info(fmt.Sprintf("%s.%s.%s/%s deleted", resourceType.Group, resourceType.GroupVersion, resourceType.Kind, resourceName)) + return 0 +} + +func (c *cmd) Synopsis() string { + return synopsis +} + +func (c *cmd) Help() string { + return flags.Usage(c.help, nil) +} + +const synopsis = "Delete resource information" +const help = ` +Usage: You have two options to delete the resource specified by the given +type, name, partition, namespace and peer and outputs its JSON representation. + +consul resource delete [type] [name] -partition= -namespace= -peer= +consul resource delete -f [resource_file_path] + +But you could only use one of the approaches. + +Example: + +$ consul resource delete catalog.v2beta1.Service card-processor -partition=billing -namespace=payments -peer=eu +$ consul resource delete -f resource.hcl + +In resource.hcl, it could be: +ID { + Type = gvk("catalog.v2beta1.Service") + Name = "card-processor" + Tenancy { + Partition = "billing" + Namespace = "payments" + PeerName = "eu" + } +} +` diff --git a/command/resource/delete-grpc/delete_test.go b/command/resource/delete-grpc/delete_test.go new file mode 100644 index 0000000000..0bab59667a --- /dev/null +++ b/command/resource/delete-grpc/delete_test.go @@ -0,0 +1,164 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 +package delete + +import ( + "errors" + "fmt" + "testing" + + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/agent" + "github.com/hashicorp/consul/command/resource/apply-grpc" + "github.com/hashicorp/consul/sdk/freeport" + "github.com/hashicorp/consul/testrpc" +) + +func TestResourceDeleteInvalidArgs(t *testing.T) { + t.Parallel() + + type tc struct { + args []string + expectedCode int + expectedErr error + } + + cases := map[string]tc{ + "nil args": { + args: nil, + expectedCode: 1, + expectedErr: errors.New("Incorrect argument format: Must specify two arguments: resource type and resource name"), + }, + "empty args": { + args: []string{}, + expectedCode: 1, + expectedErr: errors.New("Incorrect argument format: Must specify two arguments: resource type and resource name"), + }, + "missing file path": { + args: []string{"-f"}, + expectedCode: 1, + expectedErr: errors.New("Failed to parse args: flag needs an argument: -f"), + }, + "file not found": { + args: []string{"-f=../testdata/test.hcl"}, + expectedCode: 1, + expectedErr: errors.New("Failed to load data: Failed to read file: open ../testdata/test.hcl: no such file or directory"), + }, + "provide type and name": { + args: []string{"a.b.c"}, + expectedCode: 1, + expectedErr: errors.New("Incorrect argument format: Must specify two arguments: resource type and resource name"), + }, + "provide type and name with -f": { + args: []string{"a.b.c", "name", "-f", "test.hcl"}, + expectedCode: 1, + expectedErr: errors.New("Incorrect argument format: File argument is not needed when resource information is provided with the command"), + }, + "provide type and name with -f and other flags": { + args: []string{"a.b.c", "name", "-f", "test.hcl", "-namespace", "default"}, + expectedCode: 1, + expectedErr: errors.New("Incorrect argument format: File argument is not needed when resource information is provided with the command"), + }, + "does not provide resource name after type": { + args: []string{"a.b.c", "-namespace", "default"}, + expectedCode: 1, + expectedErr: errors.New("Incorrect argument format: Must provide resource name right after type"), + }, + "invalid resource type format": { + args: []string{"a.", "name", "-namespace", "default"}, + expectedCode: 1, + expectedErr: errors.New("Must provide resource type argument with either in group.version.kind format or its shorthand name"), + }, + } + + for desc, tc := range cases { + t.Run(desc, func(t *testing.T) { + ui := cli.NewMockUi() + c := New(ui) + + code := c.Run(tc.args) + + require.Equal(t, tc.expectedCode, code) + require.Contains(t, ui.ErrorWriter.String(), tc.expectedErr.Error()) + }) + } +} + +func createResource(t *testing.T, port int) { + applyUi := cli.NewMockUi() + applyCmd := apply.New(applyUi) + + args := []string{ + fmt.Sprintf("-grpc-addr=127.0.0.1:%d", port), + "-token=root", + } + + args = append(args, []string{"-f=../testdata/demo.hcl"}...) + + code := applyCmd.Run(args) + require.Equal(t, 0, code) + require.Empty(t, applyUi.ErrorWriter.String()) +} + +func TestResourceDelete(t *testing.T) { + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + t.Parallel() + + availablePort := freeport.GetOne(t) + a := agent.NewTestAgent(t, fmt.Sprintf("ports { grpc = %d }", availablePort)) + testrpc.WaitForTestAgent(t, a.RPC, "dc1") + t.Cleanup(func() { + a.Shutdown() + }) + + defaultCmdArgs := []string{ + fmt.Sprintf("-grpc-addr=127.0.0.1:%d", availablePort), + "-token=root", + } + + cases := []struct { + name string + args []string + expectedCode int + createResource bool + }{ + { + name: "delete resource in hcl format", + args: []string{"-f=../testdata/demo.hcl"}, + expectedCode: 0, + createResource: true, + }, + { + name: "delete resource in command line format", + args: []string{"demo.v2.Artist", "korn", "-partition=default", "-namespace=default", "-peer=local"}, + expectedCode: 0, + createResource: true, + }, + { + name: "delete resource that doesn't exist in command line format", + args: []string{"demo.v2.Artist", "korn", "-partition=default", "-namespace=default", "-peer=local"}, + expectedCode: 0, + createResource: false, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + ui := cli.NewMockUi() + c := New(ui) + cliArgs := append(tc.args, defaultCmdArgs...) + if tc.createResource { + createResource(t, availablePort) + } + code := c.Run(cliArgs) + require.Empty(t, ui.ErrorWriter.String()) + require.Equal(t, tc.expectedCode, code) + require.Contains(t, ui.OutputWriter.String(), "deleted") + }) + } +} diff --git a/command/resource/delete/delete.go b/command/resource/delete/delete.go index a084f21d0f..43310d7e08 100644 --- a/command/resource/delete/delete.go +++ b/command/resource/delete/delete.go @@ -161,12 +161,12 @@ $ consul resource delete -f resource.hcl In resource.hcl, it could be: ID { - Type = gvk("catalog.v2beta1.Service") - Name = "card-processor" - Tenancy { - Namespace = "payments" - Partition = "billing" - PeerName = "eu" - } + Type = gvk("catalog.v2beta1.Service") + Name = "card-processor" + Tenancy { + Namespace = "payments" + Partition = "billing" + PeerName = "eu" + } } ` diff --git a/command/resource/delete/delete_test.go b/command/resource/delete/delete_test.go index 7454455c94..75926088ba 100644 --- a/command/resource/delete/delete_test.go +++ b/command/resource/delete/delete_test.go @@ -67,7 +67,7 @@ func TestResourceDeleteInvalidArgs(t *testing.T) { "invalid resource type format": { args: []string{"a.", "name", "-namespace", "default"}, expectedCode: 1, - expectedErr: errors.New("Must provide resource type argument with either in group.verion.kind format or its shorthand name"), + expectedErr: errors.New("Must provide resource type argument with either in group.version.kind format or its shorthand name"), }, } diff --git a/command/resource/helper.go b/command/resource/helper.go index 30a9956796..516b40cbb3 100644 --- a/command/resource/helper.go +++ b/command/resource/helper.go @@ -36,8 +36,8 @@ type OuterResource struct { } type Tenancy struct { - Namespace string `json:"namespace"` Partition string `json:"partition"` + Namespace string `json:"namespace"` PeerName string `json:"peerName"` } @@ -300,7 +300,7 @@ func InferTypeFromResourceType(resourceType string) (*pbresource.Type, error) { Kind: s[2], }, nil default: - return nil, fmt.Errorf("Must provide resource type argument with either in group.verion.kind format or its shorthand name") + return nil, fmt.Errorf("Must provide resource type argument with either in group.version.kind format or its shorthand name") } } diff --git a/command/resource/list-grpc/list.go b/command/resource/list-grpc/list.go index 49cffe7df3..cd91603cd8 100644 --- a/command/resource/list-grpc/list.go +++ b/command/resource/list-grpc/list.go @@ -106,8 +106,8 @@ func (c *cmd) Run(args []string) int { return 1 } resourceTenancy = &pbresource.Tenancy{ - Namespace: c.resourceFlags.Namespace(), Partition: c.resourceFlags.Partition(), + Namespace: c.resourceFlags.Namespace(), PeerName: c.resourceFlags.Peername(), } } @@ -185,8 +185,8 @@ Sample demo.hcl: ID { Type = gvk("group.version.kind") Tenancy { - Namespace = "default" Partition = "default" + Namespace = "default" PeerName = "local" } } diff --git a/command/resource/list-grpc/list_test.go b/command/resource/list-grpc/list_test.go index 81f4685fff..b52f17a6bb 100644 --- a/command/resource/list-grpc/list_test.go +++ b/command/resource/list-grpc/list_test.go @@ -54,9 +54,9 @@ func TestResourceListCommand(t *testing.T) { output: "\"name\": \"korn\"", extraArgs: []string{ "demo.v2.Artist", + "-partition=default", "-namespace=default", "-peer=local", - "-partition=default", }, }, { @@ -65,9 +65,9 @@ func TestResourceListCommand(t *testing.T) { extraArgs: []string{ "demo.v2.Artist", "-p=korn", + "-partition=default", "-namespace=default", "-peer=local", - "-partition=default", }, }, { @@ -150,9 +150,9 @@ func TestResourceListInvalidArgs(t *testing.T) { "file argument with resource type": { args: []string{ "demo.v2.Artist", + "-partition=default", "-namespace=default", "-peer=local", - "-partition=default", fmt.Sprintf("-grpc-addr=127.0.0.1:%d", availablePort), "-token=root", "-f=demo.hcl", @@ -163,9 +163,9 @@ func TestResourceListInvalidArgs(t *testing.T) { "resource type invalid": { args: []string{ "test", + "-partition=default", "-namespace=default", "-peer=local", - "-partition=default", }, expectedCode: 1, expectedErr: errors.New("Incorrect argument format: The shorthand name does not map to any existing resource type"), diff --git a/command/resource/list/list.go b/command/resource/list/list.go index d0a5f398a6..f7eab97977 100644 --- a/command/resource/list/list.go +++ b/command/resource/list/list.go @@ -151,7 +151,7 @@ func getResourceType(args []string) (gvk *resource.GVK, e error) { s := strings.Split(args[0], ".") if len(s) < 3 { - return nil, fmt.Errorf("Must include resource type argument in group.verion.kind format") + return nil, fmt.Errorf("Must include resource type argument in group.version.kind format") } gvk = &resource.GVK{ Group: s[0], diff --git a/command/resource/list/list_test.go b/command/resource/list/list_test.go index b8fc12556a..3cec8d609f 100644 --- a/command/resource/list/list_test.go +++ b/command/resource/list/list_test.go @@ -7,13 +7,14 @@ import ( "errors" "testing" + "github.com/mitchellh/cli" + "github.com/hashicorp/consul/agent" "github.com/hashicorp/consul/testrpc" - "github.com/mitchellh/cli" "github.com/stretchr/testify/require" - apply "github.com/hashicorp/consul/command/resource/apply" + "github.com/hashicorp/consul/command/resource/apply" ) func TestResourceListCommand(t *testing.T) { @@ -148,7 +149,7 @@ func TestResourceListInvalidArgs(t *testing.T) { "-partition=default", }, expectedCode: 1, - expectedErr: errors.New("Must include resource type argument in group.verion.kind format"), + expectedErr: errors.New("Must include resource type argument in group.version.kind format"), }, "resource name is provided": { args: []string{ diff --git a/command/resource/read-grpc/read.go b/command/resource/read-grpc/read.go index e73e62ec92..a3d9a6ff93 100644 --- a/command/resource/read-grpc/read.go +++ b/command/resource/read-grpc/read.go @@ -98,8 +98,8 @@ func (c *cmd) Run(args []string) int { return 1 } resourceTenancy = &pbresource.Tenancy{ - Namespace: c.resourceFlags.Namespace(), Partition: c.resourceFlags.Partition(), + Namespace: c.resourceFlags.Namespace(), PeerName: c.resourceFlags.Peername(), } } @@ -164,8 +164,8 @@ ID { Type = gvk("catalog.v2beta1.Service") Name = "card-processor" Tenancy { - Namespace = "payments" Partition = "billing" + Namespace = "payments" PeerName = "eu" } } diff --git a/command/resource/read-grpc/read_test.go b/command/resource/read-grpc/read_test.go index a6858af659..4748f33d9e 100644 --- a/command/resource/read-grpc/read_test.go +++ b/command/resource/read-grpc/read_test.go @@ -69,7 +69,7 @@ func TestResourceReadInvalidArgs(t *testing.T) { "invalid resource type format": { args: []string{"a.", "name", "-namespace", "default"}, expectedCode: 1, - expectedErr: errors.New("Incorrect argument format: Must provide resource type argument with either in group.verion.kind format or its shorthand name"), + expectedErr: errors.New("Incorrect argument format: Must provide resource type argument with either in group.version.kind format or its shorthand name"), }, } diff --git a/command/resource/read/read_test.go b/command/resource/read/read_test.go index 5c5e854e8d..7eea7b836b 100644 --- a/command/resource/read/read_test.go +++ b/command/resource/read/read_test.go @@ -67,7 +67,7 @@ func TestResourceReadInvalidArgs(t *testing.T) { "invalid resource type format": { args: []string{"a.", "name", "-namespace", "default"}, expectedCode: 1, - expectedErr: errors.New("Incorrect argument format: Must provide resource type argument with either in group.verion.kind format or its shorthand name"), + expectedErr: errors.New("Incorrect argument format: Must provide resource type argument with either in group.version.kind format or its shorthand name"), }, } diff --git a/command/resource/resource-grpc.go b/command/resource/resource-grpc.go index 87eca41db2..94d7314597 100644 --- a/command/resource/resource-grpc.go +++ b/command/resource/resource-grpc.go @@ -95,3 +95,29 @@ func (resource *ResourceGRPC) List(resourceType *pbresource.Type, resourceTenanc return listRsp.Resources, err } + +func (resource *ResourceGRPC) Delete(resourceType *pbresource.Type, resourceTenancy *pbresource.Tenancy, resourceName string) error { + token, err := resource.C.Config.GetToken() + if err != nil { + return err + } + ctx := context.Background() + if token != "" { + ctx = metadata.AppendToOutgoingContext(context.Background(), HeaderConsulToken, token) + } + + defer resource.C.Conn.Close() + _, err = resource.C.Client.Delete(ctx, &pbresource.DeleteRequest{ + Id: &pbresource.ID{ + Type: resourceType, + Tenancy: resourceTenancy, + Name: resourceName, + }, + }) + + if err != nil { + return fmt.Errorf("error deleting resource: %+v", err) + } + + return nil +} diff --git a/command/resource/testdata/demo.hcl b/command/resource/testdata/demo.hcl index 35e72aba31..8185a541db 100644 --- a/command/resource/testdata/demo.hcl +++ b/command/resource/testdata/demo.hcl @@ -5,8 +5,8 @@ ID { Type = gvk("demo.v2.Artist") Name = "korn" Tenancy { - Namespace = "default" Partition = "default" + Namespace = "default" PeerName = "local" } } diff --git a/command/resource/testdata/invalid.hcl b/command/resource/testdata/invalid.hcl index 04c08e9212..bb97cf59f8 100644 --- a/command/resource/testdata/invalid.hcl +++ b/command/resource/testdata/invalid.hcl @@ -5,8 +5,8 @@ ID { Type = gvk("demo.v2.Artist") Name = "korn" Tenancy { - Namespace = "default" Partition = "default" + Namespace = "default" PeerName = "local" } } diff --git a/command/resource/testdata/invalid_type.hcl b/command/resource/testdata/invalid_type.hcl index b3b87ae245..7b7761a40a 100644 --- a/command/resource/testdata/invalid_type.hcl +++ b/command/resource/testdata/invalid_type.hcl @@ -4,8 +4,8 @@ D { Type = gvk("demo.v2.Artist") Tenancy { - Namespace = "default" Partition = "default" + Namespace = "default" PeerName = "local" } } diff --git a/website/content/docs/connect/config-entries/proxy-defaults.mdx b/website/content/docs/connect/config-entries/proxy-defaults.mdx index 1c57141459..90ffb4eaa4 100644 --- a/website/content/docs/connect/config-entries/proxy-defaults.mdx +++ b/website/content/docs/connect/config-entries/proxy-defaults.mdx @@ -27,7 +27,7 @@ The following list outlines field hierarchy, language-specific data types, and r - [`Name`](#name): string | must be set to `global` - [`Namespace`](#namespace): string | `default` | - [`Partition`](#partition): string | `default` | -- [`Meta`](#meta): map +- [`Meta`](#meta): map - [`Config`](#meta): map - [`EnvoyExtensions`](#envoyextensions): list of maps - [`Name`](#envoyextensions): string @@ -39,16 +39,16 @@ The following list outlines field hierarchy, language-specific data types, and r - [`TransparentProxy`](#transparentproxy): map - [`OutboundListenerPort`](#transparentproxy): number | `15001` - [`DialedDirectly`](#transparentproxy): boolean | `false` -- [`MutualTLSMode`](#mutualtlsmode): string +- [`MutualTLSMode`](#mutualtlsmode): string - [`MeshGateway`](#meshgateway): map - [`Mode`](#meshgateway): string - [`Expose`](#expose): map - [`Checks`](#expose-checks): boolean | `false` - [`Paths`](#expose-paths): list of maps - - [`Path`](#expose-paths-path): string | must begin with `/` - - [`LocalPathPort`](#expose-paths): number | `0` - - [`ListenerPort`](#expose-paths): number | `0` - - [`Protocol`](#expose-paths): string | `http` + - [`Path`](#expose-paths-path): string | must begin with `/` + - [`LocalPathPort`](#expose-paths): number | `0` + - [`ListenerPort`](#expose-paths): number | `0` + - [`Protocol`](#expose-paths): string | `http` - [`PrioritizeByLocality`](#prioritizebylocality): map | - [`Mode`](#prioritizebylocality): string | `failover` - [`AccessLogs`](#accesslogs): map @@ -56,8 +56,8 @@ The following list outlines field hierarchy, language-specific data types, and r - [`DisableListenerLogs`](#accesslogs): boolean | `false` - [`Type`](#accesslogs): string | `stdout` - [`Path`](#accesslogs): string - - [`JSONFormat`](#accesslogs): string - - [`TextFormat`](#accesslogs): string + - [`JSONFormat`](#accesslogs): string + - [`TextFormat`](#accesslogs): string @@ -79,16 +79,16 @@ The following list outlines field hierarchy, language-specific data types, and r - [`transparentProxy`](#spec-transparentproxy): map - [`outboundListenerPort`](#spec-transparentproxy): number | `15001` - [`dialedDirectly`](#spec-transparentproxy): boolean | `false` - - [`mutualTLSMode`](#spec-mutualtlsmode): string + - [`mutualTLSMode`](#spec-mutualtlsmode): string - [`meshGateway`](#spec-meshgateway): map - [`mode`](#spec-meshgateway): string - [`expose`](#spec-expose): map - [`checks`](#spec-expose-checks): boolean | `false` - [`paths`](#spec-expose-paths): list - - [`path`](#spec-expose-paths): string | must begin with `/` - - [`localPathPort`](#spec-expose-paths): number | `0` - - [`listenerPort`](#spec-expose-paths): number | `0` - - [`protocol`](#spec-expose-paths): string | `http` + - [`path`](#spec-expose-paths): string | must begin with `/` + - [`localPathPort`](#spec-expose-paths): number | `0` + - [`listenerPort`](#spec-expose-paths): number | `0` + - [`protocol`](#spec-expose-paths): string | `http` - [`prioritizeByLocality`](#prioritizebylocality): map | - [`mode`](#prioritizebylocality): string | `failover` - [`accessLogs`](#spec-accesslogs): map @@ -96,8 +96,8 @@ The following list outlines field hierarchy, language-specific data types, and r - [`disableListenerLogs`](#spec-accesslogs): boolean | `false` - [`type`](#spec-accesslogs): string | `stdout` - [`path`](#spec-accesslogs): string - - [`jsonFormat`](#spec-accesslogs): string - - [`textFormat`](#spec-accesslogs): string + - [`jsonFormat`](#spec-accesslogs): string + - [`textFormat`](#spec-accesslogs): string @@ -121,15 +121,15 @@ Meta { Config { = } -EnvoyExtensions = [ - { +EnvoyExtensions = [ + { Name= "" Required = "required" Arguments = "" ConsulVersion = "" EnvoyVersion = "" } -] +] Mode = "" TransparentProxy { OutboundListenerPort = @@ -183,7 +183,7 @@ spec: required: required arguments: consulVersion: - envoyVersion: + envoyVersion: mode: transparentProxy: outboundListenerPort: @@ -296,7 +296,7 @@ Specifies a name for the configuration entry that is used to identify the config ### `Namespace` -Specifies the namespace that the proxy defaults apply to. You can only specify the `default` namespace. +Specifies the namespace that the proxy defaults apply to. You can only specify the `default` namespace. #### Values @@ -314,7 +314,7 @@ Specifies the local admin partition that the proxy defaults apply to. Refer to [ ### `Meta` -Specifies a set of custom key-value pairs to add the [Consul KV](#/consul/docs/dynamic-app-config/kv) store. +Specifies a set of custom key-value pairs to add the [Consul KV](#/consul/docs/dynamic-app-config/kv) store. #### Values @@ -328,7 +328,7 @@ Specifies a set of custom key-value pairs to add the [Consul KV](#/consul/docs/d Specifies an arbitrary map of configuration values used by service mesh proxies. The available configurations depend on the mesh proxy you use. You can configure any global values that your proxy allows in this field. Refer to the following topics for additional information: - [Envoy proxy configuration option](/consul/docs/connect/proxies/envoy#proxy-config-options) -- [Built-in proxy configuration options](/consul/docs/connect/proxies/built-in#proxy-config-key-reference) +- [Built-in proxy configuration options](/consul/docs/connect/proxies/built-in#proxy-config-key-reference) #### Values @@ -363,18 +363,18 @@ The following table describes how to configure values in the `EnvoyExtensions` m Specifies a mode for how proxies direct inbound and outbound traffic. You can specify one of the following values: -- `transparent`: In transparent mode, proxies capture and redirect inbound and outbound traffic. The mode does not enable traffic redirection, but directs Consul to configure Envoy as if traffic is already being redirected. +- `transparent`: In transparent mode, proxies capture and redirect inbound and outbound traffic. The mode does not enable traffic redirection, but directs Consul to configure Envoy as if traffic is already being redirected. -- `direct`: In this mode, the local application and other proxies must directly dial proxy listeners. +- `direct`: In this mode, the local application and other proxies must directly dial proxy listeners. #### Values - Default: None -- Data type: String +- Data type: String ### `TransparentProxy` -Contains configurations for proxies that are running in transparent proxy mode. This mode enables permissive mTLS for Consul so that you can use your Kubernetes cluster's DNS service instead of Consul DNS. Refer to [Transparent proxy mode](/consul/docs/k8s/connect/transparent-proxy) for additional information. +Contains configurations for proxies that are running in transparent proxy mode. This mode enables permissive mTLS for Consul so that you can use your Kubernetes cluster's DNS service instead of Consul DNS. Refer to [Transparent proxy mode](/consul/docs/k8s/connect/transparent-proxy) for additional information. #### Values @@ -392,11 +392,11 @@ The following table describes how to configure values in the `TransparentProxy` ### `MutualTLSMode` -Controls the default mutual TLS (mTLS) mode for all proxies. You can only set mutual TLS mode for services in transparent proxy mode. +Controls the default mutual TLS (mTLS) mode for all proxies. You can only set mutual TLS mode for services in transparent proxy mode. You can specify one of the following modes: -`strict`: The sidecar proxy requires mTLS for incoming traffic. +`strict`: The sidecar proxy requires mTLS for incoming traffic. `permissive`: The sidecar proxy accepts mTLS traffic on the sidecar proxy service port and accepts any traffic on the destination service port. We recommend only using permissive mode if necessary while onboarding services to the service mesh. #### Values @@ -421,7 +421,7 @@ Sets the default mesh gateway `mode` field for all proxies. You can specify the ### `Expose` -Specifies default configurations for exposing HTTP paths through Envoy. Exposing paths through Envoy enables services to protect themselves by only listening on `localhost`. Applications that are not Consul service mesh-enabled are still able to contact an HTTP endpoint. +Specifies default configurations for exposing HTTP paths through Envoy. Exposing paths through Envoy enables services to protect themselves by only listening on `localhost`. Applications that are not Consul service mesh-enabled are still able to contact an HTTP endpoint. Example use-cases include exposing the `/metrics` endpoint to a monitoring system, such as Prometheus, and exposing the `/healthz` endpoint to the kubelet for liveness checks. Refer to [Expose Paths Configuration Reference](/consul/docs/connect/proxy-config-reference#expose-paths-configuration-reference) for additional information. @@ -445,12 +445,12 @@ We recommend enabling the `Checks` configuration when a Consul client cannot rea ### `Expose{}.Paths[]` -Specifies a list of configuration maps that define paths to expose through Envoy when `Expose.Checks` is set to `true`. +Specifies a list of configuration maps that define paths to expose through Envoy when `Expose.Checks` is set to `true`. #### Values - Default: None -- Data type: List of maps +- Data type: List of maps The following table describes the parameters for each map you can define in the list: @@ -461,7 +461,7 @@ The following table describes the parameters for each map you can define in the | `ListenPort` | Specifies the port where the proxy listens for connections. The port must be available. If the port is unavailable, Envoy does not expose a listener for the path and the proxy registration still succeeds. | Integer | `0` | | `Protocol` | Specifies the protocol of the listener. You can configure one of the following values:
  • `http`
  • `http2`: Use with gRPC traffic
  • | String | `http` | -### `PrioritizeByLocality` +### `PrioritizeByLocality` Sets a mode for the service that allows instances to prioritize upstream targets that are in the same network region and zone. You can specify the following string values for the `mode` field: @@ -479,7 +479,7 @@ Specifies [Envoy access logger](https://www.envoyproxy.io/docs/envoy/latest/intr #### Values - Default: None -- Data type: Map +- Data type: Map The following table describes the parameters you can define in the `AccessLogs` map: @@ -498,7 +498,7 @@ The following table describes the parameters you can define in the `AccessLogs` ### apiVersion -Specifies the verion of the Consul API to use to apply the configuration entry. This must be set to `consul.hashicorp.com/v1alpha1`. +Specifies the version of the Consul API to use to apply the configuration entry. This must be set to `consul.hashicorp.com/v1alpha1`. #### Values @@ -557,12 +557,12 @@ Map that contains the details about the ProxyDefaults configuration entry. The ` Specifies an arbitrary map of configuration values used by service mesh proxies. The available configurations depend on the mesh proxy you use. You can configure any global values that your proxy allows in this field. Refer to the following topics for additional information: - [Envoy proxy configuration option](/consul/docs/connect/proxies/envoy#proxy-config-options) -- [Built-in proxy configuration options](/consul/docs/connect/proxies/built-in#proxy-config-key-reference) +- [Built-in proxy configuration options](/consul/docs/connect/proxies/built-in#proxy-config-key-reference) #### Values - Default: None -- Data type: Map +- Data type: Map ### `spec.envoyExtensions` @@ -592,18 +592,18 @@ The following table describes how to configure values in the `EnvoyExtensions` m Specifies a mode for how proxies direct inbound and outbound traffic. You can specify one of the following values: -- `transparent`: In transparent mode, proxies capture and redirect inbound and outbound traffic. The mode does not enable traffic redirection, but directs Consul to configure Envoy as if traffic is already being redirected. +- `transparent`: In transparent mode, proxies capture and redirect inbound and outbound traffic. The mode does not enable traffic redirection, but directs Consul to configure Envoy as if traffic is already being redirected. -- `direct`: In this mode, the local application and other proxies must directly dial proxy listeners. +- `direct`: In this mode, the local application and other proxies must directly dial proxy listeners. #### Values - Default: None -- Data type: String +- Data type: String ### `spec.transparentProxy` -Contains configurations for proxies that are running in transparent proxy mode. This mode enables permissive mTLS for Consul so that you can use your Kubernetes cluster's DNS service instead of Consul DNS. Refer to [Transparent proxy mode](/consul/docs/k8s/connect/transparent-proxy) for additional information. +Contains configurations for proxies that are running in transparent proxy mode. This mode enables permissive mTLS for Consul so that you can use your Kubernetes cluster's DNS service instead of Consul DNS. Refer to [Transparent proxy mode](/consul/docs/k8s/connect/transparent-proxy) for additional information. #### Values @@ -621,11 +621,11 @@ The following table describes how to configure values in the `TransparentProxy` ### `spec.mutualTLSMode` -Controls the default mutual TLS (mTLS) mode for all proxies. You can only set mutual TLS mode for services in transparent proxy mode. +Controls the default mutual TLS (mTLS) mode for all proxies. You can only set mutual TLS mode for services in transparent proxy mode. You can specify one of the following modes: -`strict`: The sidecar proxy requires mTLS for incoming traffic. +`strict`: The sidecar proxy requires mTLS for incoming traffic. `permissive`: The sidecar proxy accepts mTLS traffic on the sidecar proxy service port and accepts any traffic on the destination service port. We recommend only using permissive mode if necessary while onboarding services to the service mesh. #### Values @@ -650,7 +650,7 @@ Sets the default mesh gateway `mode` field for all proxies. You can specify the ### `spec.expose` -Specifies default configurations for exposing HTTP paths through Envoy. Exposing paths through Envoy enables services to protect themselves by only listening on `localhost`. Applications that are not Consul service mesh-enabled are still able to contact an HTTP endpoint. +Specifies default configurations for exposing HTTP paths through Envoy. Exposing paths through Envoy enables services to protect themselves by only listening on `localhost`. Applications that are not Consul service mesh-enabled are still able to contact an HTTP endpoint. Example use-cases include exposing the `/metrics` endpoint to a monitoring system, such as Prometheus, and exposing the `/healthz` endpoint to the kubelet for liveness checks. Refer to [Expose Paths Configuration Reference](/consul/docs/connect/proxy-config-reference#expose-paths-configuration-reference) for additional information. @@ -674,12 +674,12 @@ We recommend enabling the `Checks` configuration when a Consul client cannot rea ### `spec.expose{}.paths[]` -Specifies a list of configuration maps that define paths to expose through Envoy when `spec.expose.checks` is set to `true`. +Specifies a list of configuration maps that define paths to expose through Envoy when `spec.expose.checks` is set to `true`. #### Values - Default: None -- Data type: List of maps. +- Data type: List of maps. The following table describes the parameters for each map you can define in the list: @@ -708,7 +708,7 @@ Specifies [Envoy access logger](https://www.envoyproxy.io/docs/envoy/latest/intr #### Values - Default: None -- Data type: Map +- Data type: Map The following table describes the parameters you can define in the `accessLogs` map: