Remove experimental "deploy" from "dab" files

The top-level `docker deploy` command (using the "Docker Application Bundle"
(`.dab`) file format was introduced as an experimental feature in Docker 1.13 /
17.03, but superseded by support for Docker Compose files.

With no development being done on this feature, and no active use of the file
format, support for the DAB file format and the top-level `docker deploy` command
(hidden by default in 19.03), is removed in this patch, in favour of `docker stack deploy`
using compose files.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2019-12-06 14:05:33 +01:00
parent 8547dfcff7
commit 99ad13e374
17 changed files with 4 additions and 750 deletions

View File

@ -73,18 +73,6 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
// NewTopLevelDeployCommand returns a command for `docker deploy`
func NewTopLevelDeployCommand(dockerCli command.Cli) *cobra.Command {
cmd := newDeployCommand(dockerCli, nil)
// Remove the aliases at the top level
cmd.Aliases = []string{}
cmd.Annotations = map[string]string{
"experimental": "",
"version": "1.25",
}
return cmd
}
func getOrchestrator(dockerCli command.Cli, cmd *cobra.Command) (command.Orchestrator, error) {
var orchestratorFlag string
if o, err := cmd.Flags().GetString("orchestrator"); err == nil {

View File

@ -1,8 +1,6 @@
package stack
import (
"context"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/stack/kubernetes"
@ -10,7 +8,6 @@ import (
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/command/stack/swarm"
composetypes "github.com/docker/cli/cli/compose/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@ -28,24 +25,6 @@ func newDeployCommand(dockerCli command.Cli, common *commonOptions) *cobra.Comma
if err := validateStackName(opts.Namespace); err != nil {
return err
}
commonOrchestrator := command.OrchestratorSwarm // default for top-level deploy command
if common != nil {
commonOrchestrator = common.orchestrator
}
switch {
case opts.Bundlefile == "" && len(opts.Composefiles) == 0:
return errors.Errorf("Please specify either a bundle file (with --bundle-file) or a Compose file (with --compose-file).")
case opts.Bundlefile != "" && len(opts.Composefiles) != 0:
return errors.Errorf("You cannot specify both a bundle file and a Compose file.")
case opts.Bundlefile != "":
if commonOrchestrator != command.OrchestratorSwarm {
return errors.Errorf("bundle files are not supported on another orchestrator than swarm.")
}
return swarm.DeployBundle(context.Background(), dockerCli, opts)
}
config, err := loader.LoadComposefile(dockerCli, opts)
if err != nil {
return err
@ -55,9 +34,6 @@ func newDeployCommand(dockerCli command.Cli, common *commonOptions) *cobra.Comma
}
flags := cmd.Flags()
flags.StringVar(&opts.Bundlefile, "bundle-file", "", "Path to a Distributed Application Bundle file")
flags.SetAnnotation("bundle-file", "experimental", nil)
flags.SetAnnotation("bundle-file", "swarm", nil)
flags.StringSliceVarP(&opts.Composefiles, "compose-file", "c", []string{}, `Path to a Compose file, or "-" to read from stdin`)
flags.SetAnnotation("compose-file", "version", []string{"1.25"})
flags.BoolVar(&opts.SendRegistryAuth, "with-registry-auth", false, "Send registry authentication details to Swarm agents")

View File

@ -72,7 +72,7 @@ func getConfigDetails(composefiles []string, stdin io.Reader) (composetypes.Conf
var details composetypes.ConfigDetails
if len(composefiles) == 0 {
return details, errors.New("no composefile(s)")
return details, errors.New("Please specify a Compose file (with --compose-file)")
}
if composefiles[0] == "-" && len(composefiles) == 1 {

View File

@ -4,7 +4,6 @@ import "github.com/docker/cli/opts"
// Deploy holds docker stack deploy options
type Deploy struct {
Bundlefile string
Composefiles []string
Namespace string
ResolveImage string

View File

@ -1,124 +0,0 @@
package swarm
import (
"context"
"fmt"
"io"
"os"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/bundlefile"
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/compose/convert"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
)
// DeployBundle deploy a bundlefile (dab) on a swarm.
func DeployBundle(ctx context.Context, dockerCli command.Cli, opts options.Deploy) error {
bundle, err := loadBundlefile(dockerCli.Err(), opts.Namespace, opts.Bundlefile)
if err != nil {
return err
}
if err := checkDaemonIsSwarmManager(ctx, dockerCli); err != nil {
return err
}
namespace := convert.NewNamespace(opts.Namespace)
if opts.Prune {
services := map[string]struct{}{}
for service := range bundle.Services {
services[service] = struct{}{}
}
pruneServices(ctx, dockerCli, namespace, services)
}
networks := make(map[string]types.NetworkCreate)
for _, service := range bundle.Services {
for _, networkName := range service.Networks {
networks[namespace.Scope(networkName)] = types.NetworkCreate{
Labels: convert.AddStackLabel(namespace, nil),
}
}
}
services := make(map[string]swarm.ServiceSpec)
for internalName, service := range bundle.Services {
name := namespace.Scope(internalName)
var ports []swarm.PortConfig
for _, portSpec := range service.Ports {
ports = append(ports, swarm.PortConfig{
Protocol: swarm.PortConfigProtocol(portSpec.Protocol),
TargetPort: portSpec.Port,
})
}
nets := []swarm.NetworkAttachmentConfig{}
for _, networkName := range service.Networks {
nets = append(nets, swarm.NetworkAttachmentConfig{
Target: namespace.Scope(networkName),
Aliases: []string{internalName},
})
}
serviceSpec := swarm.ServiceSpec{
Annotations: swarm.Annotations{
Name: name,
Labels: convert.AddStackLabel(namespace, service.Labels),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: service.Image,
Command: service.Command,
Args: service.Args,
Env: service.Env,
// Service Labels will not be copied to Containers
// automatically during the deployment so we apply
// it here.
Labels: convert.AddStackLabel(namespace, nil),
},
},
EndpointSpec: &swarm.EndpointSpec{
Ports: ports,
},
Networks: nets,
}
services[internalName] = serviceSpec
}
if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil {
return err
}
return deployServices(ctx, dockerCli, services, namespace, opts.SendRegistryAuth, opts.ResolveImage)
}
func loadBundlefile(stderr io.Writer, namespace string, path string) (*bundlefile.Bundlefile, error) {
defaultPath := fmt.Sprintf("%s.dab", namespace)
if path == "" {
path = defaultPath
}
if _, err := os.Stat(path); err != nil {
return nil, errors.Errorf(
"Bundle %s not found. Specify the path with --file",
path)
}
fmt.Fprintf(stderr, "Loading bundle from %s\n", path)
reader, err := os.Open(path)
if err != nil {
return nil, err
}
defer reader.Close()
bundle, err := bundlefile.LoadFile(reader)
if err != nil {
return nil, errors.Errorf("Error reading %s: %v\n", path, err)
}
return bundle, err
}

View File

@ -1,50 +0,0 @@
package swarm
import (
"bytes"
"path/filepath"
"testing"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestLoadBundlefileErrors(t *testing.T) {
testCases := []struct {
namespace string
path string
expectedError string
}{
{
namespace: "namespace_foo",
expectedError: "Bundle namespace_foo.dab not found",
},
{
namespace: "namespace_foo",
path: "invalid_path",
expectedError: "Bundle invalid_path not found",
},
// FIXME: this test never working, testdata file is missing from repo
//{
// namespace: "namespace_foo",
// path: string(golden.Get(t, "bundlefile_with_invalid_syntax")),
// expectedError: "Error reading",
//},
}
for _, tc := range testCases {
_, err := loadBundlefile(&bytes.Buffer{}, tc.namespace, tc.path)
assert.ErrorContains(t, err, tc.expectedError)
}
}
func TestLoadBundlefile(t *testing.T) {
buf := new(bytes.Buffer)
namespace := ""
path := filepath.Join("testdata", "bundlefile_with_two_services.dab")
bundleFile, err := loadBundlefile(buf, namespace, path)
assert.NilError(t, err)
assert.Check(t, is.Equal(len(bundleFile.Services), 2))
}

View File

@ -1,29 +0,0 @@
{
"Services": {
"visualizer": {
"Image": "busybox@sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f",
"Networks": [
"webnet"
],
"Ports": [
{
"Port": 8080,
"Protocol": "tcp"
}
]
},
"web": {
"Image": "busybox@sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f",
"Networks": [
"webnet"
],
"Ports": [
{
"Port": 80,
"Protocol": "tcp"
}
]
}
},
"Version": "0.1"
}