2017-11-20 09:30:52 -05:00
|
|
|
package swarm
|
2016-11-08 15:20:16 -05:00
|
|
|
|
|
|
|
import (
|
2018-05-03 21:02:44 -04:00
|
|
|
"context"
|
2017-12-04 06:30:39 -05:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
|
2017-04-17 18:07:56 -04:00
|
|
|
"github.com/docker/cli/cli/command"
|
2017-12-04 06:30:39 -05:00
|
|
|
"github.com/docker/cli/cli/command/bundlefile"
|
|
|
|
"github.com/docker/cli/cli/command/stack/options"
|
2017-04-17 18:07:56 -04:00
|
|
|
"github.com/docker/cli/cli/compose/convert"
|
2016-11-08 15:20:16 -05:00
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/swarm"
|
2017-12-04 06:30:39 -05:00
|
|
|
"github.com/pkg/errors"
|
2016-11-08 15:20:16 -05:00
|
|
|
)
|
|
|
|
|
2018-06-26 08:07:26 -04:00
|
|
|
// DeployBundle deploy a bundlefile (dab) on a swarm.
|
|
|
|
func DeployBundle(ctx context.Context, dockerCli command.Cli, opts options.Deploy) error {
|
2017-12-04 06:30:39 -05:00
|
|
|
bundle, err := loadBundlefile(dockerCli.Err(), opts.Namespace, opts.Bundlefile)
|
2016-11-08 15:20:16 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-11-21 15:03:43 -05:00
|
|
|
if err := checkDaemonIsSwarmManager(ctx, dockerCli); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-12-04 06:30:39 -05:00
|
|
|
namespace := convert.NewNamespace(opts.Namespace)
|
2016-11-08 15:20:16 -05:00
|
|
|
|
2017-12-04 06:30:39 -05:00
|
|
|
if opts.Prune {
|
2017-02-22 15:43:13 -05:00
|
|
|
services := map[string]struct{}{}
|
|
|
|
for service := range bundle.Services {
|
|
|
|
services[service] = struct{}{}
|
|
|
|
}
|
|
|
|
pruneServices(ctx, dockerCli, namespace, services)
|
|
|
|
}
|
|
|
|
|
2016-11-08 15:20:16 -05:00
|
|
|
networks := make(map[string]types.NetworkCreate)
|
|
|
|
for _, service := range bundle.Services {
|
|
|
|
for _, networkName := range service.Networks {
|
2018-03-12 13:09:59 -04:00
|
|
|
networks[namespace.Scope(networkName)] = types.NetworkCreate{
|
2016-12-05 16:14:08 -05:00
|
|
|
Labels: convert.AddStackLabel(namespace, nil),
|
2016-11-08 15:20:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
services := make(map[string]swarm.ServiceSpec)
|
|
|
|
for internalName, service := range bundle.Services {
|
2016-11-30 17:38:40 -05:00
|
|
|
name := namespace.Scope(internalName)
|
2016-11-08 15:20:16 -05:00
|
|
|
|
|
|
|
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{
|
2016-11-30 17:38:40 -05:00
|
|
|
Target: namespace.Scope(networkName),
|
2017-03-27 05:42:15 -04:00
|
|
|
Aliases: []string{internalName},
|
2016-11-08 15:20:16 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
serviceSpec := swarm.ServiceSpec{
|
|
|
|
Annotations: swarm.Annotations{
|
|
|
|
Name: name,
|
2016-12-05 16:14:08 -05:00
|
|
|
Labels: convert.AddStackLabel(namespace, service.Labels),
|
2016-11-08 15:20:16 -05:00
|
|
|
},
|
|
|
|
TaskTemplate: swarm.TaskSpec{
|
2017-08-07 05:52:40 -04:00
|
|
|
ContainerSpec: &swarm.ContainerSpec{
|
2016-11-08 15:20:16 -05:00
|
|
|
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.
|
2016-12-05 16:14:08 -05:00
|
|
|
Labels: convert.AddStackLabel(namespace, nil),
|
2016-11-08 15:20:16 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
EndpointSpec: &swarm.EndpointSpec{
|
|
|
|
Ports: ports,
|
|
|
|
},
|
|
|
|
Networks: nets,
|
|
|
|
}
|
|
|
|
|
|
|
|
services[internalName] = serviceSpec
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-12-04 06:30:39 -05:00
|
|
|
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
|
2016-11-08 15:20:16 -05:00
|
|
|
}
|