MAAS spaces multi nic containers lxd (wip) #4789

Closed
wants to merge 4 commits into
from
Next

container/lxd: switch from default profile to custom network profile

Use the supplied network configuration when creating a container. This
switches away from just using the "default" LXD profile which has one
NIC and creates a custom profile based on the containers' networking
setup.

For example:

$ lxc profile show juju-machine-0-lxd-1-network
name: juju-machine-0-lxd-1-network
config: {}
description: ""
devices:
  eth0:
    mtu: "1500"
    name: eth0
    nictype: bridged
    parent: br-eth0
    type: nic
    hwaddr: 00:16:3e:83:c0:3e
  eth1:
    mtu: "1500"
    name: eth1
    nictype: bridged
    parent: br-eth0.10
    type: nic
    hwaddr: 00:16:3e:d6:3b:bf
  eth2:
    mtu: "1500"
    name: eth2
    nictype: bridged
    parent: br-eth0.11
    type: nic
    hwaddr: 00:16:3e:28:1a:dc
  eth3:
    mtu: "1500"
    name: eth3
    nictype: bridged
    parent: br-eth0.12
    type: nic
    hwaddr: 00:16:3e:98:8a:a8

A new profile will be created per container as the MAC addresses will be
different. And the relationship with eth<N> and the parent device may
also be different.

This changes realises multi-NIC container support for LXD and is
dependent on the maas-spaces-multi-nic-containers branch.
  • Loading branch information...
commit 417c8fd67b40eac734a815707104bfc3c8657af5 Andrew McDermott committed Mar 18, 2016
View
@@ -16,6 +16,7 @@ import (
"github.com/juju/juju/cloudconfig/instancecfg"
"github.com/juju/juju/container"
"github.com/juju/juju/instance"
+ "github.com/juju/juju/network"
"github.com/juju/juju/status"
"github.com/juju/juju/tools/lxdclient"
)
@@ -116,12 +117,19 @@ func (manager *containerManager) CreateContainer(
"boot.autostart": "true",
}
+ networkProfile := fmt.Sprintf("%s-network", name)
+
+ err = manager.createNetworkProfile(networkProfile, networkConfig)
+ if err != nil {
+ return
+ }
+
spec := lxdclient.InstanceSpec{
Name: name,
Image: manager.client.ImageNameForSeries(series),
Metadata: metadata,
Profiles: []string{
- "default",
+ networkProfile,
},
}
@@ -186,3 +194,53 @@ func (manager *containerManager) IsInitialized() bool {
func HasLXDSupport() bool {
return true
}
+
+func (manager *containerManager) createNetworkProfile(profile string, networkConfig *container.NetworkConfig) error {
+ found, err := manager.client.HasProfile(profile)
+
+ if err != nil {
+ return err
+ }
+
+ if found {
+ logger.Infof("deleting existing profile %q", profile)
+ if err := manager.client.ProfileDelete(profile); err != nil {
+ return err
+ }
+ }
+
+ if err := manager.client.CreateProfile(profile, nil); err != nil {
+ return err
+ }
+
+ for _, v := range networkConfig.Interfaces {
+ if v.InterfaceType == network.LoopbackInterface {
+ continue
+ }
+
+ if v.InterfaceType != network.EthernetInterface {
+ return errors.Errorf("interface type %q not supported", v.InterfaceType)
+ }
+
+ var props = []string{}
+ props = append(props, "nictype=bridged")
+ props = append(props, fmt.Sprintf("parent=%v", v.ParentInterfaceName))
+ props = append(props, fmt.Sprintf("name=%v", v.InterfaceName))
+
+ if v.MACAddress != "" {
+ props = append(props, fmt.Sprintf("hwaddr=%v", v.MACAddress))
+ }
+
+ if v.MTU > 0 {
+ props = append(props, fmt.Sprintf("mtu=%v", v.MTU))
+ }
+
+ _, err := manager.client.ProfileDeviceAdd(profile, v.InterfaceName, "nic", props)
+
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
@@ -7,18 +7,41 @@ package lxdclient
import (
"github.com/juju/errors"
+ "github.com/lxc/lxd"
)
type rawProfileClient interface {
ProfileCreate(name string) error
ListProfiles() ([]string, error)
SetProfileConfigItem(name, key, value string) error
+ ProfileDelete(profile string) error
+ ProfileDeviceAdd(profile, devname, devtype string, props []string) (*lxd.Response, error)
}
type profileClient struct {
raw rawProfileClient
}
+// ProfileDelete deletes an existing profile. No check is made to
+// verify the profile exists.
+func (p profileClient) ProfileDelete(profile string) error {
+ if err := p.raw.ProfileDelete(profile); err != nil {
+ return errors.Trace(err)
+ }
+ return nil
+}
+
+// ProfileDeviceAdd adds a profile device, such as a disk or a nic, to
+// the specified profile. No check is made to verify the profile
+// exists.
+func (p profileClient) ProfileDeviceAdd(profile, devname, devtype string, props []string) (*lxd.Response, error) {
+ resp, err := p.raw.ProfileDeviceAdd(profile, devname, devtype, props)
+ if err != nil {
+ return resp, errors.Trace(err)
+ }
+ return resp, err
+}
+
// CreateProfile attempts to create a new lxc profile and set the given config.
func (p profileClient) CreateProfile(name string, config map[string]string) error {
if err := p.raw.ProfileCreate(name); err != nil {