github.com/portworx/docker@v1.12.1/api/client/swarm/opts.go (about)

     1  package swarm
     2  
     3  import (
     4  	"encoding/csv"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/docker/docker/opts"
    11  	"github.com/docker/engine-api/types/swarm"
    12  	"github.com/spf13/pflag"
    13  )
    14  
    15  const (
    16  	defaultListenAddr = "0.0.0.0:2377"
    17  
    18  	flagCertExpiry          = "cert-expiry"
    19  	flagDispatcherHeartbeat = "dispatcher-heartbeat"
    20  	flagListenAddr          = "listen-addr"
    21  	flagAdvertiseAddr       = "advertise-addr"
    22  	flagQuiet               = "quiet"
    23  	flagRotate              = "rotate"
    24  	flagToken               = "token"
    25  	flagTaskHistoryLimit    = "task-history-limit"
    26  	flagExternalCA          = "external-ca"
    27  )
    28  
    29  type swarmOptions struct {
    30  	taskHistoryLimit    int64
    31  	dispatcherHeartbeat time.Duration
    32  	nodeCertExpiry      time.Duration
    33  	externalCA          ExternalCAOption
    34  }
    35  
    36  // NodeAddrOption is a pflag.Value for listen and remote addresses
    37  type NodeAddrOption struct {
    38  	addr string
    39  }
    40  
    41  // String prints the representation of this flag
    42  func (a *NodeAddrOption) String() string {
    43  	return a.Value()
    44  }
    45  
    46  // Set the value for this flag
    47  func (a *NodeAddrOption) Set(value string) error {
    48  	addr, err := opts.ParseTCPAddr(value, a.addr)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	a.addr = addr
    53  	return nil
    54  }
    55  
    56  // Type returns the type of this flag
    57  func (a *NodeAddrOption) Type() string {
    58  	return "node-addr"
    59  }
    60  
    61  // Value returns the value of this option as addr:port
    62  func (a *NodeAddrOption) Value() string {
    63  	return strings.TrimPrefix(a.addr, "tcp://")
    64  }
    65  
    66  // NewNodeAddrOption returns a new node address option
    67  func NewNodeAddrOption(addr string) NodeAddrOption {
    68  	return NodeAddrOption{addr}
    69  }
    70  
    71  // NewListenAddrOption returns a NodeAddrOption with default values
    72  func NewListenAddrOption() NodeAddrOption {
    73  	return NewNodeAddrOption(defaultListenAddr)
    74  }
    75  
    76  // ExternalCAOption is a Value type for parsing external CA specifications.
    77  type ExternalCAOption struct {
    78  	values []*swarm.ExternalCA
    79  }
    80  
    81  // Set parses an external CA option.
    82  func (m *ExternalCAOption) Set(value string) error {
    83  	parsed, err := parseExternalCA(value)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	m.values = append(m.values, parsed)
    89  	return nil
    90  }
    91  
    92  // Type returns the type of this option.
    93  func (m *ExternalCAOption) Type() string {
    94  	return "external-ca"
    95  }
    96  
    97  // String returns a string repr of this option.
    98  func (m *ExternalCAOption) String() string {
    99  	externalCAs := []string{}
   100  	for _, externalCA := range m.values {
   101  		repr := fmt.Sprintf("%s: %s", externalCA.Protocol, externalCA.URL)
   102  		externalCAs = append(externalCAs, repr)
   103  	}
   104  	return strings.Join(externalCAs, ", ")
   105  }
   106  
   107  // Value returns the external CAs
   108  func (m *ExternalCAOption) Value() []*swarm.ExternalCA {
   109  	return m.values
   110  }
   111  
   112  // parseExternalCA parses an external CA specification from the command line,
   113  // such as protocol=cfssl,url=https://example.com.
   114  func parseExternalCA(caSpec string) (*swarm.ExternalCA, error) {
   115  	csvReader := csv.NewReader(strings.NewReader(caSpec))
   116  	fields, err := csvReader.Read()
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	externalCA := swarm.ExternalCA{
   122  		Options: make(map[string]string),
   123  	}
   124  
   125  	var (
   126  		hasProtocol bool
   127  		hasURL      bool
   128  	)
   129  
   130  	for _, field := range fields {
   131  		parts := strings.SplitN(field, "=", 2)
   132  
   133  		if len(parts) != 2 {
   134  			return nil, fmt.Errorf("invalid field '%s' must be a key=value pair", field)
   135  		}
   136  
   137  		key, value := parts[0], parts[1]
   138  
   139  		switch strings.ToLower(key) {
   140  		case "protocol":
   141  			hasProtocol = true
   142  			if strings.ToLower(value) == string(swarm.ExternalCAProtocolCFSSL) {
   143  				externalCA.Protocol = swarm.ExternalCAProtocolCFSSL
   144  			} else {
   145  				return nil, fmt.Errorf("unrecognized external CA protocol %s", value)
   146  			}
   147  		case "url":
   148  			hasURL = true
   149  			externalCA.URL = value
   150  		default:
   151  			externalCA.Options[key] = value
   152  		}
   153  	}
   154  
   155  	if !hasProtocol {
   156  		return nil, errors.New("the external-ca option needs a protocol= parameter")
   157  	}
   158  	if !hasURL {
   159  		return nil, errors.New("the external-ca option needs a url= parameter")
   160  	}
   161  
   162  	return &externalCA, nil
   163  }
   164  
   165  func addSwarmFlags(flags *pflag.FlagSet, opts *swarmOptions) {
   166  	flags.Int64Var(&opts.taskHistoryLimit, flagTaskHistoryLimit, 5, "Task history retention limit")
   167  	flags.DurationVar(&opts.dispatcherHeartbeat, flagDispatcherHeartbeat, time.Duration(5*time.Second), "Dispatcher heartbeat period")
   168  	flags.DurationVar(&opts.nodeCertExpiry, flagCertExpiry, time.Duration(90*24*time.Hour), "Validity period for node certificates")
   169  	flags.Var(&opts.externalCA, flagExternalCA, "Specifications of one or more certificate signing endpoints")
   170  }
   171  
   172  func (opts *swarmOptions) ToSpec() swarm.Spec {
   173  	spec := swarm.Spec{}
   174  	spec.Orchestration.TaskHistoryRetentionLimit = opts.taskHistoryLimit
   175  	spec.Dispatcher.HeartbeatPeriod = uint64(opts.dispatcherHeartbeat.Nanoseconds())
   176  	spec.CAConfig.NodeCertExpiry = opts.nodeCertExpiry
   177  	spec.CAConfig.ExternalCAs = opts.externalCA.Value()
   178  	return spec
   179  }