2016-06-13 19:56:23 -07:00
package swarm
import (
2016-06-30 14:39:39 -07:00
"encoding/csv"
"errors"
2016-06-13 19:56:23 -07:00
"fmt"
"strings"
2016-06-21 14:27:04 -07:00
"time"
2016-06-13 19:56:23 -07:00
2016-09-06 11:18:12 -07:00
"github.com/docker/docker/api/types/swarm"
2016-06-21 14:27:04 -07:00
"github.com/docker/docker/opts"
"github.com/spf13/pflag"
2016-06-13 19:56:23 -07:00
)
const (
2016-06-21 14:27:04 -07:00
defaultListenAddr = "0.0.0.0:2377"
2016-06-29 14:01:25 -07:00
2016-06-17 15:42:16 -04:00
flagCertExpiry = "cert-expiry"
flagDispatcherHeartbeat = "dispatcher-heartbeat"
flagListenAddr = "listen-addr"
2016-06-30 18:07:35 -07:00
flagAdvertiseAddr = "advertise-addr"
2016-07-27 16:14:29 +02:00
flagQuiet = "quiet"
flagRotate = "rotate"
2016-07-20 11:15:08 -07:00
flagToken = "token"
2016-06-17 15:42:16 -04:00
flagTaskHistoryLimit = "task-history-limit"
2016-06-30 14:39:39 -07:00
flagExternalCA = "external-ca"
2016-11-02 12:29:51 -07:00
flagMaxSnapshots = "max-snapshots"
flagSnapshotInterval = "snapshot-interval"
2016-10-21 18:07:55 -07:00
flagLockKey = "lock-key"
2016-10-27 18:50:49 -07:00
flagAutolock = "autolock"
2016-06-13 19:56:23 -07:00
)
2016-06-21 14:27:04 -07:00
type swarmOptions struct {
taskHistoryLimit int64
dispatcherHeartbeat time . Duration
nodeCertExpiry time . Duration
2016-06-30 14:39:39 -07:00
externalCA ExternalCAOption
2016-11-02 12:29:51 -07:00
maxSnapshots uint64
snapshotInterval uint64
2016-10-27 18:50:49 -07:00
autolock bool
2016-06-21 14:27:04 -07:00
}
2016-11-02 03:11:38 +08:00
// NodeAddrOption is a pflag.Value for listening addresses
2016-06-13 19:56:23 -07:00
type NodeAddrOption struct {
addr string
}
// String prints the representation of this flag
func ( a * NodeAddrOption ) String ( ) string {
2016-06-17 15:42:16 -04:00
return a . Value ( )
2016-06-13 19:56:23 -07:00
}
// Set the value for this flag
func ( a * NodeAddrOption ) Set ( value string ) error {
2016-06-21 14:27:04 -07:00
addr , err := opts . ParseTCPAddr ( value , a . addr )
2016-06-17 15:42:16 -04:00
if err != nil {
2016-06-21 14:27:04 -07:00
return err
2016-06-17 15:42:16 -04:00
}
2016-06-21 14:27:04 -07:00
a . addr = addr
2016-06-13 19:56:23 -07:00
return nil
}
// Type returns the type of this flag
func ( a * NodeAddrOption ) Type ( ) string {
return "node-addr"
}
2016-06-17 15:42:16 -04:00
// Value returns the value of this option as addr:port
func ( a * NodeAddrOption ) Value ( ) string {
2016-06-21 14:27:04 -07:00
return strings . TrimPrefix ( a . addr , "tcp://" )
2016-06-17 15:42:16 -04:00
}
2016-06-13 19:56:23 -07:00
// NewNodeAddrOption returns a new node address option
2016-06-21 14:27:04 -07:00
func NewNodeAddrOption ( addr string ) NodeAddrOption {
return NodeAddrOption { addr }
2016-06-17 15:42:16 -04:00
}
// NewListenAddrOption returns a NodeAddrOption with default values
func NewListenAddrOption ( ) NodeAddrOption {
2016-06-21 14:27:04 -07:00
return NewNodeAddrOption ( defaultListenAddr )
2016-06-13 19:56:23 -07:00
}
2016-06-30 14:39:39 -07:00
// ExternalCAOption is a Value type for parsing external CA specifications.
type ExternalCAOption struct {
values [ ] * swarm . ExternalCA
}
// Set parses an external CA option.
func ( m * ExternalCAOption ) Set ( value string ) error {
parsed , err := parseExternalCA ( value )
if err != nil {
return err
}
m . values = append ( m . values , parsed )
return nil
}
// Type returns the type of this option.
func ( m * ExternalCAOption ) Type ( ) string {
return "external-ca"
}
// String returns a string repr of this option.
func ( m * ExternalCAOption ) String ( ) string {
externalCAs := [ ] string { }
for _ , externalCA := range m . values {
repr := fmt . Sprintf ( "%s: %s" , externalCA . Protocol , externalCA . URL )
externalCAs = append ( externalCAs , repr )
}
return strings . Join ( externalCAs , ", " )
}
// Value returns the external CAs
func ( m * ExternalCAOption ) Value ( ) [ ] * swarm . ExternalCA {
return m . values
}
// parseExternalCA parses an external CA specification from the command line,
// such as protocol=cfssl,url=https://example.com.
func parseExternalCA ( caSpec string ) ( * swarm . ExternalCA , error ) {
csvReader := csv . NewReader ( strings . NewReader ( caSpec ) )
fields , err := csvReader . Read ( )
if err != nil {
return nil , err
}
externalCA := swarm . ExternalCA {
Options : make ( map [ string ] string ) ,
}
var (
hasProtocol bool
hasURL bool
)
for _ , field := range fields {
parts := strings . SplitN ( field , "=" , 2 )
if len ( parts ) != 2 {
return nil , fmt . Errorf ( "invalid field '%s' must be a key=value pair" , field )
}
key , value := parts [ 0 ] , parts [ 1 ]
switch strings . ToLower ( key ) {
case "protocol" :
hasProtocol = true
if strings . ToLower ( value ) == string ( swarm . ExternalCAProtocolCFSSL ) {
externalCA . Protocol = swarm . ExternalCAProtocolCFSSL
} else {
return nil , fmt . Errorf ( "unrecognized external CA protocol %s" , value )
}
case "url" :
hasURL = true
externalCA . URL = value
default :
externalCA . Options [ key ] = value
}
}
if ! hasProtocol {
return nil , errors . New ( "the external-ca option needs a protocol= parameter" )
}
if ! hasURL {
return nil , errors . New ( "the external-ca option needs a url= parameter" )
}
return & externalCA , nil
}
2016-06-21 14:27:04 -07:00
func addSwarmFlags ( flags * pflag . FlagSet , opts * swarmOptions ) {
2016-07-22 18:09:54 -07:00
flags . Int64Var ( & opts . taskHistoryLimit , flagTaskHistoryLimit , 5 , "Task history retention limit" )
2016-10-25 12:22:07 +00:00
flags . DurationVar ( & opts . dispatcherHeartbeat , flagDispatcherHeartbeat , time . Duration ( 5 * time . Second ) , "Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s)" )
flags . DurationVar ( & opts . nodeCertExpiry , flagCertExpiry , time . Duration ( 90 * 24 * time . Hour ) , "Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s)" )
2016-06-30 14:39:39 -07:00
flags . Var ( & opts . externalCA , flagExternalCA , "Specifications of one or more certificate signing endpoints" )
2016-11-02 12:29:51 -07:00
flags . Uint64Var ( & opts . maxSnapshots , flagMaxSnapshots , 0 , "Number of additional Raft snapshots to retain" )
flags . Uint64Var ( & opts . snapshotInterval , flagSnapshotInterval , 10000 , "Number of log entries between Raft snapshots" )
2016-06-21 14:27:04 -07:00
}
2016-11-02 12:29:51 -07:00
func ( opts * swarmOptions ) mergeSwarmSpec ( spec * swarm . Spec , flags * pflag . FlagSet ) {
2016-08-25 21:08:53 -07:00
if flags . Changed ( flagTaskHistoryLimit ) {
spec . Orchestration . TaskHistoryRetentionLimit = & opts . taskHistoryLimit
}
if flags . Changed ( flagDispatcherHeartbeat ) {
spec . Dispatcher . HeartbeatPeriod = opts . dispatcherHeartbeat
}
if flags . Changed ( flagCertExpiry ) {
spec . CAConfig . NodeCertExpiry = opts . nodeCertExpiry
}
if flags . Changed ( flagExternalCA ) {
spec . CAConfig . ExternalCAs = opts . externalCA . Value ( )
}
2016-11-02 12:29:51 -07:00
if flags . Changed ( flagMaxSnapshots ) {
spec . Raft . KeepOldSnapshots = & opts . maxSnapshots
}
if flags . Changed ( flagSnapshotInterval ) {
spec . Raft . SnapshotInterval = opts . snapshotInterval
}
2016-10-27 18:50:49 -07:00
if flags . Changed ( flagAutolock ) {
spec . EncryptionConfig . AutoLockManagers = opts . autolock
}
2016-11-02 12:29:51 -07:00
}
func ( opts * swarmOptions ) ToSpec ( flags * pflag . FlagSet ) swarm . Spec {
var spec swarm . Spec
opts . mergeSwarmSpec ( & spec , flags )
2016-06-21 14:27:04 -07:00
return spec
}