github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/command/stack/swarm/deploy.go (about) 1 package swarm 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/docker/cli/cli/command" 8 "github.com/docker/cli/cli/command/stack/options" 9 "github.com/docker/cli/cli/compose/convert" 10 composetypes "github.com/docker/cli/cli/compose/types" 11 "github.com/docker/docker/api/types/swarm" 12 "github.com/docker/docker/api/types/versions" 13 "github.com/pkg/errors" 14 ) 15 16 // Resolve image constants 17 const ( 18 defaultNetworkDriver = "overlay" 19 ResolveImageAlways = "always" 20 ResolveImageChanged = "changed" 21 ResolveImageNever = "never" 22 ) 23 24 // RunDeploy is the swarm implementation of docker stack deploy 25 func RunDeploy(dockerCli command.Cli, opts options.Deploy, cfg *composetypes.Config) error { 26 ctx := context.Background() 27 28 if err := validateResolveImageFlag(dockerCli, &opts); err != nil { 29 return err 30 } 31 32 return deployCompose(ctx, dockerCli, opts, cfg) 33 } 34 35 // validateResolveImageFlag validates the opts.resolveImage command line option 36 // and also turns image resolution off if the version is older than 1.30 37 func validateResolveImageFlag(dockerCli command.Cli, opts *options.Deploy) error { 38 if opts.ResolveImage != ResolveImageAlways && opts.ResolveImage != ResolveImageChanged && opts.ResolveImage != ResolveImageNever { 39 return errors.Errorf("Invalid option %s for flag --resolve-image", opts.ResolveImage) 40 } 41 // client side image resolution should not be done when the supported 42 // server version is older than 1.30 43 if versions.LessThan(dockerCli.Client().ClientVersion(), "1.30") { 44 opts.ResolveImage = ResolveImageNever 45 } 46 return nil 47 } 48 49 // checkDaemonIsSwarmManager does an Info API call to verify that the daemon is 50 // a swarm manager. This is necessary because we must create networks before we 51 // create services, but the API call for creating a network does not return a 52 // proper status code when it can't create a network in the "global" scope. 53 func checkDaemonIsSwarmManager(ctx context.Context, dockerCli command.Cli) error { 54 info, err := dockerCli.Client().Info(ctx) 55 if err != nil { 56 return err 57 } 58 if !info.Swarm.ControlAvailable { 59 return errors.New("this node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again") 60 } 61 return nil 62 } 63 64 // pruneServices removes services that are no longer referenced in the source 65 func pruneServices(ctx context.Context, dockerCli command.Cli, namespace convert.Namespace, services map[string]struct{}) { 66 client := dockerCli.Client() 67 68 oldServices, err := getStackServices(ctx, client, namespace.Name()) 69 if err != nil { 70 fmt.Fprintf(dockerCli.Err(), "Failed to list services: %s\n", err) 71 } 72 73 pruneServices := []swarm.Service{} 74 for _, service := range oldServices { 75 if _, exists := services[namespace.Descope(service.Spec.Name)]; !exists { 76 pruneServices = append(pruneServices, service) 77 } 78 } 79 removeServices(ctx, dockerCli, pruneServices) 80 }