github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/command/context/update.go (about)

     1  package context
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"text/tabwriter"
     7  
     8  	"github.com/docker/cli/cli"
     9  	"github.com/docker/cli/cli/command"
    10  	"github.com/docker/cli/cli/context/docker"
    11  	"github.com/docker/cli/cli/context/kubernetes"
    12  	"github.com/docker/cli/cli/context/store"
    13  	"github.com/pkg/errors"
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  // UpdateOptions are the options used to update a context
    18  type UpdateOptions struct {
    19  	Name                     string
    20  	Description              string
    21  	DefaultStackOrchestrator string
    22  	Docker                   map[string]string
    23  	Kubernetes               map[string]string
    24  }
    25  
    26  func longUpdateDescription() string {
    27  	buf := bytes.NewBuffer(nil)
    28  	buf.WriteString("Update a context\n\nDocker endpoint config:\n\n")
    29  	tw := tabwriter.NewWriter(buf, 20, 1, 3, ' ', 0)
    30  	fmt.Fprintln(tw, "NAME\tDESCRIPTION")
    31  	for _, d := range dockerConfigKeysDescriptions {
    32  		fmt.Fprintf(tw, "%s\t%s\n", d.name, d.description)
    33  	}
    34  	tw.Flush()
    35  	buf.WriteString("\nKubernetes endpoint config:\n\n")
    36  	tw = tabwriter.NewWriter(buf, 20, 1, 3, ' ', 0)
    37  	fmt.Fprintln(tw, "NAME\tDESCRIPTION")
    38  	for _, d := range kubernetesConfigKeysDescriptions {
    39  		fmt.Fprintf(tw, "%s\t%s\n", d.name, d.description)
    40  	}
    41  	tw.Flush()
    42  	buf.WriteString("\nExample:\n\n$ docker context update my-context --description \"some description\" --docker \"host=tcp://myserver:2376,ca=~/ca-file,cert=~/cert-file,key=~/key-file\"\n")
    43  	return buf.String()
    44  }
    45  
    46  func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
    47  	opts := &UpdateOptions{}
    48  	cmd := &cobra.Command{
    49  		Use:   "update [OPTIONS] CONTEXT",
    50  		Short: "Update a context",
    51  		Args:  cli.ExactArgs(1),
    52  		RunE: func(cmd *cobra.Command, args []string) error {
    53  			opts.Name = args[0]
    54  			return RunUpdate(dockerCli, opts)
    55  		},
    56  		Long: longUpdateDescription(),
    57  	}
    58  	flags := cmd.Flags()
    59  	flags.StringVar(&opts.Description, "description", "", "Description of the context")
    60  	flags.StringVar(
    61  		&opts.DefaultStackOrchestrator,
    62  		"default-stack-orchestrator", "",
    63  		"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
    64  	flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil)
    65  	flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
    66  	flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
    67  	flags.SetAnnotation("kubernetes", "kubernetes", nil)
    68  	flags.SetAnnotation("kubernetes", "deprecated", nil)
    69  	return cmd
    70  }
    71  
    72  // RunUpdate updates a Docker context
    73  func RunUpdate(cli command.Cli, o *UpdateOptions) error {
    74  	if err := store.ValidateContextName(o.Name); err != nil {
    75  		return err
    76  	}
    77  	s := cli.ContextStore()
    78  	c, err := s.GetMetadata(o.Name)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	dockerContext, err := command.GetDockerContext(c)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if o.DefaultStackOrchestrator != "" {
    87  		stackOrchestrator, err := command.NormalizeOrchestrator(o.DefaultStackOrchestrator)
    88  		if err != nil {
    89  			return errors.Wrap(err, "unable to parse default-stack-orchestrator")
    90  		}
    91  		dockerContext.StackOrchestrator = stackOrchestrator
    92  	}
    93  	if o.Description != "" {
    94  		dockerContext.Description = o.Description
    95  	}
    96  
    97  	c.Metadata = dockerContext
    98  
    99  	tlsDataToReset := make(map[string]*store.EndpointTLSData)
   100  
   101  	if o.Docker != nil {
   102  		dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(cli, o.Docker)
   103  		if err != nil {
   104  			return errors.Wrap(err, "unable to create docker endpoint config")
   105  		}
   106  		c.Endpoints[docker.DockerEndpoint] = dockerEP
   107  		tlsDataToReset[docker.DockerEndpoint] = dockerTLS
   108  	}
   109  	if o.Kubernetes != nil {
   110  		kubernetesEP, kubernetesTLS, err := getKubernetesEndpointMetadataAndTLS(cli, o.Kubernetes)
   111  		if err != nil {
   112  			return errors.Wrap(err, "unable to create kubernetes endpoint config")
   113  		}
   114  		if kubernetesEP == nil {
   115  			delete(c.Endpoints, kubernetes.KubernetesEndpoint)
   116  		} else {
   117  			c.Endpoints[kubernetes.KubernetesEndpoint] = kubernetesEP
   118  			tlsDataToReset[kubernetes.KubernetesEndpoint] = kubernetesTLS
   119  		}
   120  	}
   121  	if err := validateEndpointsAndOrchestrator(c); err != nil {
   122  		return err
   123  	}
   124  	if err := s.CreateOrUpdate(c); err != nil {
   125  		return err
   126  	}
   127  	for ep, tlsData := range tlsDataToReset {
   128  		if err := s.ResetEndpointTLSMaterial(o.Name, ep, tlsData); err != nil {
   129  			return err
   130  		}
   131  	}
   132  
   133  	fmt.Fprintln(cli.Out(), o.Name)
   134  	fmt.Fprintf(cli.Err(), "Successfully updated context %q\n", o.Name)
   135  	return nil
   136  }
   137  
   138  func validateEndpointsAndOrchestrator(c store.Metadata) error {
   139  	dockerContext, err := command.GetDockerContext(c)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	if _, ok := c.Endpoints[kubernetes.KubernetesEndpoint]; !ok && dockerContext.StackOrchestrator.HasKubernetes() {
   144  		return errors.Errorf("cannot specify orchestrator %q without configuring a Kubernetes endpoint", dockerContext.StackOrchestrator)
   145  	}
   146  	return nil
   147  }