Add support for swarm init lock and swarm unlock

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2016-10-21 18:07:55 -07:00 committed by Aaron Lehmann
parent 06666a5a23
commit d006a04357
5 changed files with 84 additions and 1 deletions

View File

@ -24,6 +24,7 @@ func NewSwarmCommand(dockerCli *command.DockerCli) *cobra.Command {
newJoinTokenCommand(dockerCli),
newUpdateCommand(dockerCli),
newLeaveCommand(dockerCli),
newUnlockCommand(dockerCli),
)
return cmd
}

View File

@ -1,10 +1,15 @@
package swarm
import (
"bufio"
"crypto/rand"
"errors"
"fmt"
"io"
"math/big"
"strings"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/net/context"
"github.com/docker/docker/api/types/swarm"
@ -20,6 +25,7 @@ type initOptions struct {
// Not a NodeAddrOption because it has no default port.
advertiseAddr string
forceNewCluster bool
lockKey bool
}
func newInitCommand(dockerCli *command.DockerCli) *cobra.Command {
@ -39,6 +45,7 @@ func newInitCommand(dockerCli *command.DockerCli) *cobra.Command {
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])")
flags.BoolVar(&opts.lockKey, flagLockKey, false, "Encrypt swarm with optionally provided key from stdin")
flags.BoolVar(&opts.forceNewCluster, "force-new-cluster", false, "Force create a new cluster from current state")
addSwarmFlags(flags, &opts.swarmOptions)
return cmd
@ -48,11 +55,31 @@ func runInit(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts initOption
client := dockerCli.Client()
ctx := context.Background()
var lockKey string
if opts.lockKey {
var err error
lockKey, err = readKey(dockerCli.In(), "Please enter key for encrypting swarm(leave empty to generate): ")
if err != nil {
return err
}
if len(lockKey) == 0 {
randBytes := make([]byte, 16)
if _, err := rand.Read(randBytes[:]); err != nil {
panic(fmt.Errorf("failed to general random lock key: %v", err))
}
var n big.Int
n.SetBytes(randBytes[:])
lockKey = n.Text(36)
}
}
req := swarm.InitRequest{
ListenAddr: opts.listenAddr.String(),
AdvertiseAddr: opts.advertiseAddr,
ForceNewCluster: opts.forceNewCluster,
Spec: opts.swarmOptions.ToSpec(flags),
LockKey: lockKey,
}
nodeID, err := client.SwarmInit(ctx, req)
@ -65,6 +92,10 @@ func runInit(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts initOption
fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n\n", nodeID)
if len(lockKey) > 0 {
fmt.Fprintf(dockerCli.Out(), "Swarm is encrypted. When a node is restarted it needs to be unlocked by running command:\n\n echo '%s' | docker swarm unlock\n\n", lockKey)
}
if err := printJoinCommand(ctx, dockerCli, nodeID, true, false); err != nil {
return err
}
@ -72,3 +103,18 @@ func runInit(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts initOption
fmt.Fprint(dockerCli.Out(), "To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.\n\n")
return nil
}
func readKey(in *command.InStream, prompt string) (string, error) {
if in.IsTerminal() {
fmt.Print(prompt)
dt, err := terminal.ReadPassword(int(in.FD()))
fmt.Println()
return string(dt), err
} else {
key, err := bufio.NewReader(in).ReadString('\n')
if err == io.EOF {
err = nil
}
return strings.TrimSpace(key), err
}
}

View File

@ -26,6 +26,7 @@ const (
flagExternalCA = "external-ca"
flagMaxSnapshots = "max-snapshots"
flagSnapshotInterval = "snapshot-interval"
flagLockKey = "lock-key"
)
type swarmOptions struct {

35
command/swarm/unlock.go Normal file
View File

@ -0,0 +1,35 @@
package swarm
import (
"context"
"github.com/spf13/cobra"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
)
func newUnlockCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "unlock",
Short: "Unlock swarm",
Args: cli.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
client := dockerCli.Client()
ctx := context.Background()
key, err := readKey(dockerCli.In(), "Please enter unlock key: ")
if err != nil {
return err
}
req := swarm.UnlockRequest{
LockKey: string(key),
}
return client.SwarmUnlock(ctx, req)
},
}
return cmd
}

View File

@ -96,7 +96,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
}
fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState)
if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive {
if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive && info.Swarm.LocalNodeState != swarm.LocalNodeStateLocked {
fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID)
if info.Swarm.Error != "" {
fmt.Fprintf(dockerCli.Out(), " Error: %v\n", info.Swarm.Error)