[lxc-devel] [lxd/master] MAAS tweaks

stgraber on Github lxc-bot at linuxcontainers.org
Tue Jun 2 21:19:58 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200602/752d7e67/attachment-0001.bin>
-------------- next part --------------
From 7029429c943eca979de229a234ea12ed8916d2b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 1 Jun 2020 14:08:21 -0400
Subject: [PATCH 1/3] lxd/maas: Fix support for multiple subnets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/maas/controller.go | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/lxd/maas/controller.go b/lxd/maas/controller.go
index 07390a74db..52d01774b7 100644
--- a/lxd/maas/controller.go
+++ b/lxd/maas/controller.go
@@ -153,13 +153,15 @@ func (c *Controller) CreateContainer(name string, interfaces []ContainerInterfac
 	}
 
 	for _, iface := range interfaces {
-		if len(iface.Subnets) != 1 {
+		if len(iface.Subnets) < 1 {
 			return fmt.Errorf("Bad subnet provided for interface '%s'", iface.Name)
 		}
 
-		_, ok := subnets[iface.Subnets[0].Name]
-		if !ok {
-			return fmt.Errorf("Subnet '%s' doesn't exist in MAAS", interfaces[0].Subnets[0].Name)
+		for _, subnet := range iface.Subnets {
+			_, ok := subnets[subnet.Name]
+			if !ok {
+				return fmt.Errorf("Subnet '%s' doesn't exist in MAAS", interfaces[0].Subnets[0].Name)
+			}
 		}
 	}
 
@@ -266,13 +268,15 @@ func (c *Controller) UpdateContainer(name string, interfaces []ContainerInterfac
 	}
 
 	for _, iface := range interfaces {
-		if len(iface.Subnets) != 1 {
+		if len(iface.Subnets) < 1 {
 			return fmt.Errorf("Bad subnet provided for interface '%s'", iface.Name)
 		}
 
-		_, ok := subnets[iface.Subnets[0].Name]
-		if !ok {
-			return fmt.Errorf("Subnet '%s' doesn't exist in MAAS", interfaces[0].Subnets[0].Name)
+		for _, subnet := range iface.Subnets {
+			_, ok := subnets[subnet.Name]
+			if !ok {
+				return fmt.Errorf("Subnet '%s' doesn't exist in MAAS", interfaces[0].Subnets[0].Name)
+			}
 		}
 	}
 

From c7eda13f2ae63f382cb3009d07d3e2c416adadf8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 1 Jun 2020 14:23:25 -0400
Subject: [PATCH 2/3] lxd/maas: Support projects
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/instance/drivers/driver_lxc.go  | 16 ++++-----
 lxd/instance/drivers/driver_qemu.go | 16 ++++-----
 lxd/maas/controller.go              | 55 +++++++++++++++++++++--------
 3 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/lxd/instance/drivers/driver_lxc.go b/lxd/instance/drivers/driver_lxc.go
index bbf0394b0c..ec483f9fe2 100644
--- a/lxd/instance/drivers/driver_lxc.go
+++ b/lxd/instance/drivers/driver_lxc.go
@@ -6860,20 +6860,20 @@ func (c *lxc) maasUpdate(oldDevices map[string]map[string]string) error {
 		return fmt.Errorf("Can't perform the operation because MAAS is currently unavailable")
 	}
 
-	exists, err := c.state.MAAS.DefinedContainer(project.Instance(c.project, c.name))
+	exists, err := c.state.MAAS.DefinedContainer(c)
 	if err != nil {
 		return err
 	}
 
 	if exists {
 		if len(interfaces) == 0 && len(oldInterfaces) > 0 {
-			return c.state.MAAS.DeleteContainer(project.Instance(c.project, c.name))
+			return c.state.MAAS.DeleteContainer(c)
 		}
 
-		return c.state.MAAS.UpdateContainer(project.Instance(c.project, c.name), interfaces)
+		return c.state.MAAS.UpdateContainer(c, interfaces)
 	}
 
-	return c.state.MAAS.CreateContainer(project.Instance(c.project, c.name), interfaces)
+	return c.state.MAAS.CreateContainer(c, interfaces)
 }
 
 func (c *lxc) maasRename(newName string) error {
@@ -6899,7 +6899,7 @@ func (c *lxc) maasRename(newName string) error {
 		return fmt.Errorf("Can't perform the operation because MAAS is currently unavailable")
 	}
 
-	exists, err := c.state.MAAS.DefinedContainer(project.Instance(c.project, c.name))
+	exists, err := c.state.MAAS.DefinedContainer(c)
 	if err != nil {
 		return err
 	}
@@ -6908,7 +6908,7 @@ func (c *lxc) maasRename(newName string) error {
 		return c.maasUpdate(nil)
 	}
 
-	return c.state.MAAS.RenameContainer(project.Instance(c.project, c.name), project.Instance(c.project, newName))
+	return c.state.MAAS.RenameContainer(c, newName)
 }
 
 func (c *lxc) maasDelete() error {
@@ -6934,7 +6934,7 @@ func (c *lxc) maasDelete() error {
 		return fmt.Errorf("Can't perform the operation because MAAS is currently unavailable")
 	}
 
-	exists, err := c.state.MAAS.DefinedContainer(project.Instance(c.project, c.name))
+	exists, err := c.state.MAAS.DefinedContainer(c)
 	if err != nil {
 		return err
 	}
@@ -6943,7 +6943,7 @@ func (c *lxc) maasDelete() error {
 		return nil
 	}
 
-	return c.state.MAAS.DeleteContainer(project.Instance(c.project, c.name))
+	return c.state.MAAS.DeleteContainer(c)
 }
 
 func (c *lxc) cgroup(cc *liblxc.Container) (*cgroup.CGroup, error) {
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index f798c7239c..223758dd11 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -4169,7 +4169,7 @@ func (vm *qemu) maasRename(newName string) error {
 		return fmt.Errorf("Can't perform the operation because MAAS is currently unavailable")
 	}
 
-	exists, err := vm.state.MAAS.DefinedContainer(project.Instance(vm.project, vm.name))
+	exists, err := vm.state.MAAS.DefinedContainer(vm)
 	if err != nil {
 		return err
 	}
@@ -4178,7 +4178,7 @@ func (vm *qemu) maasRename(newName string) error {
 		return vm.maasUpdate(nil)
 	}
 
-	return vm.state.MAAS.RenameContainer(project.Instance(vm.project, vm.name), project.Instance(vm.project, newName))
+	return vm.state.MAAS.RenameContainer(vm, newName)
 }
 
 func (vm *qemu) maasDelete() error {
@@ -4204,7 +4204,7 @@ func (vm *qemu) maasDelete() error {
 		return fmt.Errorf("Can't perform the operation because MAAS is currently unavailable")
 	}
 
-	exists, err := vm.state.MAAS.DefinedContainer(project.Instance(vm.project, vm.name))
+	exists, err := vm.state.MAAS.DefinedContainer(vm)
 	if err != nil {
 		return err
 	}
@@ -4213,7 +4213,7 @@ func (vm *qemu) maasDelete() error {
 		return nil
 	}
 
-	return vm.state.MAAS.DeleteContainer(project.Instance(vm.project, vm.name))
+	return vm.state.MAAS.DeleteContainer(vm)
 }
 
 func (vm *qemu) maasUpdate(oldDevices map[string]map[string]string) error {
@@ -4250,20 +4250,20 @@ func (vm *qemu) maasUpdate(oldDevices map[string]map[string]string) error {
 		return fmt.Errorf("Can't perform the operation because MAAS is currently unavailable")
 	}
 
-	exists, err := vm.state.MAAS.DefinedContainer(project.Instance(vm.project, vm.name))
+	exists, err := vm.state.MAAS.DefinedContainer(vm)
 	if err != nil {
 		return err
 	}
 
 	if exists {
 		if len(interfaces) == 0 && len(oldInterfaces) > 0 {
-			return vm.state.MAAS.DeleteContainer(project.Instance(vm.project, vm.name))
+			return vm.state.MAAS.DeleteContainer(vm)
 		}
 
-		return vm.state.MAAS.UpdateContainer(project.Instance(vm.project, vm.name), interfaces)
+		return vm.state.MAAS.UpdateContainer(vm, interfaces)
 	}
 
-	return vm.state.MAAS.CreateContainer(project.Instance(vm.project, vm.name), interfaces)
+	return vm.state.MAAS.CreateContainer(vm, interfaces)
 }
 
 // UpdateBackupFile writes the instance's backup.yaml file to storage.
diff --git a/lxd/maas/controller.go b/lxd/maas/controller.go
index 52d01774b7..15465afc61 100644
--- a/lxd/maas/controller.go
+++ b/lxd/maas/controller.go
@@ -6,8 +6,17 @@ import (
 	"strings"
 
 	"github.com/juju/gomaasapi"
+
+	"github.com/lxc/lxd/lxd/project"
 )
 
+// Instance is a MAAS specific instance interface.
+// This is used rather than instance.Instance to avoid import loops.
+type Instance interface {
+	Name() string
+	Project() string
+}
+
 // Controller represents a MAAS server's machine functions
 type Controller struct {
 	url string
@@ -102,8 +111,22 @@ func NewController(url string, key string, machine string) (*Controller, error)
 	return &c, err
 }
 
-func (c *Controller) getDevice(name string) (gomaasapi.Device, error) {
-	devs, err := c.machine.Devices(gomaasapi.DevicesArgs{Hostname: []string{name}})
+func (c *Controller) getDomain(inst Instance) string {
+	fields := strings.Split(c.machine.FQDN(), ".")
+	domain := strings.Join(fields[1:], ".")
+
+	if inst.Project() == project.Default {
+		return domain
+	}
+
+	return fmt.Sprintf("%s.%s", inst.Project(), domain)
+}
+
+func (c *Controller) getDevice(name string, domain string) (gomaasapi.Device, error) {
+	devs, err := c.machine.Devices(gomaasapi.DevicesArgs{
+		Hostname: []string{name},
+		Domain:   domain,
+	})
 	if err != nil {
 		return nil, err
 	}
@@ -134,7 +157,7 @@ func (c *Controller) getSubnets() (map[string]gomaasapi.Subnet, error) {
 }
 
 // CreateContainer defines a new MAAS device for the controller
-func (c *Controller) CreateContainer(name string, interfaces []ContainerInterface) error {
+func (c *Controller) CreateContainer(inst Instance, interfaces []ContainerInterface) error {
 	// Parse the provided interfaces
 	macInterfaces, err := parseInterfaces(interfaces)
 	if err != nil {
@@ -167,7 +190,8 @@ func (c *Controller) CreateContainer(name string, interfaces []ContainerInterfac
 
 	// Create the device and first interface
 	device, err := c.machine.CreateDevice(gomaasapi.CreateMachineDeviceArgs{
-		Hostname:      name,
+		Hostname:      inst.Name(),
+		Domain:        c.getDomain(inst),
 		InterfaceName: interfaces[0].Name,
 		MACAddress:    interfaces[0].MACAddress,
 		VLAN:          subnets[interfaces[0].Subnets[0].Name].VLAN(),
@@ -183,7 +207,7 @@ func (c *Controller) CreateContainer(name string, interfaces []ContainerInterfac
 			return
 		}
 
-		c.DeleteContainer(name)
+		c.DeleteContainer(inst)
 	}()
 
 	// Create the rest of the interfaces
@@ -199,7 +223,7 @@ func (c *Controller) CreateContainer(name string, interfaces []ContainerInterfac
 	}
 
 	// Get a fresh copy of the device
-	device, err = c.getDevice(name)
+	device, err = c.getDevice(inst.Name(), c.getDomain(inst))
 	if err != nil {
 		return err
 	}
@@ -230,8 +254,11 @@ func (c *Controller) CreateContainer(name string, interfaces []ContainerInterfac
 }
 
 // DefinedContainer returns true if the container is defined in MAAS
-func (c *Controller) DefinedContainer(name string) (bool, error) {
-	devs, err := c.machine.Devices(gomaasapi.DevicesArgs{Hostname: []string{name}})
+func (c *Controller) DefinedContainer(inst Instance) (bool, error) {
+	devs, err := c.machine.Devices(gomaasapi.DevicesArgs{
+		Hostname: []string{inst.Name()},
+		Domain:   c.getDomain(inst),
+	})
 	if err != nil {
 		return false, err
 	}
@@ -244,7 +271,7 @@ func (c *Controller) DefinedContainer(name string) (bool, error) {
 }
 
 // UpdateContainer updates the MAAS device's interfaces with the new provided state
-func (c *Controller) UpdateContainer(name string, interfaces []ContainerInterface) error {
+func (c *Controller) UpdateContainer(inst Instance, interfaces []ContainerInterface) error {
 	// Parse the provided interfaces
 	macInterfaces, err := parseInterfaces(interfaces)
 	if err != nil {
@@ -257,7 +284,7 @@ func (c *Controller) UpdateContainer(name string, interfaces []ContainerInterfac
 		return err
 	}
 
-	device, err := c.getDevice(name)
+	device, err := c.getDevice(inst.Name(), c.getDomain(inst))
 	if err != nil {
 		return err
 	}
@@ -381,8 +408,8 @@ func (c *Controller) UpdateContainer(name string, interfaces []ContainerInterfac
 }
 
 // RenameContainer renames the MAAS device for the container without releasing any allocation
-func (c *Controller) RenameContainer(name string, newName string) error {
-	device, err := c.getDevice(name)
+func (c *Controller) RenameContainer(inst Instance, newName string) error {
+	device, err := c.getDevice(inst.Name(), c.getDomain(inst))
 	if err != nil {
 		return err
 	}
@@ -405,8 +432,8 @@ func (c *Controller) RenameContainer(name string, newName string) error {
 }
 
 // DeleteContainer removes the MAAS device for the container
-func (c *Controller) DeleteContainer(name string) error {
-	device, err := c.getDevice(name)
+func (c *Controller) DeleteContainer(inst Instance) error {
+	device, err := c.getDevice(inst.Name(), c.getDomain(inst))
 	if err != nil {
 		return err
 	}

From f8215ac577d055826008f7a56e4c296f7ab2dbc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 1 Jun 2020 17:43:17 -0400
Subject: [PATCH 3/3] lxd/dnsmasq: Add project suffix
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This doesn't actually work in current dnsmasq mind you, but it's still
less wrong than the current behavior where you just nuke any existing
record in the default project instead.

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/dnsmasq/dnsmasq.go | 2 +-
 lxd/project/project.go | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/lxd/dnsmasq/dnsmasq.go b/lxd/dnsmasq/dnsmasq.go
index a853fe967d..82f7f5f7e0 100644
--- a/lxd/dnsmasq/dnsmasq.go
+++ b/lxd/dnsmasq/dnsmasq.go
@@ -41,7 +41,7 @@ func UpdateStaticEntry(network string, projectName string, instanceName string,
 	}
 
 	if netConfig["dns.mode"] == "" || netConfig["dns.mode"] == "managed" {
-		line += fmt.Sprintf(",%s", instanceName)
+		line += fmt.Sprintf(",%s", project.DNS(projectName, instanceName))
 	}
 
 	if line == hwaddr {
diff --git a/lxd/project/project.go b/lxd/project/project.go
index 887e89146a..3d923d0d95 100644
--- a/lxd/project/project.go
+++ b/lxd/project/project.go
@@ -26,6 +26,15 @@ func Instance(projectName string, instanceName string) string {
 	return instanceName
 }
 
+// DNS adds ".<project>" as a suffix to instance name when the given project name is not "default".
+func DNS(projectName string, instanceName string) string {
+	if projectName != Default {
+		return fmt.Sprintf("%s.%s", instanceName, projectName)
+	}
+
+	return instanceName
+}
+
 // InstanceParts takes a project prefixed Instance name string and returns the project and instance name.
 // If a non-project prefixed Instance name is supplied, then the project is returned as "default" and the instance
 // name is returned unmodified in the 2nd return value. This is suitable for passing back into Prefix().


More information about the lxc-devel mailing list