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