[lxc-devel] [lxd/master] VM: boot priority

tomponline on Github lxc-bot at linuxcontainers.org
Mon Jan 20 20:01:55 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 544 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200120/205e90ee/attachment-0001.bin>
-------------- next part --------------
From 9fbd01aee9042c2114e5ed81604ab6d81e21b7d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 20 Jan 2020 16:34:31 +0200
Subject: [PATCH 1/9] doc/api-extensions: Fix syntax
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>
---
 doc/api-extensions.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 5b3c2e5331..a2bc88793a 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -895,7 +895,7 @@ This adds a new `architecture` attribute to cluster members which indicates a cl
 member's architecture.
 
 ## resources\_disk\_id
-Add a new device_id field in the disk entries on the resources API.
+Add a new device\_id field in the disk entries on the resources API.
 
 ## storage\_lvm\_stripes
 This adds the ability to use LVM stripes on normal volumes and thin pool volumes.

From 44f6dfe0a43ef89d4b6f457bc4006dceded89796 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 20 Jan 2020 16:35:28 +0200
Subject: [PATCH 2/9] api: vm_boot_priority
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>
---
 doc/api-extensions.md | 3 +++
 shared/version/api.go | 1 +
 2 files changed, 4 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index a2bc88793a..a5dad365ea 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -899,3 +899,6 @@ Add a new device\_id field in the disk entries on the resources API.
 
 ## storage\_lvm\_stripes
 This adds the ability to use LVM stripes on normal volumes and thin pool volumes.
