From e9140601f5bfcc4cefb8b77f849db83980d963d1 Mon Sep 17 00:00:00 2001 From: Turo Soisenniemi Date: Sat, 23 Jun 2018 13:53:51 +0300 Subject: [PATCH] Initial implementation for backwards compatible multinic in openstack Signed-off-by: Turo Soisenniemi --- .gitlab-ci.yml | 1 - drivers/openstack/client.go | 42 +++++++++---- drivers/openstack/openstack.go | 27 ++++----- drivers/openstack/openstack_test.go | 92 +++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 26 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0fa77afb25..bc93f4279d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,7 +29,6 @@ before_script: expire_in: 1 week tags: - docker - - privileged .build_validate: &build_validate <<: *build_base diff --git a/drivers/openstack/client.go b/drivers/openstack/client.go index 8b47b86e49..b413d65bc3 100644 --- a/drivers/openstack/client.go +++ b/drivers/openstack/client.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "time" "github.com/docker/machine/libmachine/log" @@ -72,11 +73,12 @@ func (c *GenericClient) CreateInstance(d *Driver) (string, error) { Metadata: d.GetMetadata(), } if d.NetworkId != "" { - serverOpts.Networks = []servers.Network{ - { - UUID: d.NetworkId, - }, + networkIDs := strings.Split(d.NetworkId, ",") + networks := make([]servers.Network, len(networkIDs)) + for i, id := range networkIDs { + networks[i] = servers.Network{UUID: id} } + serverOpts.Networks = networks } log.Info("Creating machine...") @@ -212,10 +214,21 @@ func (c *GenericClient) GetFloatingIPPoolID(d *Driver) (string, error) { return c.getNetworkID(d, d.FloatingIpPool) } +func Contains(slice []string, element string) (bool, int) { + for i, e := range slice { + if e == element { + return true, i + } + } + return false, -1 +} + func (c *GenericClient) getNetworkID(d *Driver, networkName string) (string, error) { opts := networks.ListOpts{Name: networkName} pager := networks.List(c.Network, opts) - networkID := "" + networkNames := strings.Split(networkName, ",") + remainingNetworks := len(networkNames) + networkID := make([]string, remainingNetworks) err := pager.EachPage(func(page pagination.Page) (bool, error) { networkList, err := networks.ExtractNetworks(page) @@ -224,16 +237,25 @@ func (c *GenericClient) getNetworkID(d *Driver, networkName string) (string, err } for _, n := range networkList { - if n.Name == networkName { - networkID = n.ID - return false, nil + match, index := Contains(networkNames, n.Name) + if match { + networkID[index] = n.ID + remainingNetworks-- + + if remainingNetworks == 0 { + return false, nil + } } } return true, nil }) - return networkID, err + if remainingNetworks != 0 { + return "", err + } + + return strings.Join(networkID, ","), err } func (c *GenericClient) GetFlavorID(d *Driver) (string, error) { @@ -454,7 +476,7 @@ func (c *GenericClient) getNeutronNetworkFloatingIPs(d *Driver) ([]FloatingIP, e func (c *GenericClient) GetInstancePortID(d *Driver) (string, error) { pager := ports.List(c.Network, ports.ListOpts{ DeviceID: d.MachineId, - NetworkID: d.NetworkId, + NetworkID: strings.Split(d.NetworkId, ",")[0], }) var portID string diff --git a/drivers/openstack/openstack.go b/drivers/openstack/openstack.go index 7e305d840a..4be92455d8 100644 --- a/drivers/openstack/openstack.go +++ b/drivers/openstack/openstack.go @@ -164,11 +164,11 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { Usage: "OpenStack keypair to use to SSH to the instance", Value: "", }, - mcnflag.StringFlag{ + mcnflag.StringSliceFlag{ EnvVar: "OS_NETWORK_ID", Name: "openstack-net-id", Usage: "OpenStack network id the machine will be connected on", - Value: "", + Value: []string{}, }, mcnflag.StringFlag{ EnvVar: "OS_PRIVATE_KEY_FILE", @@ -182,11 +182,11 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { Usage: "File containing an openstack userdata script", Value: "", }, - mcnflag.StringFlag{ + mcnflag.StringSliceFlag{ EnvVar: "OS_NETWORK_NAME", Name: "openstack-net-name", Usage: "OpenStack network name the machine will be connected on", - Value: "", + Value: []string{}, }, mcnflag.StringFlag{ EnvVar: "OS_SECURITY_GROUPS", @@ -202,7 +202,7 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { mcnflag.StringFlag{ EnvVar: "OS_FLOATINGIP_POOL", Name: "openstack-floatingip-pool", - Usage: "OpenStack floating IP pool to get an IP from to assign to the instance", + Usage: "OpenStack floating IP pool to get an IP from to assign to the instance (first network only)", Value: "", }, mcnflag.IntFlag{ @@ -291,8 +291,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.FlavorName = flags.String("openstack-flavor-name") d.ImageId = flags.String("openstack-image-id") d.ImageName = flags.String("openstack-image-name") - d.NetworkId = flags.String("openstack-net-id") - d.NetworkName = flags.String("openstack-net-name") + d.NetworkId = strings.Join(flags.StringSlice("openstack-net-id"), ",") + d.NetworkName = strings.Join(flags.StringSlice("openstack-net-name"), ",") d.metadata = flags.String("openstack-metadata") if flags.String("openstack-sec-groups") != "" { d.SecurityGroups = strings.Split(flags.String("openstack-sec-groups"), ",") @@ -553,7 +553,7 @@ func (d *Driver) checkConfig() error { } if d.NetworkName != "" && d.NetworkId != "" { - return fmt.Errorf(errorExclusiveOptions, "Network name", "Network id") + return fmt.Errorf(errorExclusiveOptions, "Network names", "Network ids") } if d.EndpointType != "" && (d.EndpointType != "publicURL" && d.EndpointType != "adminURL" && d.EndpointType != "internalURL") { return fmt.Errorf(errorWrongEndpointType) @@ -570,21 +570,18 @@ func (d *Driver) resolveIds() error { return err } - networkID, err := d.client.GetNetworkID(d) + networkIDs, err := d.client.GetNetworkID(d) if err != nil { return err } - if networkID == "" { + if networkIDs == "" { return fmt.Errorf(errorUnknownNetworkName, d.NetworkName) } - d.NetworkId = networkID - log.Debug("Found network id using its name", map[string]string{ - "Name": d.NetworkName, - "ID": d.NetworkId, - }) + d.NetworkId = networkIDs + //TODO: log found networks? } if d.FlavorName != "" { diff --git a/drivers/openstack/openstack_test.go b/drivers/openstack/openstack_test.go index 49134c0855..cd31b42eb7 100644 --- a/drivers/openstack/openstack_test.go +++ b/drivers/openstack/openstack_test.go @@ -27,3 +27,95 @@ func TestSetConfigFromFlags(t *testing.T) { assert.NoError(t, err) assert.Empty(t, checkFlags.InvalidFlags) } + +func TestSetSingleNetworkId(t *testing.T) { + driver := NewDriver("default", "path") + + checkFlags := &drivers.CheckDriverOptions{ + FlagsValues: map[string]interface{}{ + "openstack-auth-url": "http://url", + "openstack-username": "user", + "openstack-password": "pwd", + "openstack-tenant-id": "ID", + "openstack-flavor-id": "ID", + "openstack-image-id": "ID", + "openstack-net-id": "ID", + }, + CreateFlags: driver.GetCreateFlags(), + } + + err := driver.SetConfigFromFlags(checkFlags) + + assert.NoError(t, err) + assert.Empty(t, checkFlags.InvalidFlags) +} + +func TestSetSingleNetworkName(t *testing.T) { + driver := NewDriver("default", "path") + + checkFlags := &drivers.CheckDriverOptions{ + FlagsValues: map[string]interface{}{ + "openstack-auth-url": "http://url", + "openstack-username": "user", + "openstack-password": "pwd", + "openstack-tenant-id": "ID", + "openstack-flavor-id": "ID", + "openstack-image-id": "ID", + "openstack-net-name": "ID", + }, + CreateFlags: driver.GetCreateFlags(), + } + + err := driver.SetConfigFromFlags(checkFlags) + + assert.NoError(t, err) + assert.Empty(t, checkFlags.InvalidFlags) +} + +func TestSetMultipleNetworkIds(t *testing.T) { + driver := NewDriver("default", "path") + + checkFlags := &drivers.CheckDriverOptions{ + FlagsValues: map[string]interface{}{ + "openstack-auth-url": "http://url", + "openstack-username": "user", + "openstack-password": "pwd", + "openstack-tenant-id": "ID", + "openstack-flavor-id": "ID", + "openstack-image-id": "ID", + //TODO: multivalue test + //"openstack-net-id": "ID", + "openstack-net-id": "ID2", + }, + CreateFlags: driver.GetCreateFlags(), + } + + err := driver.SetConfigFromFlags(checkFlags) + + assert.NoError(t, err) + assert.Empty(t, checkFlags.InvalidFlags) +} + +func TestSetMultipleNetworkNames(t *testing.T) { + driver := NewDriver("default", "path") + + checkFlags := &drivers.CheckDriverOptions{ + FlagsValues: map[string]interface{}{ + "openstack-auth-url": "http://url", + "openstack-username": "user", + "openstack-password": "pwd", + "openstack-tenant-id": "ID", + "openstack-flavor-id": "ID", + "openstack-image-id": "ID", + "openstack-net-name": "ID", + //TODO: multivalue test + //"openstack-net-name": "ID2", + }, + CreateFlags: driver.GetCreateFlags(), + } + + err := driver.SetConfigFromFlags(checkFlags) + + assert.NoError(t, err) + assert.Empty(t, checkFlags.InvalidFlags) +}