From 0893ab85602f155d6c3762e9bc2edfb2b5517a97 Mon Sep 17 00:00:00 2001 From: Abhinandan Prativadi Date: Mon, 15 May 2017 17:02:04 -0700 Subject: [PATCH] moving opts to cli repo Signed-off-by: Abhinandan Prativadi --- opts/network.go | 106 +++++++++++++++++++++++++++++++++++++++++++ opts/network_test.go | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 opts/network.go create mode 100644 opts/network_test.go diff --git a/opts/network.go b/opts/network.go new file mode 100644 index 0000000000..317a7ac51e --- /dev/null +++ b/opts/network.go @@ -0,0 +1,106 @@ +package opts + +import ( + "encoding/csv" + "fmt" + "regexp" + "strings" +) + +const ( + networkOptName = "name" + networkOptAlias = "alias" + driverOpt = "driver-opt" +) + +// NetworkAttachmentOpts represents the network options for endpoint creation +type NetworkAttachmentOpts struct { + Target string + Aliases []string + DriverOpts map[string]string +} + +// 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 { + parts := strings.SplitN(field, "=", 2) + + if len(parts) < 2 { + return fmt.Errorf("invalid field %s", field) + } + + key := strings.TrimSpace(strings.ToLower(parts[0])) + value := strings.TrimSpace(strings.ToLower(parts[1])) + + switch key { + case networkOptName: + netOpt.Target = value + case networkOptAlias: + netOpt.Aliases = append(netOpt.Aliases, value) + case driverOpt: + key, value, err = parseDriverOpt(value) + if err == nil { + if netOpt.DriverOpts == nil { + netOpt.DriverOpts = make(map[string]string) + } + netOpt.DriverOpts[key] = value + } else { + return err + } + 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 "" +} + +func parseDriverOpt(driverOpt string) (key string, value string, err error) { + parts := strings.SplitN(driverOpt, "=", 2) + if len(parts) != 2 { + err = fmt.Errorf("invalid key value pair format in driver options") + } + key = strings.TrimSpace(strings.ToLower(parts[0])) + value = strings.TrimSpace(strings.ToLower(parts[1])) + return +} diff --git a/opts/network_test.go b/opts/network_test.go new file mode 100644 index 0000000000..ac0b2115a1 --- /dev/null +++ b/opts/network_test.go @@ -0,0 +1,100 @@ +package opts + +import ( + "testing" + + "github.com/docker/docker/pkg/testutil" + "github.com/stretchr/testify/assert" +) + +func TestNetworkOptLegacySyntax(t *testing.T) { + testCases := []struct { + value string + expected []NetworkAttachmentOpts + }{ + { + value: "docknet1", + expected: []NetworkAttachmentOpts{ + { + Target: "docknet1", + }, + }, + }, + } + for _, tc := range testCases { + var network NetworkOpt + assert.NoError(t, network.Set(tc.value)) + assert.Equal(t, tc.expected, network.Value()) + } +} + +func TestNetworkOptCompleteSyntax(t *testing.T) { + testCases := []struct { + value string + expected []NetworkAttachmentOpts + }{ + { + value: "name=docknet1,alias=web,driver-opt=field1=value1", + expected: []NetworkAttachmentOpts{ + { + Target: "docknet1", + Aliases: []string{"web"}, + DriverOpts: map[string]string{ + "field1": "value1", + }, + }, + }, + }, + { + value: "name=docknet1,alias=web1,alias=web2,driver-opt=field1=value1,driver-opt=field2=value2", + expected: []NetworkAttachmentOpts{ + { + Target: "docknet1", + Aliases: []string{"web1", "web2"}, + DriverOpts: map[string]string{ + "field1": "value1", + "field2": "value2", + }, + }, + }, + }, + { + value: "name=docknet1", + expected: []NetworkAttachmentOpts{ + { + Target: "docknet1", + Aliases: []string{}, + }, + }, + }, + } + for _, tc := range testCases { + var network NetworkOpt + assert.NoError(t, network.Set(tc.value)) + assert.Equal(t, tc.expected, network.Value()) + } +} + +func TestNetworkOptInvalidSyntax(t *testing.T) { + testCases := []struct { + value string + expectedError string + }{ + { + value: "invalidField=docknet1", + expectedError: "invalid field", + }, + { + value: "network=docknet1,invalid=web", + expectedError: "invalid field", + }, + { + value: "driver-opt=field1=value1,driver-opt=field2=value2", + expectedError: "network name/id is not specified", + }, + } + for _, tc := range testCases { + var network NetworkOpt + testutil.ErrorContains(t, network.Set(tc.value), tc.expectedError) + } +}