File: network.go

package info (click to toggle)
docker.io 27.5.1%2Bdfsg4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 67,384 kB
  • sloc: sh: 5,847; makefile: 1,146; ansic: 664; python: 162; asm: 133
file content (135 lines) | stat: -rw-r--r-- 3,446 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package opts

import (
	"encoding/csv"
	"errors"
	"fmt"
	"regexp"
	"strings"
)

const (
	networkOptName        = "name"
	networkOptAlias       = "alias"
	networkOptIPv4Address = "ip"
	networkOptIPv6Address = "ip6"
	networkOptMacAddress  = "mac-address"
	networkOptLinkLocalIP = "link-local-ip"
	driverOpt             = "driver-opt"
)

// NetworkAttachmentOpts represents the network options for endpoint creation
type NetworkAttachmentOpts struct {
	Target       string
	Aliases      []string
	DriverOpts   map[string]string
	Links        []string // TODO add support for links in the csv notation of `--network`
	IPv4Address  string
	IPv6Address  string
	LinkLocalIPs []string
	MacAddress   string
}

// NetworkOpt represents a network config in swarm mode.
type NetworkOpt struct {
	options []NetworkAttachmentOpts
}

// Set networkopts value
func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo
	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 {
			// TODO(thaJeztah): these options should not be case-insensitive.
			key, val, ok := strings.Cut(strings.ToLower(field), "=")
			if !ok || key == "" {
				return fmt.Errorf("invalid field %s", field)
			}

			key = strings.TrimSpace(key)
			val = strings.TrimSpace(val)

			switch key {
			case networkOptName:
				netOpt.Target = val
			case networkOptAlias:
				netOpt.Aliases = append(netOpt.Aliases, val)
			case networkOptIPv4Address:
				netOpt.IPv4Address = val
			case networkOptIPv6Address:
				netOpt.IPv6Address = val
			case networkOptMacAddress:
				netOpt.MacAddress = val
			case networkOptLinkLocalIP:
				netOpt.LinkLocalIPs = append(netOpt.LinkLocalIPs, val)
			case driverOpt:
				key, val, err = parseDriverOpt(val)
				if err != nil {
					return err
				}
				if netOpt.DriverOpts == nil {
					netOpt.DriverOpts = make(map[string]string)
				}
				netOpt.DriverOpts[key] = val
			default:
				return errors.New("invalid field key " + key)
			}
		}
		if len(netOpt.Target) == 0 {
			return errors.New("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 ""
}

// 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
}

func parseDriverOpt(driverOpt string) (string, string, error) {
	// 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 == "" {
		return "", "", errors.New("invalid key value pair format in driver options")
	}
	key = strings.TrimSpace(key)
	value = strings.TrimSpace(value)
	return key, value, nil
}