mirror of https://github.com/status-im/consul.git
parent
6828780131
commit
7bb2c7cf13
|
@ -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 && \
|
||||
|
|
|
@ -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 }},
|
||||
|
|
|
@ -134,8 +134,8 @@ Usage: consul resource apply [options] <resource>
|
|||
Type = gvk("group.version.kind")
|
||||
Name = "resource-name"
|
||||
Tenancy {
|
||||
Namespace = "default"
|
||||
Partition = "default"
|
||||
Namespace = "default"
|
||||
PeerName = "local"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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=<default> -namespace=<default> -peer=<local>
|
||||
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"
|
||||
}
|
||||
}
|
||||
`
|
|
@ -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")
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -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"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ ID {
|
|||
Type = gvk("demo.v2.Artist")
|
||||
Name = "korn"
|
||||
Tenancy {
|
||||
Namespace = "default"
|
||||
Partition = "default"
|
||||
Namespace = "default"
|
||||
PeerName = "local"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ ID {
|
|||
Type = gvk("demo.v2.Artist")
|
||||
Name = "korn"
|
||||
Tenancy {
|
||||
Namespace = "default"
|
||||
Partition = "default"
|
||||
Namespace = "default"
|
||||
PeerName = "local"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
D {
|
||||
Type = gvk("demo.v2.Artist")
|
||||
Tenancy {
|
||||
Namespace = "default"
|
||||
Partition = "default"
|
||||
Namespace = "default"
|
||||
PeerName = "local"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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` | <EnterpriseAlert inline/>
|
||||
- [`Partition`](#partition): string | `default` | <EnterpriseAlert inline/>
|
||||
- [`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 | <EnterpriseAlert inline/>
|
||||
- [`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
|
||||
|
||||
</Tab>
|
||||
<Tab heading="YAML" group="yaml">
|
||||
|
@ -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 | <EnterpriseAlert inline/>
|
||||
- [`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
|
||||
|
||||
</Tab>
|
||||
|
||||
|
@ -121,15 +121,15 @@ Meta {
|
|||
Config {
|
||||
<arbitrary string key> = <arbitrary value>
|
||||
}
|
||||
EnvoyExtensions = [
|
||||
{
|
||||
EnvoyExtensions = [
|
||||
{
|
||||
Name= "<name of the extension>"
|
||||
Required = "required"
|
||||
Arguments = "<arguments to pass to the extension>"
|
||||
ConsulVersion = "<Consul version required by the extension>"
|
||||
EnvoyVersion = "<Envoy version required by the extension>"
|
||||
}
|
||||
]
|
||||
]
|
||||
Mode = "<name of proxy mode>"
|
||||
TransparentProxy {
|
||||
OutboundListenerPort = <port the proxy should listen on for outbound traffic>
|
||||
|
@ -183,7 +183,7 @@ spec:
|
|||
required: required
|
||||
arguments: <arguments to pass to the extension>
|
||||
consulVersion: <Consul version required by the extension>
|
||||
envoyVersion: <Envoy version required by the extension>
|
||||
envoyVersion: <Envoy version required by the extension>
|
||||
mode: <name of proxy mode>
|
||||
transparentProxy:
|
||||
outboundListenerPort: <port the proxy should listen on for outbound traffic>
|
||||
|
@ -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: <li>`http`</li><li>`http2`: Use with gRPC traffic</li> | 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:
|
||||
|
||||
|
|
Loading…
Reference in New Issue