2017-05-15 20:02:04 -04:00
|
|
|
package opts
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/csv"
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-04-03 08:37:26 -04:00
|
|
|
networkOptName = "name"
|
|
|
|
networkOptAlias = "alias"
|
|
|
|
networkOptIPv4Address = "ip"
|
|
|
|
networkOptIPv6Address = "ip6"
|
|
|
|
driverOpt = "driver-opt"
|
2017-05-15 20:02:04 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// NetworkAttachmentOpts represents the network options for endpoint creation
|
|
|
|
type NetworkAttachmentOpts struct {
|
2019-03-20 12:53:44 -04:00
|
|
|
Target string
|
|
|
|
Aliases []string
|
|
|
|
DriverOpts map[string]string
|
|
|
|
Links []string // TODO add support for links in the csv notation of `--network`
|
2019-04-03 08:37:26 -04:00
|
|
|
IPv4Address string
|
|
|
|
IPv6Address string
|
2019-03-20 12:53:44 -04:00
|
|
|
LinkLocalIPs []string // TODO add support for LinkLocalIPs in the csv notation of `--network` ?
|
2017-05-15 20:02:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// NetworkOpt represents a network config in swarm mode.
|
|
|
|
type NetworkOpt struct {
|
|
|
|
options []NetworkAttachmentOpts
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set networkopts value
|
|
|
|
func (n *NetworkOpt) Set(value string) error {
|
|
|
|
longSyntax, err := regexp.MatchString(`\w+=\w+(,\w+=\w+)*`, value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var netOpt NetworkAttachmentOpts
|
|
|
|
if longSyntax {
|
|
|
|
csvReader := csv.NewReader(strings.NewReader(value))
|
|
|
|
fields, err := csvReader.Read()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
netOpt.Aliases = []string{}
|
|
|
|
for _, field := range fields {
|
2022-12-27 10:24:23 -05:00
|
|
|
// TODO(thaJeztah): these options should not be case-insensitive.
|
|
|
|
key, val, ok := strings.Cut(strings.ToLower(field), "=")
|
|
|
|
if !ok || key == "" {
|
2017-05-15 20:02:04 -04:00
|
|
|
return fmt.Errorf("invalid field %s", field)
|
|
|
|
}
|
|
|
|
|
2022-12-27 10:24:23 -05:00
|
|
|
key = strings.TrimSpace(key)
|
|
|
|
val = strings.TrimSpace(val)
|
2017-05-15 20:02:04 -04:00
|
|
|
|
|
|
|
switch key {
|
|
|
|
case networkOptName:
|
2022-12-27 10:24:23 -05:00
|
|
|
netOpt.Target = val
|
2017-05-15 20:02:04 -04:00
|
|
|
case networkOptAlias:
|
2022-12-27 10:24:23 -05:00
|
|
|
netOpt.Aliases = append(netOpt.Aliases, val)
|
2019-04-03 08:37:26 -04:00
|
|
|
case networkOptIPv4Address:
|
2022-12-27 10:24:23 -05:00
|
|
|
netOpt.IPv4Address = val
|
2019-04-03 08:37:26 -04:00
|
|
|
case networkOptIPv6Address:
|
2022-12-27 10:24:23 -05:00
|
|
|
netOpt.IPv6Address = val
|
2017-05-15 20:02:04 -04:00
|
|
|
case driverOpt:
|
2022-12-27 10:24:23 -05:00
|
|
|
key, val, err = parseDriverOpt(val)
|
|
|
|
if err != nil {
|
2017-05-15 20:02:04 -04:00
|
|
|
return err
|
|
|
|
}
|
2022-12-27 10:24:23 -05:00
|
|
|
if netOpt.DriverOpts == nil {
|
|
|
|
netOpt.DriverOpts = make(map[string]string)
|
|
|
|
}
|
|
|
|
netOpt.DriverOpts[key] = val
|
2017-05-15 20:02:04 -04:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("invalid field key %s", key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(netOpt.Target) == 0 {
|
|
|
|
return fmt.Errorf("network name/id is not specified")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
netOpt.Target = value
|
|
|
|
}
|
|
|
|
n.options = append(n.options, netOpt)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type returns the type of this option
|
|
|
|
func (n *NetworkOpt) Type() string {
|
|
|
|
return "network"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Value returns the networkopts
|
|
|
|
func (n *NetworkOpt) Value() []NetworkAttachmentOpts {
|
|
|
|
return n.options
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the network opts as a string
|
|
|
|
func (n *NetworkOpt) String() string {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2017-07-10 16:44:45 -04:00
|
|
|
// NetworkMode return the network mode for the network option
|
|
|
|
func (n *NetworkOpt) NetworkMode() string {
|
|
|
|
networkIDOrName := "default"
|
|
|
|
netOptVal := n.Value()
|
|
|
|
if len(netOptVal) > 0 {
|
|
|
|
networkIDOrName = netOptVal[0].Target
|
|
|
|
}
|
|
|
|
return networkIDOrName
|
|
|
|
}
|
|
|
|
|
2017-10-12 11:44:03 -04:00
|
|
|
func parseDriverOpt(driverOpt string) (string, string, error) {
|
2022-12-27 10:24:23 -05:00
|
|
|
// TODO(thaJeztah): these options should not be case-insensitive.
|
|
|
|
// TODO(thaJeztah): should value be converted to lowercase as well, or only the key?
|
|
|
|
key, value, ok := strings.Cut(strings.ToLower(driverOpt), "=")
|
|
|
|
if !ok || key == "" {
|
2017-10-12 11:44:03 -04:00
|
|
|
return "", "", fmt.Errorf("invalid key value pair format in driver options")
|
2017-05-15 20:02:04 -04:00
|
|
|
}
|
2022-12-27 10:24:23 -05:00
|
|
|
key = strings.TrimSpace(key)
|
|
|
|
value = strings.TrimSpace(value)
|
2017-10-12 11:44:03 -04:00
|
|
|
return key, value, nil
|
2017-05-15 20:02:04 -04:00
|
|
|
}
|