github.com/ali-iotechsys/cli@v20.10.0+incompatible/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(&opts); err != nil {
    29  		return err
    30  	}
    31  	// client side image resolution should not be done when the supported
    32  	// server version is older than 1.30
    33  	if versions.LessThan(dockerCli.Client().ClientVersion(), "1.30") {
    34  		opts.ResolveImage = ResolveImageNever
    35  	}
    36  
    37  	return deployCompose(ctx, dockerCli, opts, cfg)
    38  }
    39  
    40  // validateResolveImageFlag validates the opts.resolveImage command line option
    41  func validateResolveImageFlag(opts *options.Deploy) error {
    42  	switch opts.ResolveImage {
    43  	case ResolveImageAlways, ResolveImageChanged, ResolveImageNever:
    44  		return nil
    45  	default:
    46  		return errors.Errorf("Invalid option %s for flag --resolve-image", opts.ResolveImage)
    47  	}
    48  }
    49  
    50  // checkDaemonIsSwarmManager does an Info API call to verify that the daemon is
    51  // a swarm manager. This is necessary because we must create networks before we
    52  // create services, but the API call for creating a network does not return a
    53  // proper status code when it can't create a network in the "global" scope.
    54  func checkDaemonIsSwarmManager(ctx context.Context, dockerCli command.Cli) error {
    55  	info, err := dockerCli.Client().Info(ctx)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	if !info.Swarm.ControlAvailable {
    60  		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")
    61  	}
    62  	return nil
    63  }
    64  
    65  // pruneServices removes services that are no longer referenced in the source
    66  func pruneServices(ctx context.Context, dockerCli command.Cli, namespace convert.Namespace, services map[string]struct{}) {
    67  	client := dockerCli.Client()
    68  
    69  	oldServices, err := getStackServices(ctx, client, namespace.Name())
    70  	if err != nil {
    71  		fmt.Fprintf(dockerCli.Err(), "Failed to list services: %s\n", err)
    72  	}
    73  
    74  	pruneServices := []swarm.Service{}
    75  	for _, service := range oldServices {
    76  		if _, exists := services[namespace.Descope(service.Spec.Name)]; !exists {
    77  			pruneServices = append(pruneServices, service)
    78  		}
    79  	}
    80  	removeServices(ctx, dockerCli, pruneServices)
    81  }