2016-09-08 13:11:39 -04:00
package swarm
import (
2018-05-03 21:02:44 -04:00
"context"
2016-09-08 13:11:39 -04:00
"fmt"
2018-07-28 22:44:11 -04:00
"net"
2016-09-08 13:11:39 -04:00
"strings"
2017-04-17 18:07:56 -04:00
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
2016-09-08 13:11:39 -04:00
"github.com/docker/docker/api/types/swarm"
2016-10-27 21:50:49 -04:00
"github.com/pkg/errors"
2016-09-08 13:11:39 -04:00
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
type initOptions struct {
swarmOptions
listenAddr NodeAddrOption
// Not a NodeAddrOption because it has no default port.
2018-07-28 22:44:11 -04:00
advertiseAddr string
dataPathAddr string
2018-11-26 16:04:39 -05:00
dataPathPort uint32
2018-07-28 22:44:11 -04:00
forceNewCluster bool
availability string
defaultAddrPools [ ] net . IPNet
DefaultAddrPoolMaskLength uint32
2016-09-08 13:11:39 -04:00
}
2016-12-25 16:23:35 -05:00
func newInitCommand ( dockerCli command . Cli ) * cobra . Command {
2016-09-08 13:11:39 -04:00
opts := initOptions {
listenAddr : NewListenAddrOption ( ) ,
}
cmd := & cobra . Command {
Use : "init [OPTIONS]" ,
Short : "Initialize a swarm" ,
Args : cli . NoArgs ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
return runInit ( dockerCli , cmd . Flags ( ) , opts )
} ,
}
flags := cmd . Flags ( )
flags . Var ( & opts . listenAddr , flagListenAddr , "Listen address (format: <ip|interface>[:port])" )
flags . StringVar ( & opts . advertiseAddr , flagAdvertiseAddr , "" , "Advertised address (format: <ip|interface>[:port])" )
2017-04-14 19:54:17 -04:00
flags . StringVar ( & opts . dataPathAddr , flagDataPathAddr , "" , "Address or interface to use for data path traffic (format: <ip|interface>)" )
2018-07-30 04:54:05 -04:00
flags . SetAnnotation ( flagDataPathAddr , "version" , [ ] string { "1.31" } )
2018-11-26 16:04:39 -05:00
flags . Uint32Var ( & opts . dataPathPort , flagDataPathPort , 0 , "Port number to use for data path traffic (1024 - 49151). If no value is set or is set to 0, the default port (4789) is used." )
flags . SetAnnotation ( flagDataPathPort , "version" , [ ] string { "1.40" } )
2016-11-01 15:11:38 -04:00
flags . BoolVar ( & opts . forceNewCluster , "force-new-cluster" , false , "Force create a new cluster from current state" )
2016-11-10 15:05:19 -05:00
flags . BoolVar ( & opts . autolock , flagAutolock , false , "Enable manager autolocking (requiring an unlock key to start a stopped manager)" )
2017-02-08 03:31:16 -05:00
flags . StringVar ( & opts . availability , flagAvailability , "active" , ` Availability of the node ("active"|"pause"|"drain") ` )
2020-05-03 16:23:08 -04:00
flags . Var ( newIPNetSliceValue ( [ ] net . IPNet { } , & opts . defaultAddrPools ) , flagDefaultAddrPool , "default address pool in CIDR format" )
2018-07-28 22:44:11 -04:00
flags . SetAnnotation ( flagDefaultAddrPool , "version" , [ ] string { "1.39" } )
flags . Uint32Var ( & opts . DefaultAddrPoolMaskLength , flagDefaultAddrPoolMaskLength , 24 , "default address pool subnet mask length" )
flags . SetAnnotation ( flagDefaultAddrPoolMaskLength , "version" , [ ] string { "1.39" } )
2016-09-08 13:11:39 -04:00
addSwarmFlags ( flags , & opts . swarmOptions )
return cmd
}
2016-12-25 16:23:35 -05:00
func runInit ( dockerCli command . Cli , flags * pflag . FlagSet , opts initOptions ) error {
2018-07-28 22:44:11 -04:00
var defaultAddrPool [ ] string
2016-09-08 13:11:39 -04:00
client := dockerCli . Client ( )
ctx := context . Background ( )
2018-07-28 22:44:11 -04:00
for _ , p := range opts . defaultAddrPools {
defaultAddrPool = append ( defaultAddrPool , p . String ( ) )
}
2016-09-08 13:11:39 -04:00
req := swarm . InitRequest {
2016-10-27 21:50:49 -04:00
ListenAddr : opts . listenAddr . String ( ) ,
AdvertiseAddr : opts . advertiseAddr ,
2017-04-14 19:54:17 -04:00
DataPathAddr : opts . dataPathAddr ,
2018-11-26 16:04:39 -05:00
DataPathPort : opts . dataPathPort ,
2018-07-28 22:44:11 -04:00
DefaultAddrPool : defaultAddrPool ,
2016-10-27 21:50:49 -04:00
ForceNewCluster : opts . forceNewCluster ,
Spec : opts . swarmOptions . ToSpec ( flags ) ,
AutoLockManagers : opts . swarmOptions . autolock ,
2018-07-28 22:44:11 -04:00
SubnetSize : opts . DefaultAddrPoolMaskLength ,
2016-09-08 13:11:39 -04:00
}
2016-12-21 21:13:31 -05:00
if flags . Changed ( flagAvailability ) {
availability := swarm . NodeAvailability ( strings . ToLower ( opts . availability ) )
switch availability {
case swarm . NodeAvailabilityActive , swarm . NodeAvailabilityPause , swarm . NodeAvailabilityDrain :
req . Availability = availability
default :
2017-03-09 13:23:45 -05:00
return errors . Errorf ( "invalid availability %q, only active, pause and drain are supported" , opts . availability )
2016-12-21 21:13:31 -05:00
}
}
2016-09-08 13:11:39 -04:00
nodeID , err := client . SwarmInit ( ctx , req )
if err != nil {
if strings . Contains ( err . Error ( ) , "could not choose an IP address to advertise" ) || strings . Contains ( err . Error ( ) , "could not find the system's IP address" ) {
return errors . New ( err . Error ( ) + " - specify one with --advertise-addr" )
}
return err
}
fmt . Fprintf ( dockerCli . Out ( ) , "Swarm initialized: current node (%s) is now a manager.\n\n" , nodeID )
2017-02-09 17:54:05 -05:00
if err := printJoinCommand ( ctx , dockerCli , nodeID , true , false ) ; err != nil {
2016-09-08 13:11:39 -04:00
return err
}
fmt . Fprint ( dockerCli . Out ( ) , "To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.\n\n" )
2016-10-21 21:07:55 -04:00
2016-10-27 21:50:49 -04:00
if req . AutoLockManagers {
unlockKeyResp , err := client . SwarmGetUnlockKey ( ctx )
if err != nil {
return errors . Wrap ( err , "could not fetch unlock key" )
2016-10-21 21:07:55 -04:00
}
2017-06-09 17:16:56 -04:00
printUnlockCommand ( dockerCli . Out ( ) , unlockKeyResp . UnlockKey )
2016-10-21 21:07:55 -04:00
}
2016-10-27 21:50:49 -04:00
return nil
2016-10-21 21:07:55 -04:00
}