From dba937847fd38937f4a874dff8043a9fa73983a8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 11 May 2018 22:28:59 -0700 Subject: [PATCH] command/intention/create: -replace flag, jank, we should change to PUT --- command/intention/create/create.go | 32 ++++++++++++- command/intention/create/create_test.go | 63 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/command/intention/create/create.go b/command/intention/create/create.go index b847117a15..dd5f615656 100644 --- a/command/intention/create/create.go +++ b/command/intention/create/create.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/command/flags" + "github.com/hashicorp/consul/command/intention/finder" "github.com/mitchellh/cli" ) @@ -44,7 +45,8 @@ func (c *cmd) init() { c.flags.BoolVar(&c.flagFile, "file", false, "Read intention data from one or more files.") c.flags.BoolVar(&c.flagReplace, "replace", false, - "Replace matching intentions.") + "Replace matching intentions. This is not an atomic operation. "+ + "If the insert fails, then the previous intention will still be deleted.") c.flags.Var((*flags.FlagMapValue)(&c.flagMeta), "meta", "Metadata to set on the intention, formatted as key=value. This flag "+ "may be specified multiple times to set multiple meta fields.") @@ -86,8 +88,36 @@ func (c *cmd) Run(args []string) int { return 1 } + // Create the finder in case we need it + find := &finder.Finder{Client: client} + // Go through and create each intention for _, ixn := range ixns { + // If replace is set to true, then find this intention and delete it. + if c.flagReplace { + ixn, err := find.Find(ixn.SourceString(), ixn.DestinationString()) + if err != nil { + c.UI.Error(fmt.Sprintf( + "Error looking up intention for replacement with source %q "+ + "and destination %q: %s", + ixn.SourceString(), + ixn.DestinationString(), + err)) + return 1 + } + if ixn != nil { + if _, err := client.Connect().IntentionDelete(ixn.ID, nil); err != nil { + c.UI.Error(fmt.Sprintf( + "Error deleting intention for replacement with source %q "+ + "and destination %q: %s", + ixn.SourceString(), + ixn.DestinationString(), + err)) + return 1 + } + } + } + _, _, err := client.Connect().IntentionCreate(ixn, nil) if err != nil { c.UI.Error(fmt.Sprintf("Error creating intention %q: %s", ixn, err)) diff --git a/command/intention/create/create_test.go b/command/intention/create/create_test.go index 963a3edc6c..067d0d6a93 100644 --- a/command/intention/create/create_test.go +++ b/command/intention/create/create_test.go @@ -186,3 +186,66 @@ func TestCommand_FileNoExist(t *testing.T) { require.Equal(1, c.Run(args), ui.ErrorWriter.String()) require.Contains(ui.ErrorWriter.String(), "no such file") } + +func TestCommand_replace(t *testing.T) { + t.Parallel() + + require := require.New(t) + a := agent.NewTestAgent(t.Name(), ``) + defer a.Shutdown() + client := a.Client() + + // Create the first + { + ui := cli.NewMockUi() + c := New(ui) + + args := []string{ + "-http-addr=" + a.HTTPAddr(), + "foo", "bar", + } + require.Equal(0, c.Run(args), ui.ErrorWriter.String()) + + ixns, _, err := client.Connect().Intentions(nil) + require.NoError(err) + require.Len(ixns, 1) + require.Equal("foo", ixns[0].SourceName) + require.Equal("bar", ixns[0].DestinationName) + require.Equal(api.IntentionActionAllow, ixns[0].Action) + } + + // Don't replace, should be an error + { + ui := cli.NewMockUi() + c := New(ui) + + args := []string{ + "-http-addr=" + a.HTTPAddr(), + "-deny", + "foo", "bar", + } + require.Equal(1, c.Run(args), ui.ErrorWriter.String()) + require.Contains(ui.ErrorWriter.String(), "duplicate") + } + + // Replace it + { + ui := cli.NewMockUi() + c := New(ui) + + args := []string{ + "-http-addr=" + a.HTTPAddr(), + "-replace", + "-deny", + "foo", "bar", + } + require.Equal(0, c.Run(args), ui.ErrorWriter.String()) + + ixns, _, err := client.Connect().Intentions(nil) + require.NoError(err) + require.Len(ixns, 1) + require.Equal("foo", ixns[0].SourceName) + require.Equal("bar", ixns[0].DestinationName) + require.Equal(api.IntentionActionDeny, ixns[0].Action) + } +}