+
+## vm\_boot\_priority
+Adds a `boot.priority` property on nic and disk devices to control the boot order.
diff --git a/shared/version/api.go b/shared/version/api.go
index 95985665cb..b06864911b 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -183,6 +183,7 @@ var APIExtensions = []string{
 	"clustering_architecture",
 	"resources_disk_id",
 	"storage_lvm_stripes",
+	"vm_boot_priority",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From 2e8f4bb22d7023ef79f9a3319c1781584c208230 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Mon, 20 Jan 2020 16:33:57 +0200
Subject: [PATCH 3/9] lxd/vm: Add boot.priority
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>
---
 doc/instances.md           | 6 ++++++
 lxd/device/disk.go         | 1 +
 lxd/device/nic.go          | 1 +
 lxd/device/nic_bridged.go  | 1 +
 lxd/device/nic_macvlan.go  | 2 +-
 lxd/device/nic_physical.go | 1 +
 lxd/device/nic_sriov.go    | 1 +
 scripts/bash/lxd-client    | 3 ++-
 8 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/doc/instances.md b/doc/instances.md
index e845ae0b92..08149c0f24 100644
--- a/doc/instances.md
+++ b/doc/instances.md
@@ -272,6 +272,7 @@ hwaddr                  | string    | randomly assigned | no        | The MAC ad
 vlan                    | integer   | -                 | no        | The VLAN ID to attach to
 maas.subnet.ipv4        | string    | -                 | no        | MAAS IPv4 subnet to register the instance in
 maas.subnet.ipv6        | string    | -                 | no        | MAAS IPv6 subnet to register the instance in
+boot.priority           | integer   | -                 | no        | Boot priority for VMs (higher boots first)
 
 #### nictype: bridged
 Uses an existing bridge on the host and creates a virtual device pair to connect the host bridge to the instance.
@@ -297,6 +298,7 @@ security.ipv4\_filtering | boolean   | false             | no        | Prevent t
 security.ipv6\_filtering | boolean   | false             | no        | Prevent the instance from spoofing another's IPv6 address (enables mac\_filtering)
 maas.subnet.ipv4         | string    | -                 | no        | MAAS IPv4 subnet to register the instance in
 maas.subnet.ipv6         | string    | -                 | no        | MAAS IPv6 subnet to register the instance in
+boot.priority            | integer   | -                 | no        | Boot priority for VMs (higher boots first)
 
 #### nictype: macvlan
 Sets up a new network device based on an existing one but using a different MAC address.
@@ -312,6 +314,7 @@ hwaddr                  | string    | randomly assigned | no        | The MAC ad
 vlan                    | integer   | -                 | no        | The VLAN ID to attach to
 maas.subnet.ipv4        | string    | -                 | no        | MAAS IPv4 subnet to register the instance in
 maas.subnet.ipv6        | string    | -                 | no        | MAAS IPv6 subnet to register the instance in
+boot.priority           | integer   | -                 | no        | Boot priority for VMs (higher boots first)
 
 #### nictype: ipvlan
 Sets up a new network device based on an existing one using the same MAC address but a different IP.
@@ -365,6 +368,7 @@ limits.egress           | string    | -                 | no        | I/O limit
 limits.max              | string    | -                 | no        | Same as modifying both limits.ingress and limits.egress
 ipv4.routes             | string    | -                 | no        | Comma delimited list of IPv4 static routes to add on host to nic
 ipv6.routes             | string    | -                 | no        | Comma delimited list of IPv6 static routes to add on host to nic
+boot.priority           | integer   | -                 | no        | Boot priority for VMs (higher boots first)
 
 #### nictype: sriov
 Passes a virtual function of an SR-IOV enabled physical network device into the instance.
@@ -381,6 +385,7 @@ security.mac\_filtering | boolean   | false             | no        | Prevent th
 vlan                    | integer   | -                 | no        | The VLAN ID to attach to
 maas.subnet.ipv4        | string    | -                 | no        | MAAS IPv4 subnet to register the instance in
 maas.subnet.ipv6        | string    | -                 | no        | MAAS IPv6 subnet to register the instance in
+boot.priority           | integer   | -                 | no        | Boot priority for VMs (higher boots first)
 
 #### nictype: routed
 This NIC type is similar in operation to IPVLAN, in that it allows an instance to join an external network without needing to configure a bridge and shares the host's MAC address.
@@ -572,6 +577,7 @@ shift               | boolean   | false     | no        | Setup a shifting overl
 raw.mount.options   | string    | -         | no        | Filesystem specific mount options
 ceph.user\_name     | string    | admin     | no        | If source is ceph or cephfs then ceph user\_name must be specified by user for proper mount
 ceph.cluster\_name  | string    | admin     | no        | If source is ceph or cephfs then ceph cluster\_name must be specified by user for proper mount
+boot.priority       | integer   | -         | no        | Boot priority for VMs (higher boots first)
 
 ### Type: unix-char
 Unix character device entries simply make the requested character device
diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index 508b31bc0a..c0fff8f6c5 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -82,6 +82,7 @@ func (d *disk) validateConfig() error {
 		"raw.mount.options": shared.IsAny,
 		"ceph.cluster_name": shared.IsAny,
 		"ceph.user_name":    shared.IsAny,
+		"boot.priority":     shared.IsUint32,
 	}
 
 	// VMs don't use the "path" property, but containers need it, so if we are validating a profile that can
diff --git a/lxd/device/nic.go b/lxd/device/nic.go
index 7f7f942ebc..562ee7a08a 100644
--- a/lxd/device/nic.go
+++ b/lxd/device/nic.go
@@ -47,6 +47,7 @@ func nicValidationRules(requiredFields []string, optionalFields []string) map[st
 		"ipv6.address":            NetworkValidAddressV6,
 		"ipv4.routes":             NetworkValidNetworkV4List,
 		"ipv6.routes":             NetworkValidNetworkV6List,
+		"boot.priority":           shared.IsUint32,
 	}
 
 	validators := map[string]func(value string) error{}
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 0428adbbd4..3ec776aeb2 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -71,6 +71,7 @@ func (d *nicBridged) validateConfig() error {
 		"security.ipv6_filtering",
 		"maas.subnet.ipv4",
 		"maas.subnet.ipv6",
+		"boot.priority",
 	}
 	err := d.config.Validate(nicValidationRules(requiredFields, optionalFields))
 	if err != nil {
diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index fb7b87d21d..d59ad57bb0 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -19,7 +19,7 @@ func (d *nicMACVLAN) validateConfig() error {
 	}
 
 	requiredFields := []string{"parent"}
-	optionalFields := []string{"name", "mtu", "hwaddr", "vlan", "maas.subnet.ipv4", "maas.subnet.ipv6"}
+	optionalFields := []string{"name", "mtu", "hwaddr", "vlan", "maas.subnet.ipv4", "maas.subnet.ipv6", "boot.priority"}
 	err := d.config.Validate(nicValidationRules(requiredFields, optionalFields))
 	if err != nil {
 		return err
diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go
index 8376da3a07..ebb465b70a 100644
--- a/lxd/device/nic_physical.go
+++ b/lxd/device/nic_physical.go
@@ -26,6 +26,7 @@ func (d *nicPhysical) validateConfig() error {
 		"vlan",
 		"maas.subnet.ipv4",
 		"maas.subnet.ipv6",
+		"boot.priority",
 	}
 	err := d.config.Validate(nicValidationRules(requiredFields, optionalFields))
 	if err != nil {
diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index 1079b9773f..508036d799 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -37,6 +37,7 @@ func (d *nicSRIOV) validateConfig() error {
 		"security.mac_filtering",
 		"maas.subnet.ipv4",
 		"maas.subnet.ipv6",
+		"boot.priority",
 	}
 	err := d.config.Validate(nicValidationRules(requiredFields, optionalFields))
 	if err != nil {
diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client
index b437c10524..65de585d16 100644
--- a/scripts/bash/lxd-client
+++ b/scripts/bash/lxd-client
@@ -114,7 +114,8 @@ _have lxc && {
       security.ipv4_filtering security.ipv6_filtering vlan limits.read \
       limits.write path source optional readonly size recursive pool \
       propagation shift major minor uid gid mode required vendorid productid \
-      pci id listen connect bind nat proxy_protocol security.uid security.gid"
+      pci id listen connect bind nat proxy_protocol security.uid security.gid \
+      boot.priority"
 
     networks_keys="bridge.driver bridge.external_interfaces bridge.mode \
       bridge.mtu bridge.hwaddr dns.domain dns.mode fan.overlay_subnet fan.type \

From 273de74a5048c7f8f9bdb2a0cbe5e6d55de090b9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jan 2020 19:52:57 +0000
Subject: [PATCH 4/9] lxd/container/logs: Makes log file retrieval project
 aware

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/container_logs.go | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lxd/container_logs.go b/lxd/container_logs.go
index d093eefb35..dc1355a05c 100644
--- a/lxd/container_logs.go
+++ b/lxd/container_logs.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/gorilla/mux"
 
+	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/version"
@@ -103,11 +104,11 @@ func containerLogGet(d *Daemon, r *http.Request) response.Response {
 		return response.SmartError(err)
 	}
 
-	project := projectParam(r)
+	projectName := projectParam(r)
 	name := mux.Vars(r)["name"]
 
 	// Handle requests targeted to a container on a different node
-	resp, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
+	resp, err := ForwardedResponseIfContainerIsRemote(d, r, projectName, name, instanceType)
 	if err != nil {
 		return response.SmartError(err)
 	}
@@ -126,7 +127,7 @@ func containerLogGet(d *Daemon, r *http.Request) response.Response {
 	}
 
 	ent := response.FileResponseEntry{
-		Path:     shared.LogPath(name, file),
+		Path:     shared.LogPath(project.Prefix(projectName, name), file),
 		Filename: file,
 	}
 

From 2115bb6456a9bc1b5b1db4c7b5e251461bd2744f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jan 2020 19:53:21 +0000
Subject: [PATCH 5/9] lxd/container/lxc: Adds devName skipping for startCommon

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/container_lxc.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index df12b17c21..4e8f3eb3ba 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -2172,6 +2172,10 @@ func (c *containerLXC) startCommon() (string, []func() error, error) {
 			}
 
 			for _, nicItem := range runConf.NetworkInterface {
+				if nicItem.Key == "devName" {
+					// Skip internal device name key, not used by liblxc.
+					continue
+				}
 				err = lxcSetConfigItem(c.c, fmt.Sprintf("%s.%d.%s", networkKeyPrefix, nicID, nicItem.Key), nicItem.Value)
 				if err != nil {
 					return "", postStartHooks, errors.Wrapf(err, "Failed to setup device network interface '%s'", dev.Name)

From 088246c4a70dc0e956d5c3ca50a0774be487c4ca Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jan 2020 19:53:40 +0000
Subject: [PATCH 6/9] lxd/device/config/device/runconfig: Adds DevName to
 MountEntryItem

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/config/device_runconfig.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/device/config/device_runconfig.go b/lxd/device/config/device_runconfig.go
index 744e9027fa..35b24e3cbf 100644
--- a/lxd/device/config/device_runconfig.go
+++ b/lxd/device/config/device_runconfig.go
@@ -17,6 +17,7 @@ type RunConfigItem struct {
 
 // MountEntryItem represents a single mount entry item.
 type MountEntryItem struct {
+	DevName    string   // The internal name for the device.
 	DevPath    string   // Describes the block special device or remote filesystem to be mounted.
 	TargetPath string   // Describes the mount point (target) for the filesystem.
 	FSType     string   // Describes the type of the filesystem.

From 03874f8833c757f584526abf93c24b2a28015110 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jan 2020 19:54:49 +0000
Subject: [PATCH 7/9] lxd/device/disk: Adds DevName to MountEntryItem

Also sets TargetPath for root disk device for VMs. This will be used as root device indicator.

Also switches to using just MountEntryItem for VM disk configs.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/disk.go | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index c0fff8f6c5..7fd8b50763 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -344,6 +344,7 @@ func (d *disk) startContainer() (*deviceConfig.RunConfig, error) {
 		if sourceDevPath != "" {
 			// Instruct LXD to perform the mount.
 			runConf.Mounts = append(runConf.Mounts, deviceConfig.MountEntryItem{
+				DevName:    d.name,
 				DevPath:    sourceDevPath,
 				TargetPath: relativeDestPath,
 				FSType:     "none",
@@ -364,8 +365,13 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) {
 	runConf := deviceConfig.RunConfig{}
 
 	if shared.IsRootDiskDevice(d.config) {
-		// The root disk device is special as it is given the first device ID and boot order in VM config.
-		runConf.RootFS.Path = d.config["path"]
+		runConf.Mounts = []deviceConfig.MountEntryItem{
+			{
+				TargetPath: d.config["path"], // Indicator used that this is the root device.
+				DevName:    d.name,
+			},
+		}
+
 		return &runConf, nil
 	} else if d.config["source"] == diskSourceCloudInit {
 		// This is a special virtual disk source that can be attached to a VM to provide cloud-init config.
@@ -376,8 +382,8 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) {
 
 		runConf.Mounts = []deviceConfig.MountEntryItem{
 			{
-				DevPath:    isoPath,
-				TargetPath: d.name,
+				DevPath: isoPath,
+				DevName: d.name,
 			},
 		}
 		return &runConf, nil
@@ -386,10 +392,11 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) {
 		if !shared.PathExists(d.config["source"]) {
 			return nil, fmt.Errorf("Cannot find disk source")
 		}
+
 		runConf.Mounts = []deviceConfig.MountEntryItem{
 			{
-				DevPath:    d.config["source"],
-				TargetPath: d.name,
+				DevPath: d.config["source"],
+				DevName: d.name,
 			},
 		}
 		return &runConf, nil

From 1670a1abd30908ee82c48d0a6cc006f6e122ec56 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jan 2020 19:56:05 +0000
Subject: [PATCH 8/9] lxd/device: Adds devName property to network interface
 run config

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/device/infiniband_physical.go | 1 +
 lxd/device/infiniband_sriov.go    | 1 +
 lxd/device/nic_bridged.go         | 1 +
 lxd/device/nic_macvlan.go         | 1 +
 lxd/device/nic_p2p.go             | 1 +
 lxd/device/nic_physical.go        | 1 +
 lxd/device/nic_sriov.go           | 1 +
 7 files changed, 7 insertions(+)

diff --git a/lxd/device/infiniband_physical.go b/lxd/device/infiniband_physical.go
index 564625461a..f1ba582621 100644
--- a/lxd/device/infiniband_physical.go
+++ b/lxd/device/infiniband_physical.go
@@ -116,6 +116,7 @@ func (d *infinibandPhysical) Start() (*deviceConfig.RunConfig, error) {
 	}
 
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},
diff --git a/lxd/device/infiniband_sriov.go b/lxd/device/infiniband_sriov.go
index f471d9419b..ea37fda93c 100644
--- a/lxd/device/infiniband_sriov.go
+++ b/lxd/device/infiniband_sriov.go
@@ -138,6 +138,7 @@ func (d *infinibandSRIOV) Start() (*deviceConfig.RunConfig, error) {
 	}
 
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 3ec776aeb2..6359052328 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -176,6 +176,7 @@ func (d *nicBridged) Start() (*deviceConfig.RunConfig, error) {
 
 	runConf := deviceConfig.RunConfig{}
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index d59ad57bb0..5471bc869b 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -106,6 +106,7 @@ func (d *nicMACVLAN) Start() (*deviceConfig.RunConfig, error) {
 
 	runConf := deviceConfig.RunConfig{}
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_p2p.go b/lxd/device/nic_p2p.go
index 2349039c50..6b2770218e 100644
--- a/lxd/device/nic_p2p.go
+++ b/lxd/device/nic_p2p.go
@@ -85,6 +85,7 @@ func (d *nicP2P) Start() (*deviceConfig.RunConfig, error) {
 
 	runConf := deviceConfig.RunConfig{}
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go
index ebb465b70a..09f4002568 100644
--- a/lxd/device/nic_physical.go
+++ b/lxd/device/nic_physical.go
@@ -111,6 +111,7 @@ func (d *nicPhysical) Start() (*deviceConfig.RunConfig, error) {
 
 	runConf := deviceConfig.RunConfig{}
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index 508036d799..7c426e01e5 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -113,6 +113,7 @@ func (d *nicSRIOV) Start() (*deviceConfig.RunConfig, error) {
 
 	runConf := deviceConfig.RunConfig{}
 	runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+		{Key: "devName", Value: d.name},
 		{Key: "name", Value: d.config["name"]},
 		{Key: "type", Value: "phys"},
 		{Key: "flags", Value: "up"},

From 1ff1c82b40ebdeaba531514259b6fa682bfe311d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 20 Jan 2020 19:58:11 +0000
Subject: [PATCH 9/9] lxd/instance/drivers/driver/qemu: Adds support for Disk
 and NIC device boot.priority setting

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instance/drivers/driver_qemu.go | 125 +++++++++++++++++-----------
 1 file changed, 76 insertions(+), 49 deletions(-)

diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index 90cd4f9245..c20d3f784b 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -10,6 +10,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -1136,6 +1137,45 @@ echo "To start it now, unmount this filesystem and run: systemctl start lxd-agen
 	return nil
 }
 
+// deviceBootPriorities returns a map keyed on device name containing the boot index to use.
+// Qemu tries to boot devices in order of boot index (lowest first).
+func (vm *qemu) deviceBootPriorities() (map[string]int, error) {
+	type devicePrios struct {
+		Name     string
+		BootPrio uint32
+	}
+
+	devices := []devicePrios{}
+
+	for devName, devConf := range vm.expandedDevices {
+		if devConf["type"] != "disk" && devConf["type"] != "nic" {
+			continue
+		}
+
+		bootPrio := uint32(0) // Default to lowest priority.
+		if devConf["boot.priority"] != "" {
+			prio, err := strconv.ParseInt(devConf["boot.priority"], 10, 32)
+			if err != nil {
+				return nil, errors.Wrapf(err, "Invalid boot.priority for device %q", devName)
+			}
+			bootPrio = uint32(prio)
+		} else if devConf["path"] == "/" {
+			bootPrio = 1 // Set boot priority of root disk higher than any device without a boot prio.
+		}
+
+		devices = append(devices, devicePrios{Name: devName, BootPrio: bootPrio})
+	}
+
+	sort.SliceStable(devices, func(i, j int) bool { return devices[i].BootPrio > devices[j].BootPrio })
+
+	sortedDevs := make(map[string]int, len(devices))
+	for bootIndex, dev := range devices {
+		sortedDevs[dev.Name] = bootIndex
+	}
+
+	return sortedDevs, nil
+}
+
 // generateQemuConfigFile writes the qemu config file and returns its location.
 // It writes the config file inside the VM's log path.
 func (vm *qemu) generateQemuConfigFile(qemuType string, qemuConf string, devConfs []*deviceConfig.RunConfig) (string, error) {
@@ -1260,22 +1300,20 @@ backend = "pty"
 	}
 
 	nicIndex := 0
-	driveIndex := 0
-	for _, runConf := range devConfs {
-		// Add root drive device.
-		if runConf.RootFS.Path != "" {
-			err = vm.addRootDriveConfig(sb)
-			if err != nil {
-				return "", err
-			}
-		}
+	bootIndexes, err := vm.deviceBootPriorities()
+	if err != nil {
+		return "", errors.Wrap(err, "Error calculating boot indexes")
+	}
 
+	for _, runConf := range devConfs {
 		// Add drive devices.
 		if len(runConf.Mounts) > 0 {
 			for _, drive := range runConf.Mounts {
-				// Increment first so index starts at 1, as root drive uses index 0.
-				driveIndex++
-				err = vm.addDriveConfig(sb, driveIndex, drive)
+				if drive.TargetPath == "/" {
+					err = vm.addRootDriveConfig(sb, bootIndexes, drive)
+				} else {
+					err = vm.addDriveConfig(sb, bootIndexes, drive)
+				}
 				if err != nil {
 					return "", err
 				}
@@ -1284,7 +1322,7 @@ backend = "pty"
 
 		// Add network device.
 		if len(runConf.NetworkInterface) > 0 {
-			err = vm.addNetDevConfig(sb, nicIndex, runConf.NetworkInterface)
+			err = vm.addNetDevConfig(sb, nicIndex, bootIndexes, runConf.NetworkInterface)
 			if err != nil {
 				return "", err
 			}
@@ -1451,7 +1489,11 @@ mount_tag = "config"
 }
 
 // addRootDriveConfig adds the qemu config required for adding the root drive.
-func (vm *qemu) addRootDriveConfig(sb *strings.Builder) error {
+func (vm *qemu) addRootDriveConfig(sb *strings.Builder, bootIndexes map[string]int, rootDriveConf deviceConfig.MountEntryItem) error {
+	if rootDriveConf.TargetPath != "/" {
+		return fmt.Errorf("Non-root drive config supplied")
+	}
+
 	pool, err := vm.getStoragePool()
 	if err != nil {
 		return err
@@ -1462,67 +1504,52 @@ func (vm *qemu) addRootDriveConfig(sb *strings.Builder) error {
 		return err
 	}
 
-	// Devices use "lxd_" prefix indicating that this is a user named device.
-	t := template.Must(template.New("").Parse(`
-# Root drive ("root" device)
-[drive "lxd_root"]
-file = "{{.file}}"
-format = "raw"
-if = "none"
-cache = "none"
-aio = "native"
-
-[device "dev-lxd_root"]
-driver = "scsi-hd"
-bus = "qemu_scsi.0"
-channel = "0"
-scsi-id = "0"
-lun = "1"
-drive = "lxd_root"
-bootindex = "1"
-`))
-	m := map[string]interface{}{
-		"file": rootDrivePath,
+	// Generate a new device config with the root device path expanded.
+	driveConf := deviceConfig.MountEntryItem{
+		DevName: rootDriveConf.DevName,
+		DevPath: rootDrivePath,
 	}
-	return t.Execute(sb, m)
+
+	return vm.addDriveConfig(sb, bootIndexes, driveConf)
 }
 
 // addDriveConfig adds the qemu config required for adding a supplementary drive.
-func (vm *qemu) addDriveConfig(sb *strings.Builder, driveIndex int, driveConf deviceConfig.MountEntryItem) error {
-	driveName := fmt.Sprintf(driveConf.TargetPath)
+func (vm *qemu) addDriveConfig(sb *strings.Builder, bootIndexes map[string]int, driveConf deviceConfig.MountEntryItem) error {
+	devName := fmt.Sprintf(driveConf.DevName)
 
 	// Devices use "lxd_" prefix indicating that this is a user named device.
 	t := template.Must(template.New("").Parse(`
-# {{.driveName}} drive
-[drive "lxd_{{.driveName}}"]
+# {{.devName}} drive
+[drive "lxd_{{.devName}}"]
 file = "{{.devPath}}"
 format = "raw"
 if = "none"
 cache = "none"
 aio = "native"
 
-[device "dev-lxd_{{.driveName}}"]
+[device "dev-lxd_{{.devName}}"]
 driver = "scsi-hd"
 bus = "qemu_scsi.0"
 channel = "0"
-scsi-id = "{{.driveIndex}}"
+scsi-id = "{{.bootIndex}}"
 lun = "1"
-drive = "lxd_{{.driveName}}"
+drive = "lxd_{{.devName}}"
+bootindex = "{{.bootIndex}}"
 `))
 
 	m := map[string]interface{}{
-		"driveName":  driveName,
-		"devPath":    driveConf.DevPath,
-		"driveIndex": driveIndex,
+		"devName":   devName,
+		"devPath":   driveConf.DevPath,
+		"bootIndex": bootIndexes[devName],
 	}
 	return t.Execute(sb, m)
 }
 
 // addNetDevConfig adds the qemu config required for adding a network device.
-func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, nicConfig []deviceConfig.RunConfigItem) error {
+func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, bootIndexes map[string]int, nicConfig []deviceConfig.RunConfigItem) error {
 	var devName, devTap, devHwaddr string
 	for _, nicItem := range nicConfig {
-		if nicItem.Key == "name" {
+		if nicItem.Key == "devName" {
 			devName = nicItem.Value
 		} else if nicItem.Key == "link" {
 			devTap = nicItem.Value
@@ -1563,7 +1590,7 @@ bootindex = "{{.bootIndex}}"
 		"portIndex":    14 + nicIndex,
 		"pcieAddr":     4 + nicIndex,
 		"devHwaddr":    devHwaddr,
-		"bootIndex":    2 + nicIndex,
+		"bootIndex":    bootIndexes[devName],
 	}
 	return t.Execute(sb, m)
 }


More information about the lxc-devel mailing list