Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cli): add initial peering cli commands
- Loading branch information
Showing
25 changed files
with
1,780 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:feature | ||
cli: Adds new subcommands for `peering` workflows. Refer to the [CLI docs](https://www.consul.io/commands/peering) for more information. | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package delete | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
|
||
"github.com/mitchellh/cli" | ||
|
||
"github.com/hashicorp/consul/api" | ||
"github.com/hashicorp/consul/command/flags" | ||
) | ||
|
||
func New(ui cli.Ui) *cmd { | ||
c := &cmd{UI: ui} | ||
c.init() | ||
return c | ||
} | ||
|
||
type cmd struct { | ||
UI cli.Ui | ||
flags *flag.FlagSet | ||
http *flags.HTTPFlags | ||
help string | ||
|
||
name string | ||
} | ||
|
||
func (c *cmd) init() { | ||
c.flags = flag.NewFlagSet("", flag.ContinueOnError) | ||
|
||
c.flags.StringVar(&c.name, "name", "", "(Required) The local name assigned to the peer cluster.") | ||
|
||
c.http = &flags.HTTPFlags{} | ||
flags.Merge(c.flags, c.http.ClientFlags()) | ||
flags.Merge(c.flags, c.http.PartitionFlag()) | ||
c.help = flags.Usage(help, c.flags) | ||
} | ||
|
||
func (c *cmd) Run(args []string) int { | ||
if err := c.flags.Parse(args); err != nil { | ||
return 1 | ||
} | ||
|
||
if c.name == "" { | ||
c.UI.Error("Missing the required -name flag") | ||
return 1 | ||
} | ||
|
||
client, err := c.http.APIClient() | ||
if err != nil { | ||
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) | ||
return 1 | ||
} | ||
|
||
peerings := client.Peerings() | ||
|
||
_, err = peerings.Delete(context.Background(), c.name, &api.WriteOptions{}) | ||
if err != nil { | ||
c.UI.Error(fmt.Sprintf("Error deleting peering for %s: %v", c.name, err)) | ||
return 1 | ||
} | ||
|
||
c.UI.Info(fmt.Sprintf("Successfully submitted peering connection, %s, for deletion", c.name)) | ||
return 0 | ||
} | ||
|
||
func (c *cmd) Synopsis() string { | ||
return synopsis | ||
} | ||
|
||
func (c *cmd) Help() string { | ||
return flags.Usage(c.help, nil) | ||
} | ||
|
||
const ( | ||
synopsis = "Delete a peering connection" | ||
help = ` | ||
Usage: consul peering delete [options] -name <peer name> | ||
Delete a peering connection. Consul deletes all data imported from the peer | ||
in the background. The peering connection is removed after all associated | ||
data has been deleted. Operators can still read the peering connections | ||
while the data is being removed. A 'DeletedAt' field will be populated with | ||
the timestamp of when the peering was marked for deletion. | ||
Example: | ||
$ consul peering delete -name west-dc | ||
` | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package delete | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/mitchellh/cli" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/hashicorp/consul/agent" | ||
"github.com/hashicorp/consul/api" | ||
"github.com/hashicorp/consul/testrpc" | ||
) | ||
|
||
func TestDeleteCommand_noTabs(t *testing.T) { | ||
t.Parallel() | ||
|
||
if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') { | ||
t.Fatal("help has tabs") | ||
} | ||
} | ||
|
||
func TestDeleteCommand(t *testing.T) { | ||
if testing.Short() { | ||
t.Skip("too slow for testing.Short") | ||
} | ||
|
||
t.Parallel() | ||
|
||
acceptor := agent.NewTestAgent(t, ``) | ||
t.Cleanup(func() { _ = acceptor.Shutdown() }) | ||
|
||
testrpc.WaitForTestAgent(t, acceptor.RPC, "dc1") | ||
|
||
acceptingClient := acceptor.Client() | ||
|
||
t.Run("name is required", func(t *testing.T) { | ||
ui := cli.NewMockUi() | ||
cmd := New(ui) | ||
|
||
args := []string{ | ||
"-http-addr=" + acceptor.HTTPAddr(), | ||
} | ||
|
||
code := cmd.Run(args) | ||
require.Equal(t, 1, code, "err: %s", ui.ErrorWriter.String()) | ||
require.Contains(t, ui.ErrorWriter.String(), "Missing the required -name flag") | ||
}) | ||
|
||
t.Run("delete connection", func(t *testing.T) { | ||
|
||
req := api.PeeringGenerateTokenRequest{PeerName: "foo"} | ||
_, _, err := acceptingClient.Peerings().GenerateToken(context.Background(), req, &api.WriteOptions{}) | ||
require.NoError(t, err, "Could not generate peering token at acceptor") | ||
|
||
ui := cli.NewMockUi() | ||
cmd := New(ui) | ||
|
||
args := []string{ | ||
"-http-addr=" + acceptor.HTTPAddr(), | ||
"-name=foo", | ||
} | ||
|
||
code := cmd.Run(args) | ||
require.Equal(t, 0, code) | ||
output := ui.OutputWriter.String() | ||
require.Contains(t, output, "Success") | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package establish | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
|
||
"github.com/mitchellh/cli" | ||
|
||
"github.com/hashicorp/consul/api" | ||
"github.com/hashicorp/consul/command/flags" | ||
) | ||
|
||
func New(ui cli.Ui) *cmd { | ||
c := &cmd{UI: ui} | ||
c.init() | ||
return c | ||
} | ||
|
||
type cmd struct { | ||
UI cli.Ui | ||
flags *flag.FlagSet | ||
http *flags.HTTPFlags | ||
help string | ||
|
||
name string | ||
peeringToken string | ||
meta map[string]string | ||
} | ||
|
||
func (c *cmd) init() { | ||
c.flags = flag.NewFlagSet("", flag.ContinueOnError) | ||
|
||
c.flags.StringVar(&c.name, "name", "", "(Required) The local name assigned to the peer cluster.") | ||
|
||
c.flags.StringVar(&c.peeringToken, "peering-token", "", "(Required) The peering token from the accepting cluster.") | ||
|
||
c.flags.Var((*flags.FlagMapValue)(&c.meta), "meta", | ||
"Metadata to associate with the peering, formatted as key=value. This flag "+ | ||
"may be specified multiple times to set multiple meta fields.") | ||
|
||
c.http = &flags.HTTPFlags{} | ||
flags.Merge(c.flags, c.http.ClientFlags()) | ||
flags.Merge(c.flags, c.http.PartitionFlag()) | ||
c.help = flags.Usage(help, c.flags) | ||
} | ||
|
||
func (c *cmd) Run(args []string) int { | ||
if err := c.flags.Parse(args); err != nil { | ||
return 1 | ||
} | ||
|
||
if c.name == "" { | ||
c.UI.Error("Missing the required -name flag") | ||
return 1 | ||
} | ||
|
||
if c.peeringToken == "" { | ||
c.UI.Error("Missing the required -peering-token flag") | ||
return 1 | ||
} | ||
|
||
client, err := c.http.APIClient() | ||
if err != nil { | ||
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) | ||
return 1 | ||
} | ||
|
||
peerings := client.Peerings() | ||
|
||
req := api.PeeringEstablishRequest{ | ||
PeerName: c.name, | ||
PeeringToken: c.peeringToken, | ||
Partition: c.http.Partition(), | ||
Meta: c.meta, | ||
} | ||
|
||
_, _, err = peerings.Establish(context.Background(), req, &api.WriteOptions{}) | ||
if err != nil { | ||
c.UI.Error(fmt.Sprintf("Error establishing peering for %s: %v", req.PeerName, err)) | ||
return 1 | ||
} | ||
|
||
c.UI.Info(fmt.Sprintf("Successfully established peering connection with %s", req.PeerName)) | ||
return 0 | ||
} | ||
|
||
func (c *cmd) Synopsis() string { | ||
return synopsis | ||
} | ||
|
||
func (c *cmd) Help() string { | ||
return flags.Usage(c.help, nil) | ||
} | ||
|
||
const ( | ||
synopsis = "Establish a peering connection" | ||
help = ` | ||
Usage: consul peering establish [options] -name <peer name> -peering-token <token> | ||
Establish a peering connection. The name provided will be used locally by | ||
this cluster to refer to the peering connection. The peering token can | ||
only be used once to establish the connection. | ||
Example: | ||
$ consul peering establish -name west-dc -peering-token <token> | ||
` | ||
) |
Oops, something went wrong.