From 2f97a618dce714f4a09af892c7073d8467b2baff Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 1 Oct 2018 08:39:27 -0700 Subject: [PATCH] command/services/deregister: basics working from file --- command/services/deregister/deregister.go | 102 ++++++++++++++++ .../services/deregister/deregister_test.go | 115 ++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 command/services/deregister/deregister.go create mode 100644 command/services/deregister/deregister_test.go diff --git a/command/services/deregister/deregister.go b/command/services/deregister/deregister.go new file mode 100644 index 0000000000..eac269d623 --- /dev/null +++ b/command/services/deregister/deregister.go @@ -0,0 +1,102 @@ +package deregister + +import ( + "flag" + "fmt" + + "github.com/hashicorp/consul/command/flags" + "github.com/hashicorp/consul/command/services" + "github.com/mitchellh/cli" +) + +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 +} + +func (c *cmd) init() { + c.flags = flag.NewFlagSet("", flag.ContinueOnError) + + c.http = &flags.HTTPFlags{} + flags.Merge(c.flags, c.http.ClientFlags()) + flags.Merge(c.flags, c.http.ServerFlags()) + c.help = flags.Usage(help, c.flags) +} + +func (c *cmd) Run(args []string) int { + if err := c.flags.Parse(args); err != nil { + return 1 + } + + // Check for arg validation + args = c.flags.Args() + if len(args) == 0 { + c.UI.Error("Service deregistration requires at least one argument.") + return 1 + } + + svcs, err := services.ServicesFromFiles(args) + if err != nil { + c.UI.Error(fmt.Sprintf("Error: %s", err)) + return 1 + } + + // Create and test the HTTP client + client, err := c.http.APIClient() + if err != nil { + c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) + return 1 + } + + // Create all the services + for _, svc := range svcs { + id := svc.ID + if id == "" { + id = svc.Name + } + if id == "" { + continue + } + + if err := client.Agent().ServiceDeregister(id); err != nil { + c.UI.Error(fmt.Sprintf("Error registering service %q: %s", + svc.Name, err)) + return 1 + } + } + + return 0 +} + +func (c *cmd) Synopsis() string { + return synopsis +} + +func (c *cmd) Help() string { + return c.help +} + +const synopsis = "Deregister services with the local agent" +const help = ` +Usage: consul services deregister [options] [FILE...] + + Deregister one or more services that were previously registered with + the local agent. + + $ consul services deregister web.json db.json + + The -id flag may be used to deregister a single service by ID: + + $ consul services deregister -id=web + + Services are deregistered from the local agent catalog. This command must + be run against the same agent where the service was registered. +` diff --git a/command/services/deregister/deregister_test.go b/command/services/deregister/deregister_test.go new file mode 100644 index 0000000000..379bb8491c --- /dev/null +++ b/command/services/deregister/deregister_test.go @@ -0,0 +1,115 @@ +package deregister + +import ( + "os" + "strings" + "testing" + + "github.com/hashicorp/consul/agent" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/testutil" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +func TestCommand_noTabs(t *testing.T) { + t.Parallel() + if strings.ContainsRune(New(nil).Help(), '\t') { + t.Fatal("help has tabs") + } +} + +func TestCommand_File_id(t *testing.T) { + t.Parallel() + + require := require.New(t) + a := agent.NewTestAgent(t.Name(), ``) + defer a.Shutdown() + client := a.Client() + + // Register a service + require.NoError(client.Agent().ServiceRegister(&api.AgentServiceRegistration{ + Name: "web"})) + require.NoError(client.Agent().ServiceRegister(&api.AgentServiceRegistration{ + Name: "db"})) + + ui := cli.NewMockUi() + c := New(ui) + + contents := `{ "Service": { "ID": "web", "Name": "foo" } }` + f := testFile(t, "json") + defer os.Remove(f.Name()) + if _, err := f.WriteString(contents); err != nil { + t.Fatalf("err: %#v", err) + } + + args := []string{ + "-http-addr=" + a.HTTPAddr(), + f.Name(), + } + + require.Equal(0, c.Run(args), ui.ErrorWriter.String()) + + svcs, err := client.Agent().Services() + require.NoError(err) + require.Len(svcs, 1) + require.NotNil(svcs["db"]) +} + +func TestCommand_File_nameOnly(t *testing.T) { + t.Parallel() + + require := require.New(t) + a := agent.NewTestAgent(t.Name(), ``) + defer a.Shutdown() + client := a.Client() + + // Register a service + require.NoError(client.Agent().ServiceRegister(&api.AgentServiceRegistration{ + Name: "web"})) + require.NoError(client.Agent().ServiceRegister(&api.AgentServiceRegistration{ + Name: "db"})) + + ui := cli.NewMockUi() + c := New(ui) + + contents := `{ "Service": { "Name": "web" } }` + f := testFile(t, "json") + defer os.Remove(f.Name()) + if _, err := f.WriteString(contents); err != nil { + t.Fatalf("err: %#v", err) + } + + args := []string{ + "-http-addr=" + a.HTTPAddr(), + f.Name(), + } + + require.Equal(0, c.Run(args), ui.ErrorWriter.String()) + + svcs, err := client.Agent().Services() + require.NoError(err) + require.Len(svcs, 1) + require.NotNil(svcs["db"]) +} + +func testFile(t *testing.T, suffix string) *os.File { + f := testutil.TempFile(t, "register-test-file") + if err := f.Close(); err != nil { + t.Fatalf("err: %s", err) + } + + newName := f.Name() + "." + suffix + if err := os.Rename(f.Name(), newName); err != nil { + os.Remove(f.Name()) + t.Fatalf("err: %s", err) + } + + f, err := os.Create(newName) + if err != nil { + os.Remove(newName) + t.Fatalf("err: %s", err) + } + + return f +}