diff --git a/cli/stop_service.go b/cli/stop_service.go index 3814149..3fc5045 100644 --- a/cli/stop_service.go +++ b/cli/stop_service.go @@ -4,25 +4,63 @@ package cli import ( + "context" "fmt" "github.com/spf13/cobra" service "spud/service" + webclient "spud/webclient" ) func getStopCommand() *cobra.Command { + type ParsedFlags struct { + serviceName string + daemonHost string + daemonPort int + } stop := &cobra.Command{ Use: "stop [service-name]", Short: "Stops a running service and all of its containers.", - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return fmt.Errorf("Must specify a service using '--service'") + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + var serviceName, host string + var port int + var err error + + if host, err = cmd.PersistentFlags().GetString("host"); err != nil { + return err } - serviceName := args[0] + if port, err = cmd.PersistentFlags().GetInt("port"); err != nil { + return err + } - return service.NewPodmanServiceManager().Stop(serviceName) + if host != "" && port == 0 || host == "" && port != 0 { + return fmt.Errorf("Invalid flags: host and port must be defined together or not at all.") + } + + if len(args) == 0 { + return fmt.Errorf("Must provide a service name.") + } + + serviceName = args[0] + + cmd.SetContext(context.WithValue(cmd.Context(), "flags", ParsedFlags{serviceName: serviceName, daemonHost: host, daemonPort: port})) + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + flags := cmd.Context().Value("flags").(ParsedFlags) + + if flags.daemonHost != "" && flags.daemonPort != 0 { + webclient.NewWebClient(flags.daemonHost, flags.daemonPort).StopService(flags.serviceName) + return nil + + } + + return service.NewPodmanServiceManager().Stop(flags.serviceName) }, } + stop.PersistentFlags().StringP("host", "H", "", "If specified, host where the daemon lives.") + stop.PersistentFlags().IntP("port", "p", 0, "Port on the daemon host.") + return stop } diff --git a/cli/stop_service_test.go b/cli/stop_service_test.go index 0dbf321..1213409 100644 --- a/cli/stop_service_test.go +++ b/cli/stop_service_test.go @@ -1,10 +1,12 @@ package cli import ( + "fmt" + "github.com/spf13/cobra" "testing" ) -func TestCliStopRequiresAServiceName(t *testing.T) { +func Test_StopServiceCli_StopRequiresAServiceName(t *testing.T) { cli := GetCli() cli.SetArgs([]string{"stop"}) @@ -15,3 +17,36 @@ func TestCliStopRequiresAServiceName(t *testing.T) { t.Error("Expected error, got nil.") } } + +func Test_StopServiceCli_ErrorIfHostAndPortNotProvidedTogether(t *testing.T) { + inputs := [][]string{ + {"stop", "-H", "host"}, + {"stop", "-p", "9999"}, + } + + for _, input := range inputs { + t.Run(fmt.Sprintf("%+v", input), func(t *testing.T) { + cli := GetCli() + cli.SetArgs(input) + + stopCommand, _, _ := cli.Find([]string{"stop"}) + + previousPreRun := stopCommand.PersistentPreRunE + + stopCommand.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { + if err := previousPreRun(cmd, args); err == nil { + t.Errorf("Expected error, got nil.") + } + + return nil + } + + stopCommand.RunE = func(cmd *cobra.Command, args []string) error { + return nil + } + + cli.Execute() + }) + + } +} diff --git a/webclient/client_test.go b/webclient/client_test.go index 450af35..a8b4719 100644 --- a/webclient/client_test.go +++ b/webclient/client_test.go @@ -26,6 +26,11 @@ func (d *DummyHttpClient) Post(url string, contentType string, data io.Reader) ( return nil, nil } +func (d *DummyHttpClient) Do(request *http.Request) (*http.Response, error) { + d.requests = append(d.requests, RecordedRequest{method: request.Method, url: request.URL.String(), contentType: "", data: request.Body}) + return nil, nil +} + func Test_WebClient_GetBaseUrlGetsUrlFromHostPort(t *testing.T) { c := NewWebClient("http://host", 9999) @@ -71,3 +76,21 @@ func Test_WebClient_CreateServiceSendsDefinition(t *testing.T) { t.Errorf("Unexpected data: %s != %s", actualDef.String(), string(expectedDef)) } } + +func Test_WebClient_StopServiceDeletesToDaemon(t *testing.T) { + c := NewWebClient("http://host", 9999) + httpClient := &DummyHttpClient{} + c.httpClient = httpClient + + serviceName := "test-service" + c.StopService(serviceName) + + if len(httpClient.requests) != 1 || httpClient.requests[0].method != http.MethodDelete { + t.Errorf("Expected one DELETE request, got none.") + } + + expected := c.getBaseUrl() + "/service/" + serviceName + "/" + if httpClient.requests[0].url != expected { + t.Errorf("Expected url to be %s, got %s.", expected, httpClient.requests[0].url) + } +} diff --git a/webclient/main.go b/webclient/main.go index e955eab..74f6b0c 100644 --- a/webclient/main.go +++ b/webclient/main.go @@ -12,6 +12,7 @@ import ( type HttpClient interface { Post(string, string, io.Reader) (*http.Response, error) + Do(*http.Request) (*http.Response, error) } type WebClient struct { @@ -43,3 +44,10 @@ func (c WebClient) CreateService(def service_definition.ServiceDefinition) error return e } + +func (c WebClient) StopService(name string) error { + req, _ := http.NewRequest(http.MethodDelete, c.getBaseUrl()+"/service/"+name+"/", nil) + _, e := c.httpClient.Do(req) + + return e +}