diff --git a/Makefile b/Makefile index d8a5e7b38..c6d3d8e38 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ all: cli protos: ## Generate go code from .proto files @docker build . \ + --output type=local,dest=. \ --target protos cli: ## Compile the cli diff --git a/azure/aci.go b/azure/aci.go index 7404483d8..964a2ca17 100644 --- a/azure/aci.go +++ b/azure/aci.go @@ -98,11 +98,12 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group return err } -func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (c containerinstance.ContainerGroup, err error) { +func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (containerinstance.ContainerGroup, error) { containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) if err != nil { - return c, fmt.Errorf("cannot get container group client: %v", err) + return containerinstance.ContainerGroup{}, fmt.Errorf("cannot get container group client: %v", err) } + return containerGroupsClient.Delete(ctx, aciContext.ResourceGroup, containerGroupName) } @@ -271,7 +272,7 @@ func getSubscriptionsClient() subscription.SubscriptionsClient { return subc } -//GetGroupsClient ... +// GetGroupsClient ... func GetGroupsClient(subscriptionID string) resources.GroupsClient { groupsClient := resources.NewGroupsClient(subscriptionID) authorizer, _ := auth.NewAuthorizerFromCLI() @@ -279,7 +280,7 @@ func GetGroupsClient(subscriptionID string) resources.GroupsClient { return groupsClient } -//GetSubscriptionID ... +// GetSubscriptionID ... func GetSubscriptionID(ctx context.Context) (string, error) { c := getSubscriptionsClient() res, err := c.List(ctx) diff --git a/azure/backend.go b/azure/backend.go index 1a6e7bdf4..f1fedddff 100644 --- a/azure/backend.go +++ b/azure/backend.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "net/http" "strconv" "strings" @@ -23,6 +24,9 @@ import ( const singleContainerName = "single--container--aci" +// ErrNoSuchContainer is returned when the mentioned container does not exist +var ErrNoSuchContainer = errors.New("no such container") + func init() { backend.Register("aci", "aci", func(ctx context.Context) (backend.Service, error) { return New(ctx) @@ -214,6 +218,18 @@ func (cs *aciContainerService) Logs(ctx context.Context, containerName string, r return err } +func (cs *aciContainerService) Delete(ctx context.Context, containerID string, _ bool) error { + cg, err := deleteACIContainerGroup(ctx, cs.ctx, containerID) + if err != nil { + return err + } + if cg.StatusCode == http.StatusNoContent { + return ErrNoSuchContainer + } + + return err +} + type aciComposeService struct { containerGroupsClient containerinstance.ContainerGroupsClient ctx store.AciContext @@ -239,6 +255,14 @@ func (cs *aciComposeService) Down(ctx context.Context, opts compose.ProjectOptio return err } logrus.Debugf("Down on project with name %q\n", project.Name) - _, err = deleteACIContainerGroup(ctx, cs.ctx, project.Name) + + cg, err := deleteACIContainerGroup(ctx, cs.ctx, project.Name) + if err != nil { + return err + } + if cg.StatusCode == http.StatusNoContent { + return ErrNoSuchContainer + } + return err } diff --git a/azure/convert/convert.go b/azure/convert/convert.go index 490599e69..1f4523acf 100644 --- a/azure/convert/convert.go +++ b/azure/convert/convert.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/profiles/latest/containerinstance/mgmt/containerinstance" "github.com/Azure/go-autorest/autorest/to" "github.com/compose-spec/compose-go/types" + "github.com/docker/api/compose" "github.com/docker/api/context/store" ) diff --git a/backend/v1/backend.pb.go b/backend/v1/backend.pb.go index 013dd4947..b93e99e7c 100644 --- a/backend/v1/backend.pb.go +++ b/backend/v1/backend.pb.go @@ -26,7 +26,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.21.0-devel +// protoc-gen-go v1.22.0 // protoc v3.6.1 // source: backend/v1/backend.proto diff --git a/cli/cmd/rm.go b/cli/cmd/rm.go new file mode 100644 index 000000000..0e97479d8 --- /dev/null +++ b/cli/cmd/rm.go @@ -0,0 +1,52 @@ +package cmd + +import ( + "fmt" + "strings" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/docker/api/client" +) + +type rmOpts struct { + force bool +} + +// RmCommand deletes containers +func RmCommand() *cobra.Command { + var opts rmOpts + cmd := &cobra.Command{ + Use: "rm", + Aliases: []string{"delete"}, + Short: "Remove containers", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var errs []string + c, err := client.New(cmd.Context()) + if err != nil { + return errors.Wrap(err, "cannot connect to backend") + } + + for _, id := range args { + err := c.ContainerService().Delete(cmd.Context(), id, opts.force) + if err != nil { + errs = append(errs, err.Error()+" "+id) + continue + } + fmt.Println(id) + } + + if len(errs) > 0 { + return errors.New(strings.Join(errs, "\n")) + } + + return nil + }, + } + + cmd.Flags().BoolVarP(&opts.force, "force", "f", false, "Force removal") + + return cmd +} diff --git a/cli/main.go b/cli/main.go index ce569983f..22ae0cdce 100644 --- a/cli/main.go +++ b/cli/main.go @@ -108,6 +108,7 @@ func main() { run.Command(), cmd.ExecCommand(), cmd.LogsCommand(), + cmd.RmCommand(), compose.Command(), ) diff --git a/cli/v1/cli.pb.go b/cli/v1/cli.pb.go index a0faba286..8a8be6910 100644 --- a/cli/v1/cli.pb.go +++ b/cli/v1/cli.pb.go @@ -26,7 +26,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.21.0-devel +// protoc-gen-go v1.22.0 // protoc v3.6.1 // source: cli/v1/cli.proto diff --git a/compose/v1/compose.pb.go b/compose/v1/compose.pb.go index fe2917e72..f0dda24cc 100644 --- a/compose/v1/compose.pb.go +++ b/compose/v1/compose.pb.go @@ -26,7 +26,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.21.0-devel +// protoc-gen-go v1.22.0 // protoc v3.6.1 // source: compose/v1/compose.proto diff --git a/containers/api.go b/containers/api.go index f3ba59454..77d9aaead 100644 --- a/containers/api.go +++ b/containers/api.go @@ -54,4 +54,6 @@ type Service interface { Exec(ctx context.Context, containerName string, command string, reader io.Reader, writer io.Writer) error // Logs returns all the logs of a container Logs(ctx context.Context, containerName string, request LogsRequest) error + // Delete removes containers + Delete(ctx context.Context, id string, force bool) error } diff --git a/containers/v1/containers.pb.go b/containers/v1/containers.pb.go index 632e7b6b9..b204eddfe 100644 --- a/containers/v1/containers.pb.go +++ b/containers/v1/containers.pb.go @@ -26,7 +26,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.21.0-devel +// protoc-gen-go v1.22.0 // protoc v3.6.1 // source: containers/v1/containers.proto diff --git a/example/backend.go b/example/backend.go index be00e0c19..e167191af 100644 --- a/example/backend.go +++ b/example/backend.go @@ -59,6 +59,11 @@ func (cs *containerService) Logs(ctx context.Context, containerName string, requ return nil } +func (cs *containerService) Delete(ctx context.Context, id string, force bool) error { + fmt.Printf("Deleting container %q with force = %t\n", id, force) + return nil +} + type composeService struct{} func (cs *composeService) Up(ctx context.Context, opts compose.ProjectOptions) error { diff --git a/moby/backend.go b/moby/backend.go index d22c50863..527e870e5 100644 --- a/moby/backend.go +++ b/moby/backend.go @@ -125,3 +125,9 @@ func (ms *mobyService) Logs(ctx context.Context, containerName string, request c _, err = io.Copy(request.Writer, r) return err } + +func (ms *mobyService) Delete(ctx context.Context, containerID string, force bool) error { + return ms.apiClient.ContainerRemove(ctx, containerID, types.ContainerRemoveOptions{ + Force: force, + }) +} diff --git a/server/proxy/proxy.go b/server/proxy/proxy.go index a30c38801..787e4501e 100644 --- a/server/proxy/proxy.go +++ b/server/proxy/proxy.go @@ -72,8 +72,13 @@ func (p *proxyContainerAPI) Kill(_ context.Context, _ *v1.KillRequest) (*v1.Kill panic("not implemented") // TODO: Implement } -func (p *proxyContainerAPI) Delete(_ context.Context, _ *v1.DeleteRequest) (*v1.DeleteResponse, error) { - panic("not implemented") // TODO: Implement +func (p *proxyContainerAPI) Delete(ctx context.Context, request *v1.DeleteRequest) (*v1.DeleteResponse, error) { + err := Client(ctx).ContainerService().Delete(ctx, request.Id, request.Force) + if err != nil { + return &v1.DeleteResponse{}, err + } + + return &v1.DeleteResponse{}, nil } func (p *proxyContainerAPI) Update(_ context.Context, _ *v1.UpdateRequest) (*v1.UpdateResponse, error) { diff --git a/tests/aci-e2e/e2e-aci.go b/tests/aci-e2e/e2e-aci.go index 0f45688e8..fea2e453f 100644 --- a/tests/aci-e2e/e2e-aci.go +++ b/tests/aci-e2e/e2e-aci.go @@ -5,16 +5,18 @@ import ( "log" "github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/resources/mgmt/resources" + "github.com/Azure/go-autorest/autorest/to" + . "github.com/onsi/gomega" + "github.com/docker/api/azure" . "github.com/docker/api/tests/framework" - . "github.com/onsi/gomega" ) -const resourceGroupName = "resourceGroupTest" - -var location = "westeurope" - -const contextName = "acitest" +const ( + resourceGroupName = "resourceGroupTest" + location = "westeurope" + contextName = "acitest" +) func main() { SetupTest() @@ -45,7 +47,7 @@ func main() { Expect(err).To(BeNil()) NewDockerCommand("context", "create", contextName, "aci", "--aci-subscription-id", subscriptionID, "--aci-resource-group", resourceGroupName, "--aci-location", location).ExecOrDie() - //Expect(output).To(ContainSubstring("ACI context acitest created")) + // Expect(output).To(ContainSubstring("ACI context acitest created")) }) defer deleteResourceGroup(resourceGroupName) @@ -62,35 +64,33 @@ func main() { Expect(len(Lines(output))).To(Equal(1)) }) - /* - var nginxID string - It("runs nginx on port 80", func() { - NewDockerCommand("run", "nginx", "-p", "80:80").ExecOrDie() - output := NewDockerCommand("ps").ExecOrDie() - Lines := Lines(output) - Expect(len(Lines)).To(Equal(2)) + var nginxID string + It("runs nginx on port 80 (PORT NOT CHECKED YET!!! REMOVE THAT WHEN IMPLEMENTED)", func() { + NewDockerCommand("run", "nginx", "-p", "80:80").ExecOrDie() + output := NewDockerCommand("ps").ExecOrDie() + lines := Lines(output) + Expect(len(lines)).To(Equal(2)) - containerFields := Columns(Lines[1]) - nginxID = containerFields[0] - Expect(containerFields[1]).To(Equal("nginx")) - Expect(containerFields[2]).To(Equal("Running")) - exposedIP := containerFields[3] - Expect(exposedIP).To(ContainSubstring(":80->80/TCP")) + containerFields := Columns(lines[1]) + nginxID = containerFields[0] + Expect(containerFields[1]).To(Equal("nginx")) + Expect(containerFields[2]).To(Equal("Running")) + // exposedIP := containerFields[3] + // Expect(exposedIP).To(ContainSubstring(":80->80/TCP")) - url := strings.ReplaceAll(exposedIP, "->80/TCP", "") - output = NewCommand("curl", url).ExecOrDie() - Expect(output).To(ContainSubstring("Welcome to nginx!")) - }) + // url := strings.ReplaceAll(exposedIP, "->80/TCP", "") + // output = NewCommand("curl", url).ExecOrDie() + // Expect(output).To(ContainSubstring("Welcome to nginx!")) + }) - It("removes container nginx", func() { - output := NewDockerCommand("rm", nginxID).ExecOrDie() - Expect(Lines(output)[0]).To(Equal(nginxID)) - }) - */ + It("removes container nginx", func() { + output := NewDockerCommand("rm", nginxID).ExecOrDie() + Expect(Lines(output)[0]).To(Equal(nginxID)) + }) It("deploys a compose app", func() { NewDockerCommand("compose", "up", "-f", "./tests/composefiles/aci-demo/aci_demo_port.yaml", "--name", "acidemo").ExecOrDie() - //Expect(output).To(ContainSubstring("Successfully deployed")) + // Expect(output).To(ContainSubstring("Successfully deployed")) output := NewDockerCommand("ps").ExecOrDie() Lines := Lines(output) Expect(len(Lines)).To(Equal(4)) @@ -141,7 +141,7 @@ func setupTestResourecGroup(groupName string) { Expect(err).To(BeNil()) gc := azure.GetGroupsClient(subscriptionID) _, err = gc.CreateOrUpdate(ctx, groupName, resources.Group{ - Location: &location, + Location: to.StringPtr(location), }) Expect(err).To(BeNil()) } diff --git a/tests/e2e/e2e.go b/tests/e2e/e2e.go index 3b7064876..d20173ed3 100644 --- a/tests/e2e/e2e.go +++ b/tests/e2e/e2e.go @@ -3,8 +3,9 @@ package main import ( "time" - . "github.com/docker/api/tests/framework" . "github.com/onsi/gomega" + + . "github.com/docker/api/tests/framework" ) func main() {