github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/swarm/join.go (about) 1 package swarm 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/docker/cli/cli" 9 "github.com/docker/cli/cli/command" 10 "github.com/docker/docker/api/types/swarm" 11 "github.com/pkg/errors" 12 "github.com/spf13/cobra" 13 "github.com/spf13/pflag" 14 ) 15 16 type joinOptions struct { 17 remote string 18 listenAddr NodeAddrOption 19 // Not a NodeAddrOption because it has no default port. 20 advertiseAddr string 21 dataPathAddr string 22 token string 23 availability string 24 } 25 26 func newJoinCommand(dockerCli command.Cli) *cobra.Command { 27 opts := joinOptions{ 28 listenAddr: NewListenAddrOption(), 29 } 30 31 cmd := &cobra.Command{ 32 Use: "join [OPTIONS] HOST:PORT", 33 Short: "Join a swarm as a node and/or manager", 34 Args: cli.ExactArgs(1), 35 RunE: func(cmd *cobra.Command, args []string) error { 36 opts.remote = args[0] 37 return runJoin(cmd.Context(), dockerCli, cmd.Flags(), opts) 38 }, 39 Annotations: map[string]string{ 40 "version": "1.24", 41 "swarm": "", // swarm join does not require swarm to be active, and is always available on API 1.24 and up 42 }, 43 } 44 45 flags := cmd.Flags() 46 flags.Var(&opts.listenAddr, flagListenAddr, `Listen address (format: "<ip|interface>[:port]")`) 47 flags.StringVar(&opts.advertiseAddr, flagAdvertiseAddr, "", `Advertised address (format: "<ip|interface>[:port]")`) 48 flags.StringVar(&opts.dataPathAddr, flagDataPathAddr, "", `Address or interface to use for data path traffic (format: "<ip|interface>")`) 49 flags.SetAnnotation(flagDataPathAddr, "version", []string{"1.31"}) 50 flags.StringVar(&opts.token, flagToken, "", "Token for entry into the swarm") 51 flags.StringVar(&opts.availability, flagAvailability, "active", `Availability of the node ("active", "pause", "drain")`) 52 return cmd 53 } 54 55 func runJoin(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, opts joinOptions) error { 56 client := dockerCli.Client() 57 58 req := swarm.JoinRequest{ 59 JoinToken: opts.token, 60 ListenAddr: opts.listenAddr.String(), 61 AdvertiseAddr: opts.advertiseAddr, 62 DataPathAddr: opts.dataPathAddr, 63 RemoteAddrs: []string{opts.remote}, 64 } 65 if flags.Changed(flagAvailability) { 66 availability := swarm.NodeAvailability(strings.ToLower(opts.availability)) 67 switch availability { 68 case swarm.NodeAvailabilityActive, swarm.NodeAvailabilityPause, swarm.NodeAvailabilityDrain: 69 req.Availability = availability 70 default: 71 return errors.Errorf("invalid availability %q, only active, pause and drain are supported", opts.availability) 72 } 73 } 74 75 err := client.SwarmJoin(ctx, req) 76 if err != nil { 77 return err 78 } 79 80 info, err := client.Info(ctx) 81 if err != nil { 82 return err 83 } 84 85 if info.Swarm.ControlAvailable { 86 fmt.Fprintln(dockerCli.Out(), "This node joined a swarm as a manager.") 87 } else { 88 fmt.Fprintln(dockerCli.Out(), "This node joined a swarm as a worker.") 89 } 90 return nil 91 }