diff --git a/cli/cmd/compose/compose.go b/cli/cmd/compose/compose.go index 8acb5d3f7..98658d41e 100644 --- a/cli/cmd/compose/compose.go +++ b/cli/cmd/compose/compose.go @@ -20,13 +20,10 @@ import ( "context" "github.com/compose-spec/compose-go/cli" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/docker/api/client" - apicontext "github.com/docker/api/context" - "github.com/docker/api/context/store" "github.com/docker/api/errdefs" ) @@ -67,26 +64,10 @@ func Command() *cobra.Command { } func checkComposeSupport(ctx context.Context) error { - c, err := client.New(ctx) - if err == nil { - composeService := c.ComposeService() - if composeService == nil { - return errors.New("compose not implemented in current context") - } - return nil - } + _, err := client.New(ctx) if errdefs.IsNotFoundError(err) { - currentContext := apicontext.CurrentContext(ctx) - s := store.ContextStore(ctx) - cc, err := s.Get(currentContext) - if err != nil { - return err - } - if cc.Type() == store.AwsContextType { - return errors.Errorf(`%q context type has been renamed. Recreate the context by running: -$ docker context create %s `, cc.Type(), store.EcsContextType) - } - return errors.Wrapf(errdefs.ErrNotImplemented, "compose command not supported on context type %q", cc.Type()) + return errdefs.ErrNotImplemented } + return err } diff --git a/cli/cmd/compose/down.go b/cli/cmd/compose/down.go index a9bedddbf..86b7a1a2a 100644 --- a/cli/cmd/compose/down.go +++ b/cli/cmd/compose/down.go @@ -18,7 +18,6 @@ package compose import ( "context" - "errors" "github.com/spf13/cobra" @@ -47,16 +46,11 @@ func runDown(ctx context.Context, opts composeOptions) error { return err } - composeService := c.ComposeService() - if composeService == nil { - return errors.New("compose not implemented in current context") - } - return progress.Run(ctx, func(ctx context.Context) error { options, err := opts.toProjectOptions() if err != nil { return err } - return composeService.Down(ctx, options) + return c.ComposeService().Down(ctx, options) }) } diff --git a/cli/cmd/compose/logs.go b/cli/cmd/compose/logs.go index aa22e63d5..62ac02320 100644 --- a/cli/cmd/compose/logs.go +++ b/cli/cmd/compose/logs.go @@ -18,7 +18,6 @@ package compose import ( "context" - "errors" "os" "github.com/spf13/cobra" @@ -47,14 +46,9 @@ func runLogs(ctx context.Context, opts composeOptions) error { return err } - composeService := c.ComposeService() - if composeService == nil { - return errors.New("compose not implemented in current context") - } - options, err := opts.toProjectOptions() if err != nil { return err } - return composeService.Logs(ctx, options, os.Stdout) + return c.ComposeService().Logs(ctx, options, os.Stdout) } diff --git a/cli/cmd/compose/ps.go b/cli/cmd/compose/ps.go index 109e31908..068542167 100644 --- a/cli/cmd/compose/ps.go +++ b/cli/cmd/compose/ps.go @@ -18,7 +18,6 @@ package compose import ( "context" - "errors" "fmt" "io" "os" @@ -51,16 +50,11 @@ func runPs(ctx context.Context, opts composeOptions) error { return err } - composeService := c.ComposeService() - if composeService == nil { - return errors.New("compose not implemented in current context") - } - options, err := opts.toProjectOptions() if err != nil { return err } - serviceList, err := composeService.Ps(ctx, options) + serviceList, err := c.ComposeService().Ps(ctx, options) if err != nil { return err } diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go index 0cd28e9cf..1442cfe96 100644 --- a/cli/cmd/compose/up.go +++ b/cli/cmd/compose/up.go @@ -18,7 +18,6 @@ package compose import ( "context" - "errors" "github.com/spf13/cobra" @@ -49,16 +48,11 @@ func runUp(ctx context.Context, opts composeOptions) error { return err } - composeService := c.ComposeService() - if composeService == nil { - return errors.New("compose not implemented in current context") - } - return progress.Run(ctx, func(ctx context.Context) error { options, err := opts.toProjectOptions() if err != nil { return err } - return composeService.Up(ctx, options) + return c.ComposeService().Up(ctx, options) }) } diff --git a/cli/main.go b/cli/main.go index 26c25315b..d5f6e11c7 100644 --- a/cli/main.go +++ b/cli/main.go @@ -175,6 +175,11 @@ func main() { ctype = cc.Type() } + if ctype == store.AwsContextType { + exit(root, currentContext, errors.Errorf(`%q context type has been renamed. Recreate the context by running: +$ docker context create %s `, cc.Type(), store.EcsContextType)) + } + metrics.Track(ctype, os.Args[1:], root.PersistentFlags()) ctx = apicontext.WithCurrentContext(ctx, currentContext) @@ -189,21 +194,32 @@ func main() { // Context should always be handled by new CLI requiredCmd, _, _ := root.Find(os.Args[1:]) if requiredCmd != nil && isOwnCommand(requiredCmd) { - exit(err) + exit(root, currentContext, err) } mobycli.ExecIfDefaultCtxType(ctx) checkIfUnknownCommandExistInDefaultContext(err, currentContext) - exit(err) + exit(root, currentContext, err) } } -func exit(err error) { +func exit(cmd *cobra.Command, ctx string, err error) { if errors.Is(err, errdefs.ErrLoginRequired) { fmt.Fprintln(os.Stderr, err) os.Exit(errdefs.ExitCodeLoginRequired) } + if errors.Is(err, errdefs.ErrNotImplemented) { + cmd, _, _ := cmd.Traverse(os.Args[1:]) + name := cmd.Name() + parent := cmd.Parent() + if parent != nil && parent.Parent() != nil { + name = parent.Name() + " " + name + } + fmt.Fprintf(os.Stderr, "Command %q not available in current context (%s)\n", name, ctx) + os.Exit(1) + } + fatal(err) } diff --git a/client/client.go b/client/client.go index 64b98e89e..3b864a0b6 100644 --- a/client/client.go +++ b/client/client.go @@ -19,14 +19,13 @@ package client import ( "context" - "github.com/docker/api/secrets" - "github.com/docker/api/backend" "github.com/docker/api/compose" "github.com/docker/api/containers" apicontext "github.com/docker/api/context" "github.com/docker/api/context/cloud" "github.com/docker/api/context/store" + "github.com/docker/api/secrets" ) // New returns a backend client associated with current context @@ -63,15 +62,27 @@ type Client struct { // ContainerService returns the backend service for the current context func (c *Client) ContainerService() containers.Service { - return c.bs.ContainerService() + if cs := c.bs.ContainerService(); cs != nil { + return cs + } + + return &containerService{} } // ComposeService returns the backend service for the current context func (c *Client) ComposeService() compose.Service { - return c.bs.ComposeService() + if cs := c.bs.ComposeService(); cs != nil { + return cs + } + + return &composeService{} } // SecretsService returns the backend service for the current context func (c *Client) SecretsService() secrets.Service { - return c.bs.SecretsService() + if ss := c.bs.SecretsService(); ss != nil { + return ss + } + + return &secretsService{} } diff --git a/client/compose.go b/client/compose.go new file mode 100644 index 000000000..ba78d1a84 --- /dev/null +++ b/client/compose.go @@ -0,0 +1,55 @@ +/* + Copyright 2020 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "io" + + "github.com/compose-spec/compose-go/cli" + + "github.com/docker/api/compose" + "github.com/docker/api/errdefs" +) + +type composeService struct { +} + +// Up executes the equivalent to a `compose up` +func (c *composeService) Up(context.Context, *cli.ProjectOptions) error { + return errdefs.ErrNotImplemented +} + +// Down executes the equivalent to a `compose down` +func (c *composeService) Down(context.Context, *cli.ProjectOptions) error { + return errdefs.ErrNotImplemented +} + +// Logs executes the equivalent to a `compose logs` +func (c *composeService) Logs(context.Context, *cli.ProjectOptions, io.Writer) error { + return errdefs.ErrNotImplemented +} + +// Ps executes the equivalent to a `compose ps` +func (c *composeService) Ps(context.Context, *cli.ProjectOptions) ([]compose.ServiceStatus, error) { + return nil, errdefs.ErrNotImplemented +} + +// Convert translate compose model into backend's native format +func (c *composeService) Convert(context.Context, *cli.ProjectOptions) ([]byte, error) { + return nil, errdefs.ErrNotImplemented +} diff --git a/client/containers.go b/client/containers.go new file mode 100644 index 000000000..b958c7afe --- /dev/null +++ b/client/containers.go @@ -0,0 +1,67 @@ +/* + Copyright 2020 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + + "github.com/docker/api/containers" + "github.com/docker/api/errdefs" +) + +type containerService struct { +} + +// List returns all the containers +func (c *containerService) List(context.Context, bool) ([]containers.Container, error) { + return nil, errdefs.ErrNotImplemented +} + +// Start starts a stopped container +func (c *containerService) Start(context.Context, string) error { + return errdefs.ErrNotImplemented +} + +// Stop stops the running container +func (c *containerService) Stop(context.Context, string, *uint32) error { + return errdefs.ErrNotImplemented +} + +// Run creates and starts a container +func (c *containerService) Run(context.Context, containers.ContainerConfig) error { + return errdefs.ErrNotImplemented +} + +// Exec executes a command inside a running container +func (c *containerService) Exec(context.Context, string, containers.ExecRequest) error { + return errdefs.ErrNotImplemented +} + +// Logs returns all the logs of a container +func (c *containerService) Logs(context.Context, string, containers.LogsRequest) error { + return errdefs.ErrNotImplemented +} + +// Delete removes containers +func (c *containerService) Delete(context.Context, string, containers.DeleteRequest) error { + return errdefs.ErrNotImplemented +} + +// Inspect get a specific container +func (c *containerService) Inspect(context.Context, string) (containers.Container, error) { + return containers.Container{}, errdefs.ErrNotImplemented +} diff --git a/client/secrets.go b/client/secrets.go new file mode 100644 index 000000000..44385f863 --- /dev/null +++ b/client/secrets.go @@ -0,0 +1,43 @@ +/* + Copyright 2020 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + + "github.com/docker/api/errdefs" + "github.com/docker/api/secrets" +) + +type secretsService struct { +} + +func (s *secretsService) CreateSecret(context.Context, secrets.Secret) (string, error) { + return "", errdefs.ErrNotImplemented +} + +func (s *secretsService) InspectSecret(context.Context, string) (secrets.Secret, error) { + return secrets.Secret{}, errdefs.ErrNotImplemented +} + +func (s *secretsService) ListSecrets(context.Context) ([]secrets.Secret, error) { + return nil, errdefs.ErrNotImplemented +} + +func (s *secretsService) DeleteSecret(context.Context, string, bool) error { + return errdefs.ErrNotImplemented +} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 04a7d2966..0eccc3456 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -54,7 +54,7 @@ func TestComposeNotImplemented(t *testing.T) { res = c.RunDockerCmd("compose", "up") res.Assert(t, icmd.Expected{ ExitCode: 1, - Err: `compose command not supported on context type "moby": not implemented`, + Err: `Command "compose up" not available in current context (default)`, }) }