The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6813
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === This PR removes the somewhat hacky `ProfileValidationName` constant that used an empty instanceName as a way to indicate to device validation that the 'instance' being validated was in fact a profile type and to allow validation to be somewhat more relaxed to accommodate a device being defined in the same profile for different instance types. Instead we now remove `instanceName` entirely from device validation and instead use the `instancetype.Any` type to indicate profile validation (i.e the instance type being validated could be "any"). In order to support this, a `device.Validate()` function has been added, which accepts a new interface type `instance.ConfigReader` which allows only access to an instance's config, which allow us to instantiate an instance of type "Any" that contains the profile device. config for validation. This is then passed as an argument to each device's `validateConfig()` function. Additionally a tentative first step at a `common` instance type implementation has been added, and embedded into the `qemu` driver. At this time this common instance only deals with config access and expanding config. However it is expected that more common instance functionality will be moved across once the `containerLXC` type has been moved into `instance/drivers` package.
From 8be13df905cbaed9f1eb57c88014e8f65313261a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:25:21 +0000 Subject: [PATCH 01/12] lxd/device/device/common: Splits device common into own file Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/device_common.go | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 lxd/device/device_common.go diff --git a/lxd/device/device_common.go b/lxd/device/device_common.go new file mode 100644 index 0000000000..2f6551f5d3 --- /dev/null +++ b/lxd/device/device_common.go @@ -0,0 +1,58 @@ +package device + +import ( + "fmt" + + deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" + "github.com/lxc/lxd/lxd/state" +) + +// deviceCommon represents the common struct for all devices. +type deviceCommon struct { + inst instance.Instance + name string + config deviceConfig.Device + state *state.State + volatileGet func() map[string]string + volatileSet func(map[string]string) error +} + +// init stores the Instance, daemon state, device name and config into device. +// It also needs to be provided with volatile get and set functions for the device to allow +// persistent data to be accessed. This is implemented as part of deviceCommon so that the majority +// of devices don't need to implement it and can just embed deviceCommon. +func (d *deviceCommon) init(inst instance.Instance, state *state.State, name string, conf deviceConfig.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) { + d.inst = inst + d.name = name + d.config = conf + d.state = state + d.volatileGet = volatileGet + d.volatileSet = volatileSet +} + +// Add returns nil error as majority of devices don't need to do any host-side setup. +func (d *deviceCommon) Add() error { + return nil +} + +// Register returns nil error as majority of devices don't need to do any event registration. +func (d *deviceCommon) Register() error { + return nil +} + +// CanHotPlug returns true as majority of devices can be started/stopped when instance is running. +// Also returns an empty list of update fields as most devices do not support live updates. +func (d *deviceCommon) CanHotPlug() (bool, []string) { + return true, []string{} +} + +// Update returns an error as most devices do not support live updates without being restarted. +func (d *deviceCommon) Update(oldDevices deviceConfig.Devices, isRunning bool) error { + return fmt.Errorf("Device does not support updates whilst started") +} + +// Remove returns nil error as majority of devices don't need to do any host-side cleanup on delete. +func (d *deviceCommon) Remove() error { + return nil +} From 00c762a7f36d8431bc8fb9c67cc197594223b044 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:25:39 +0000 Subject: [PATCH 02/12] lxd/device/device: Removes original device.go file Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/device.go | 163 ------------------------------------------- 1 file changed, 163 deletions(-) delete mode 100644 lxd/device/device.go diff --git a/lxd/device/device.go b/lxd/device/device.go deleted file mode 100644 index af9e4a07ed..0000000000 --- a/lxd/device/device.go +++ /dev/null @@ -1,163 +0,0 @@ -package device - -import ( - "fmt" - - deviceConfig "github.com/lxc/lxd/lxd/device/config" - "github.com/lxc/lxd/lxd/instance" - "github.com/lxc/lxd/lxd/state" -) - -// devTypes defines supported top-level device type creation functions. -var devTypes = map[string]func(deviceConfig.Device) device{ - "nic": nicLoadByType, - "infiniband": infinibandLoadByType, - "proxy": func(c deviceConfig.Device) device { return &proxy{} }, - "gpu": func(c deviceConfig.Device) device { return &gpu{} }, - "usb": func(c deviceConfig.Device) device { return &usb{} }, - "unix-char": func(c deviceConfig.Device) device { return &unixCommon{} }, - "unix-block": func(c deviceConfig.Device) device { return &unixCommon{} }, - "unix-hotplug": func(c deviceConfig.Device) device { return &unixHotplug{} }, - "disk": func(c deviceConfig.Device) device { return &disk{} }, - "none": func(c deviceConfig.Device) device { return &none{} }, -} - -// VolatileSetter is a function that accepts one or more key/value strings to save into the LXD -// config for this instance. It should add the volatile device name prefix to each key when saving. -type VolatileSetter func(map[string]string) error - -// VolatileGetter is a function that retrieves any key/value string that exists in the LXD database -// config for this instance. It should only return keys that match the volatile device name prefix, -// and should remove the prefix before being returned. -type VolatileGetter func() map[string]string - -// Device represents a device that can be added to an instance. -type Device interface { - // CanHotPlug returns true if device can be managed whilst instance is running. - // It also returns a slice of config fields that can be live updated. If only fields in this - // list have changed then Update() is called rather than triggering a device remove & add. - CanHotPlug() (bool, []string) - - // Add performs any host-side setup when a device is added to an instance. - // It is called irrespective of whether the instance is running or not. - Add() error - - // Start peforms any host-side configuration required to start the device for the instance. - // This can be when a device is plugged into a running instance or the instance is starting. - // Returns run-time configuration needed for configuring the instance with the new device. - Start() (*deviceConfig.RunConfig, error) - - // Register provides the ability for a device to subcribe to events that LXD can generate. - // It is called after a device is started (after Start()) or when LXD starts. - Register() error - - // Update performs host-side modifications for a device based on the difference between the - // current config and previous devices config supplied as an argument. This called if the - // only config fields that have changed are supplied in the list returned from CanHotPlug(). - // The function also accepts a boolean indicating whether the instance is running or not. - Update(oldDevices deviceConfig.Devices, running bool) error - - // Stop performs any host-side cleanup required when a device is removed from an instance, - // either due to unplugging it from a running instance or instance is being shutdown. - // Returns run-time configuration needed for detaching the device from the instance. - Stop() (*deviceConfig.RunConfig, error) - - // Remove performs any host-side cleanup when an instance is removed from an instance. - Remove() error -} - -// device represents a sealed interface that implements Device, but also contains some internal -// setup functions for a Device that should only be called by device.New() to avoid exposing devices -// that are not in a known configured state. This is separate from the Device interface so that -// Devices created outside of the device package can be used by LXD, but ensures that any devices -// created by the device package will only be accessible after being configured properly by New(). -type device interface { - Device - - // init stores the Instance, daemon State and Config into device and performs any setup. - init(instance.Instance, *state.State, string, deviceConfig.Device, VolatileGetter, VolatileSetter) - - // validateConfig checks Config stored by init() is valid for the instance type. - validateConfig() error -} - -// deviceCommon represents the common struct for all devices. -type deviceCommon struct { - inst instance.Instance - name string - config deviceConfig.Device - state *state.State - volatileGet func() map[string]string - volatileSet func(map[string]string) error -} - -// init stores the Instance, daemon state, device name and config into device. -// It also needs to be provided with volatile get and set functions for the device to allow -// persistent data to be accessed. This is implemented as part of deviceCommon so that the majority -// of devices don't need to implement it and can just embed deviceCommon. -func (d *deviceCommon) init(inst instance.Instance, state *state.State, name string, conf deviceConfig.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) { - d.inst = inst - d.name = name - d.config = conf - d.state = state - d.volatileGet = volatileGet - d.volatileSet = volatileSet -} - -// Add returns nil error as majority of devices don't need to do any host-side setup. -func (d *deviceCommon) Add() error { - return nil -} - -// Register returns nil error as majority of devices don't need to do any event registration. -func (d *deviceCommon) Register() error { - return nil -} - -// CanHotPlug returns true as majority of devices can be started/stopped when instance is running. -// Also returns an empty list of update fields as most devices do not support live updates. -func (d *deviceCommon) CanHotPlug() (bool, []string) { - return true, []string{} -} - -// Update returns an error as most devices do not support live updates without being restarted. -func (d *deviceCommon) Update(oldDevices deviceConfig.Devices, isRunning bool) error { - return fmt.Errorf("Device does not support updates whilst started") -} - -// Remove returns nil error as majority of devices don't need to do any host-side cleanup on delete. -func (d *deviceCommon) Remove() error { - return nil -} - -// New instantiates a new device struct, validates the supplied config and sets it into the device. -// If the device type is valid, but the other config validation fails then an instantiated device -// is still returned with the validation error. If an unknown device is requested or the device is -// not compatible with the instance type then an ErrUnsupportedDevType error is returned. -func New(inst instance.Instance, state *state.State, name string, conf deviceConfig.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (Device, error) { - if conf["type"] == "" { - return nil, fmt.Errorf("Missing device type for device '%s'", name) - } - - devFunc := devTypes[conf["type"]] - - // Check if top-level type is recognised, if it is known type it will return a function. - if devFunc == nil { - return nil, ErrUnsupportedDevType - } - - // Run the device create function and check it succeeds. - dev := devFunc(conf) - if dev == nil { - return nil, ErrUnsupportedDevType - } - - // Init the device and run validation of supplied config. - dev.init(inst, state, name, conf, volatileGet, volatileSet) - err := dev.validateConfig() - - // We still return the instantiated device here, as in some scenarios the caller - // may still want to use the device (such as when stopping or removing) even if - // the config validation has failed. - return dev, err -} From 9790359629cda3a0505274a8e916794891482f57 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:25:58 +0000 Subject: [PATCH 03/12] lxd/device/device/interface: Splits device interfaces into own file Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/device_interface.go | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 lxd/device/device_interface.go diff --git a/lxd/device/device_interface.go b/lxd/device/device_interface.go new file mode 100644 index 0000000000..52fc2edf89 --- /dev/null +++ b/lxd/device/device_interface.go @@ -0,0 +1,66 @@ +package device + +import ( + deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" + "github.com/lxc/lxd/lxd/state" +) + +// VolatileSetter is a function that accepts one or more key/value strings to save into the LXD +// config for this instance. It should add the volatile device name prefix to each key when saving. +type VolatileSetter func(map[string]string) error + +// VolatileGetter is a function that retrieves any key/value string that exists in the LXD database +// config for this instance. It should only return keys that match the volatile device name prefix, +// and should remove the prefix before being returned. +type VolatileGetter func() map[string]string + +// Device represents a device that can be added to an instance. +type Device interface { + // CanHotPlug returns true if device can be managed whilst instance is running. + // It also returns a slice of config fields that can be live updated. If only fields in this + // list have changed then Update() is called rather than triggering a device remove & add. + CanHotPlug() (bool, []string) + + // Add performs any host-side setup when a device is added to an instance. + // It is called irrespective of whether the instance is running or not. + Add() error + + // Start peforms any host-side configuration required to start the device for the instance. + // This can be when a device is plugged into a running instance or the instance is starting. + // Returns run-time configuration needed for configuring the instance with the new device. + Start() (*deviceConfig.RunConfig, error) + + // Register provides the ability for a device to subcribe to events that LXD can generate. + // It is called after a device is started (after Start()) or when LXD starts. + Register() error + + // Update performs host-side modifications for a device based on the difference between the + // current config and previous devices config supplied as an argument. This called if the + // only config fields that have changed are supplied in the list returned from CanHotPlug(). + // The function also accepts a boolean indicating whether the instance is running or not. + Update(oldDevices deviceConfig.Devices, running bool) error + + // Stop performs any host-side cleanup required when a device is removed from an instance, + // either due to unplugging it from a running instance or instance is being shutdown. + // Returns run-time configuration needed for detaching the device from the instance. + Stop() (*deviceConfig.RunConfig, error) + + // Remove performs any host-side cleanup when an instance is removed from an instance. + Remove() error +} + +// device represents a sealed interface that implements Device, but also contains some internal +// setup functions for a Device that should only be called by device.New() to avoid exposing devices +// that are not in a known configured state. This is separate from the Device interface so that +// Devices created outside of the device package can be used by LXD, but ensures that any devices +// created by the device package will only be accessible after being configured properly by New(). +type device interface { + Device + + // init stores the Instance, daemon State and Config into device and performs any setup. + init(instance.Instance, *state.State, string, deviceConfig.Device, VolatileGetter, VolatileSetter) + + // validateConfig checks Config stored by init() is valid for the instance type. + validateConfig(instance.ConfigReader) error +} From 48c183cd0cee7fab25b872de295b06520928bd21 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:27:10 +0000 Subject: [PATCH 04/12] lxd/device/device/load: Separates device load functions into own file Adds Validate() function for validating devices without needing a concrete instance. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/device_load.go | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lxd/device/device_load.go diff --git a/lxd/device/device_load.go b/lxd/device/device_load.go new file mode 100644 index 0000000000..1227dba7bb --- /dev/null +++ b/lxd/device/device_load.go @@ -0,0 +1,77 @@ +package device + +import ( + "fmt" + + deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" + "github.com/lxc/lxd/lxd/state" +) + +// devTypes defines supported top-level device type creation functions. +var devTypes = map[string]func(deviceConfig.Device) device{ + "nic": nicLoadByType, + "infiniband": infinibandLoadByType, + "proxy": func(c deviceConfig.Device) device { return &proxy{} }, + "gpu": func(c deviceConfig.Device) device { return &gpu{} }, + "usb": func(c deviceConfig.Device) device { return &usb{} }, + "unix-char": func(c deviceConfig.Device) device { return &unixCommon{} }, + "unix-block": func(c deviceConfig.Device) device { return &unixCommon{} }, + "unix-hotplug": func(c deviceConfig.Device) device { return &unixHotplug{} }, + "disk": func(c deviceConfig.Device) device { return &disk{} }, + "none": func(c deviceConfig.Device) device { return &none{} }, +} + +// load instantiates a device and initialises its internal state. It does not validate the config supplied. +func load(inst instance.Instance, state *state.State, name string, conf deviceConfig.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (device, error) { + if conf["type"] == "" { + return nil, fmt.Errorf("Missing device type for device %q", name) + } + + devFunc := devTypes[conf["type"]] + + // Check if top-level type is recognised, if it is known type it will return a function. + if devFunc == nil { + return nil, ErrUnsupportedDevType + } + + // Run the device create function and check it succeeds. + dev := devFunc(conf) + if dev == nil { + return nil, ErrUnsupportedDevType + } + + // Setup the device's internal variables. + dev.init(inst, state, name, conf, volatileGet, volatileSet) + + return dev, nil +} + +// New instantiates a new device struct, validates the supplied config and sets it into the device. +// If the device type is valid, but the other config validation fails then an instantiated device +// is still returned with the validation error. If an unknown device is requested or the device is +// not compatible with the instance type then an ErrUnsupportedDevType error is returned. +func New(inst instance.Instance, state *state.State, name string, conf deviceConfig.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (Device, error) { + dev, err := load(inst, state, name, conf, volatileGet, volatileSet) + if err != nil { + return nil, err + } + + err = dev.validateConfig(inst) + + // We still return the instantiated device here, as in some scenarios the caller + // may still want to use the device (such as when stopping or removing) even if + // the config validation has failed. + return dev, err +} + +// Validate checks a device's config is valid. This only requires an instance.ConfigReader rather than an full +// blown instance to allow profile devices to be validated too. +func Validate(instConfig instance.ConfigReader, state *state.State, name string, conf deviceConfig.Device) error { + dev, err := load(nil, state, name, conf, nil, nil) + if err != nil { + return err + } + + return dev.validateConfig(instConfig) +} From 7c6e99090383a62ed3d7ea50e6e167f8a287b942 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:27:53 +0000 Subject: [PATCH 05/12] lxd/instance/drivers/driver/common: Adds common driver type Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/instance/drivers/driver_common.go | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 lxd/instance/drivers/driver_common.go diff --git a/lxd/instance/drivers/driver_common.go b/lxd/instance/drivers/driver_common.go new file mode 100644 index 0000000000..10d70c9dc1 --- /dev/null +++ b/lxd/instance/drivers/driver_common.go @@ -0,0 +1,74 @@ +package drivers + +import ( + "github.com/lxc/lxd/lxd/db" + deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance/instancetype" + "github.com/lxc/lxd/lxd/state" + "github.com/lxc/lxd/shared/api" +) + +// common provides structure common to all instance types. +type common struct { + dbType instancetype.Type + expandedConfig map[string]string + expandedDevices deviceConfig.Devices + localConfig map[string]string + localDevices deviceConfig.Devices + profiles []string + project string + state *state.State +} + +// Type returns the instance's type. +func (c *common) Type() instancetype.Type { + return c.dbType +} + +// ExpandedConfig returns instance's expanded config. +func (c *common) ExpandedConfig() map[string]string { + return c.expandedConfig +} + +// ExpandedDevices returns instance's expanded device config. +func (c *common) ExpandedDevices() deviceConfig.Devices { + return c.expandedDevices +} + +// LocalConfig returns the instance's local config. +func (c *common) LocalConfig() map[string]string { + return c.localConfig +} + +// LocalDevices returns the instance's local device config. +func (c *common) LocalDevices() deviceConfig.Devices { + return c.localDevices +} + +func (c *common) expandConfig(profiles []api.Profile) error { + if profiles == nil && len(c.profiles) > 0 { + var err error + profiles, err = c.state.Cluster.ProfilesGet(c.project, c.profiles) + if err != nil { + return err + } + } + + c.expandedConfig = db.ProfilesExpandConfig(c.localConfig, profiles) + + return nil +} + +func (c *common) expandDevices(profiles []api.Profile) error { + if profiles == nil && len(c.profiles) > 0 { + var err error + profiles, err = c.state.Cluster.ProfilesGet(c.project, c.profiles) + if err != nil { + return err + } + } + + c.expandedDevices = db.ProfilesExpandDevices(c.localDevices, profiles) + + return nil +} From 076616edde0ac55737fb6086a26b25e2b9b337ce Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:28:45 +0000 Subject: [PATCH 06/12] lxd/instance/instance/interface: Adds ConfigRead interface For accessing an instance's type and config only. Embeds this into existing Instance interface. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/instance/instance_interface.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lxd/instance/instance_interface.go b/lxd/instance/instance_interface.go index 59a39167ad..1018ddf780 100644 --- a/lxd/instance/instance_interface.go +++ b/lxd/instance/instance_interface.go @@ -14,8 +14,19 @@ import ( "github.com/lxc/lxd/shared/api" ) +// ConfigReader is used to read instance config. +type ConfigReader interface { + Type() instancetype.Type + ExpandedConfig() map[string]string + ExpandedDevices() deviceConfig.Devices + LocalConfig() map[string]string + LocalDevices() deviceConfig.Devices +} + // The Instance interface. type Instance interface { + ConfigReader + // Instance actions. Freeze() error Shutdown(timeout time.Duration) error @@ -71,15 +82,11 @@ type Instance interface { Location() string Project() string Name() string - Type() instancetype.Type Description() string Architecture() int CreationDate() time.Time LastUsedDate() time.Time - ExpandedConfig() map[string]string - ExpandedDevices() deviceConfig.Devices - LocalConfig() map[string]string - LocalDevices() deviceConfig.Devices + Profiles() []string InitPID() int State() string From e319b22496359e2718cd6ff3043b7eee8b63ead6 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:30:00 +0000 Subject: [PATCH 07/12] lxd/instance/drivers/load: Updates validDevices() to use device.Validate function This avoids needing to instantiate a concrete instance type for profile validation. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/instance/drivers/load.go | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/lxd/instance/drivers/load.go b/lxd/instance/drivers/load.go index 018ad0fb34..a77e55f8a0 100644 --- a/lxd/instance/drivers/load.go +++ b/lxd/instance/drivers/load.go @@ -47,40 +47,27 @@ func load(s *state.State, args db.InstanceArgs, profiles []api.Profile) (instanc } // validDevices validate instance device configs. -func validDevices(state *state.State, cluster *db.Cluster, instanceType instancetype.Type, instanceName string, devices deviceConfig.Devices, expanded bool) error { +func validDevices(state *state.State, cluster *db.Cluster, instanceType instancetype.Type, devices deviceConfig.Devices, expanded bool) error { // Empty device list if devices == nil { return nil } - // Create temporary InstanceArgs, populate it's name, localDevices and expandedDevices properties based - // on the mode of validation occurring. In non-expanded validation expensive checks should be avoided. - instArgs := db.InstanceArgs{ - Name: instanceName, - Type: instanceType, - Devices: devices.Clone(), // Prevent devices from modifying their config. + instConf := &common{ + dbType: instanceType, + localDevices: devices.Clone(), } - var expandedDevices deviceConfig.Devices + // In non-expanded validation expensive checks should be avoided. if expanded { // The devices being validated are already expanded, so just use the same // devices clone as we used for the main devices config. - expandedDevices = instArgs.Devices - } - - // Create a temporary Instance for use in device validation. - var inst instance.Instance - if instArgs.Type == instancetype.Container { - inst = LXCInstantiate(state, instArgs, expandedDevices) - } else if instArgs.Type == instancetype.VM { - inst = qemuInstantiate(state, instArgs, expandedDevices) - } else { - return fmt.Errorf("Invalid instance type") + instConf.expandedDevices = instConf.localDevices } // Check each device individually using the device package. for name, config := range devices { - _, err := device.New(inst, state, name, config, nil, nil) + err := device.Validate(instConf, state, name, config) if err != nil { return errors.Wrapf(err, "Device validation failed %q", name) } From feb032e1dc5b924ea790b07aaee9d25dc0c945e2 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:30:41 +0000 Subject: [PATCH 08/12] lxd/instance/instance/utils: Removes instanceName from validateDevices function Reinforces that device validation doesn't need instance name, as we might be validating profile devices. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/instance/instance_utils.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go index 9dbc6e8d1c..b418f90dac 100644 --- a/lxd/instance/instance_utils.go +++ b/lxd/instance/instance_utils.go @@ -32,11 +32,8 @@ import ( "github.com/lxc/lxd/shared/version" ) -// ProfileValidationName is an indicator that the instance is just being used for profile validation. -const ProfileValidationName = "" - // ValidDevices is linked from instance/drivers.validDevices to validate device config. -var ValidDevices func(state *state.State, cluster *db.Cluster, instanceType instancetype.Type, instanceName string, devices deviceConfig.Devices, expanded bool) error +var ValidDevices func(state *state.State, cluster *db.Cluster, instanceType instancetype.Type, devices deviceConfig.Devices, expanded bool) error // Load is linked from instance/drivers.load to allow different instance types to be loaded. var Load func(s *state.State, args db.InstanceArgs, profiles []api.Profile) (Instance, error) From 451c7509242e5142c4dc187fa9e697f715235d28 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:33:09 +0000 Subject: [PATCH 09/12] lxd/instance/drivers/driver/qemu: Embeds common type and removes dupe functionality Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/instance/drivers/driver_qemu.go | 101 ++++++---------------------- 1 file changed, 21 insertions(+), 80 deletions(-) diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go index 556b1bc32a..f816561b0a 100644 --- a/lxd/instance/drivers/driver_qemu.go +++ b/lxd/instance/drivers/driver_qemu.go @@ -32,7 +32,6 @@ import ( deviceConfig "github.com/lxc/lxd/lxd/device/config" "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/drivers/qmp" - "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/instance/operationlock" "github.com/lxc/lxd/lxd/maas" "github.com/lxc/lxd/lxd/operations" @@ -84,20 +83,22 @@ func qemuLoad(s *state.State, args db.InstanceArgs, profiles []api.Profile) (ins // have access to the profiles used to do it. This can be safely passed as nil if not required. func qemuInstantiate(s *state.State, args db.InstanceArgs, expandedDevices deviceConfig.Devices) *qemu { vm := &qemu{ - state: s, + common: common{ + dbType: args.Type, + localConfig: args.Config, + localDevices: args.Devices, + project: args.Project, + state: s, + profiles: args.Profiles, + }, id: args.ID, - project: args.Project, name: args.Name, description: args.Description, ephemeral: args.Ephemeral, architecture: args.Architecture, - dbType: args.Type, snapshot: args.Snapshot, creationDate: args.CreationDate, lastUsedDate: args.LastUsedDate, - profiles: args.Profiles, - localConfig: args.Config, - localDevices: args.Devices, stateful: args.Stateful, node: args.Node, expiryDate: args.ExpiryDate, @@ -128,22 +129,24 @@ func qemuInstantiate(s *state.State, args db.InstanceArgs, expandedDevices devic func qemuCreate(s *state.State, args db.InstanceArgs) (instance.Instance, error) { // Create the instance struct. vm := &qemu{ - state: s, + common: common{ + dbType: args.Type, + localConfig: args.Config, + localDevices: args.Devices, + state: s, + profiles: args.Profiles, + project: args.Project, + }, id: args.ID, - project: args.Project, name: args.Name, node: args.Node, description: args.Description, ephemeral: args.Ephemeral, architecture: args.Architecture, - dbType: args.Type, snapshot: args.Snapshot, stateful: args.Stateful, creationDate: args.CreationDate, lastUsedDate: args.LastUsedDate, - profiles: args.Profiles, - localConfig: args.Config, - localDevices: args.Devices, expiryDate: args.ExpiryDate, } @@ -191,7 +194,7 @@ func qemuCreate(s *state.State, args db.InstanceArgs) (instance.Instance, error) return nil, err } - err = instance.ValidDevices(s, s.Cluster, vm.Type(), vm.Name(), vm.expandedDevices, true) + err = instance.ValidDevices(s, s.Cluster, vm.Type(), vm.expandedDevices, true) if err != nil { logger.Error("Failed creating instance", ctxMap) return nil, errors.Wrap(err, "Invalid devices") @@ -255,28 +258,19 @@ func qemuCreate(s *state.State, args db.InstanceArgs) (instance.Instance, error) // qemu is the QEMU virtual machine driver. type qemu struct { + common + // Properties. architecture int - dbType instancetype.Type snapshot bool creationDate time.Time lastUsedDate time.Time ephemeral bool id int - project string name string description string stateful bool - // Config. - expandedConfig map[string]string - expandedDevices deviceConfig.Devices - localConfig map[string]string - localDevices deviceConfig.Devices - profiles []string - - state *state.State - // Clustering. node string @@ -1977,7 +1971,7 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error { } // Validate the new devices without using expanded devices validation (expensive checks disabled). - err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), vm.Name(), args.Devices, false) + err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), args.Devices, false) if err != nil { return errors.Wrap(err, "Invalid devices") } @@ -2161,7 +2155,7 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error { } // Do full expanded validation of the devices diff. - err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), vm.Name(), vm.expandedDevices, true) + err = instance.ValidDevices(vm.state, vm.state.Cluster, vm.Type(), vm.expandedDevices, true) if err != nil { return errors.Wrap(err, "Invalid expanded devices") } @@ -3265,11 +3259,6 @@ func (vm *qemu) Name() string { return vm.name } -// Type returns the instance's type. -func (vm *qemu) Type() instancetype.Type { - return vm.dbType -} - // Description returns the instance's description. func (vm *qemu) Description() string { return vm.description @@ -3290,54 +3279,6 @@ func (vm *qemu) LastUsedDate() time.Time { return vm.lastUsedDate } -func (vm *qemu) expandConfig(profiles []api.Profile) error { - if profiles == nil && len(vm.profiles) > 0 { - var err error - profiles, err = vm.state.Cluster.ProfilesGet(vm.project, vm.profiles) - if err != nil { - return err - } - } - - vm.expandedConfig = db.ProfilesExpandConfig(vm.localConfig, profiles) - - return nil -} - -func (vm *qemu) expandDevices(profiles []api.Profile) error { - if profiles == nil && len(vm.profiles) > 0 { - var err error - profiles, err = vm.state.Cluster.ProfilesGet(vm.project, vm.profiles) - if err != nil { - return err - } - } - - vm.expandedDevices = db.ProfilesExpandDevices(vm.localDevices, profiles) - - return nil -} - -// ExpandedConfig returns instance's expanded config. -func (vm *qemu) ExpandedConfig() map[string]string { - return vm.expandedConfig -} - -// ExpandedDevices returns instance's expanded device config. -func (vm *qemu) ExpandedDevices() deviceConfig.Devices { - return vm.expandedDevices -} - -// LocalConfig returns the instance's local config. -func (vm *qemu) LocalConfig() map[string]string { - return vm.localConfig -} - -// LocalDevices returns the instance's local device config. -func (vm *qemu) LocalDevices() deviceConfig.Devices { - return vm.localDevices -} - // Profiles returns the instance's profiles. func (vm *qemu) Profiles() []string { return vm.profiles From a7aa674072371bff94719b417c2b5817705f126b Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:33:58 +0000 Subject: [PATCH 10/12] lxd: instance.ValidDevices usage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container.go | 2 +- lxd/container_lxc.go | 6 +++--- lxd/profiles.go | 5 ++--- lxd/profiles_utils.go | 5 ++--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lxd/container.go b/lxd/container.go index 844fe79b75..5283d13ec3 100644 --- a/lxd/container.go +++ b/lxd/container.go @@ -689,7 +689,7 @@ func instanceCreateInternal(s *state.State, args db.InstanceArgs) (instance.Inst } // Validate container devices with the supplied container name and devices. - err = instance.ValidDevices(s, s.Cluster, args.Type, args.Name, args.Devices, false) + err = instance.ValidDevices(s, s.Cluster, args.Type, args.Devices, false) if err != nil { return nil, errors.Wrap(err, "Invalid devices") } diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index 6e162807b4..95a6a939fc 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -205,7 +205,7 @@ func containerLXCCreate(s *state.State, args db.InstanceArgs) (instance.Instance return nil, err } - err = instance.ValidDevices(s, s.Cluster, c.Type(), c.Name(), c.expandedDevices, true) + err = instance.ValidDevices(s, s.Cluster, c.Type(), c.expandedDevices, true) if err != nil { c.Delete() logger.Error("Failed creating container", ctxMap) @@ -3922,7 +3922,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error { } // Validate the new devices without using expanded devices validation (expensive checks disabled). - err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), c.Name(), args.Devices, false) + err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), args.Devices, false) if err != nil { return errors.Wrap(err, "Invalid devices") } @@ -4113,7 +4113,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error { } // Do full expanded validation of the devices diff. - err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), c.Name(), c.expandedDevices, true) + err = instance.ValidDevices(c.state, c.state.Cluster, c.Type(), c.expandedDevices, true) if err != nil { return errors.Wrap(err, "Invalid expanded devices") } diff --git a/lxd/profiles.go b/lxd/profiles.go index df37752ecb..590a8df759 100644 --- a/lxd/profiles.go +++ b/lxd/profiles.go @@ -109,9 +109,8 @@ func profilesPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - // Validate instance devices with an ProfileValidationName instanceName to indicate profile validation. - // At this point we don't know the instance type, so just use Container type for validation. - err = instance.ValidDevices(d.State(), d.cluster, instancetype.Container, instance.ProfileValidationName, deviceConfig.NewDevices(req.Devices), false) + // At this point we don't know the instance type, so just use instancetype.Any type for validation. + err = instance.ValidDevices(d.State(), d.cluster, instancetype.Any, deviceConfig.NewDevices(req.Devices), false) if err != nil { return response.BadRequest(err) } diff --git a/lxd/profiles_utils.go b/lxd/profiles_utils.go index b2e00869e4..a2e050fed7 100644 --- a/lxd/profiles_utils.go +++ b/lxd/profiles_utils.go @@ -21,9 +21,8 @@ func doProfileUpdate(d *Daemon, project, name string, id int64, profile *api.Pro return err } - // Validate instance devices with ProfileValidationName name to indicate profile validation. - // At this point we don't know the instance type, so just use Container type for validation. - err = instance.ValidDevices(d.State(), d.cluster, instancetype.Container, instance.ProfileValidationName, deviceConfig.NewDevices(req.Devices), false) + // At this point we don't know the instance type, so just use instancetype.Any type for validation. + err = instance.ValidDevices(d.State(), d.cluster, instancetype.Any, deviceConfig.NewDevices(req.Devices), false) if err != nil { return err } From 2a0af09f06482bda5fbf9b6d9fd7d57c6204b4eb Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:44:49 +0000 Subject: [PATCH 11/12] lxd/device/device/utils/instance: Adds instanceSupported function Helper function to check instance type matches instancetype.Any or one of the instance types supplied. The instancetype.Any is always supported to allow mixed-instance type profile validation to be supported. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/device_utils_instance.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lxd/device/device_utils_instance.go b/lxd/device/device_utils_instance.go index d001461ee5..2d808c3055 100644 --- a/lxd/device/device_utils_instance.go +++ b/lxd/device/device_utils_instance.go @@ -6,6 +6,7 @@ import ( deviceConfig "github.com/lxc/lxd/lxd/device/config" "github.com/lxc/lxd/lxd/instance" + "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/state" ) @@ -54,3 +55,20 @@ func instanceGetReservedDevices(s *state.State, m deviceConfig.Device) (map[stri return reservedDevices, nil } + +// instanceSupported is a helper function to check instance type is supported for validation. +// Always returns true if supplied instance type is Any, to support profile validation. +func instanceSupported(instType instancetype.Type, supportedTypes ...instancetype.Type) bool { + // If instance type is Any, then profile validation is occurring and we need to support this. + if instType == instancetype.Any { + return true + } + + for _, supportedType := range supportedTypes { + if instType == supportedType { + return true + } + } + + return false +} From 0ba74d0e96a4b2f004ad174bcf84d1c4f304316b Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Thu, 30 Jan 2020 13:46:18 +0000 Subject: [PATCH 12/12] lxd/device: Updates device validateConfig to support instance.ConfigReader argument Switches validation implementations to use instance.ConfigReader argument so profile validation can occur without a concrete instance being supplied. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/disk.go | 19 +++++++++---------- lxd/device/gpu.go | 5 +++-- lxd/device/infiniband_physical.go | 5 +++-- lxd/device/infiniband_sriov.go | 5 +++-- lxd/device/nic_bridged.go | 5 +++-- lxd/device/nic_ipvlan.go | 5 +++-- lxd/device/nic_macvlan.go | 5 +++-- lxd/device/nic_p2p.go | 5 +++-- lxd/device/nic_physical.go | 7 ++++--- lxd/device/nic_routed.go | 5 +++-- lxd/device/nic_sriov.go | 7 ++++--- lxd/device/none.go | 3 ++- lxd/device/proxy.go | 5 +++-- lxd/device/unix_common.go | 5 +++-- lxd/device/unix_hotplug.go | 5 +++-- lxd/device/usb.go | 5 +++-- 16 files changed, 55 insertions(+), 41 deletions(-) diff --git a/lxd/device/disk.go b/lxd/device/disk.go index f2b4eb00c6..ada9b9d2a2 100644 --- a/lxd/device/disk.go +++ b/lxd/device/disk.go @@ -49,8 +49,8 @@ func (d *disk) isRequired(devConfig deviceConfig.Device) bool { } // validateConfig checks the supplied config for correctness. -func (d *disk) validateConfig() error { - if d.inst.Type() != instancetype.Container && d.inst.Type() != instancetype.VM { +func (d *disk) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) { return ErrUnsupportedDevType } @@ -87,9 +87,9 @@ func (d *disk) validateConfig() error { // VMs don't use the "path" property, but containers need it, so if we are validating a profile that can // be used for all instance types, we must allow any value. - if d.inst.Name() == instance.ProfileValidationName { + if instConf.Type() == instancetype.Any { rules["path"] = shared.IsAny - } else if d.inst.Type() == instancetype.Container || d.config["path"] == "/" { + } else if instConf.Type() == instancetype.Container || d.config["path"] == "/" { // If we are validating a container or the root device is being validated, then require the value. rules["path"] = shared.IsNotEmpty } @@ -133,7 +133,7 @@ func (d *disk) validateConfig() error { // same path, so that if merged profiles share the same the path and then one is removed // this can still be cleanly removed. pathCount := 0 - for _, devConfig := range d.inst.LocalDevices() { + for _, devConfig := range instConf.LocalDevices() { if devConfig["type"] == "disk" && d.config["path"] != "" && devConfig["path"] == d.config["path"] { pathCount++ if pathCount > 1 { @@ -165,11 +165,10 @@ func (d *disk) validateConfig() error { return fmt.Errorf("The \"%s\" storage pool doesn't exist", d.config["pool"]) } - // Only check storate volume is available if we are validating an instance device - // and not a profile device (check for ProfileValidationName name), and we have least - // one expanded device (this is so we only do this expensive check after devices - // have been expanded). - if d.inst.Name() != instance.ProfileValidationName && len(d.inst.ExpandedDevices()) > 0 && d.config["source"] != "" && d.config["path"] != "/" { + // Only check storate volume is available if we are validating an instance device and not a profile + // device (check for instancetype.Any), and we have least one expanded device (this is so we only + // do this expensive check after devices have been expanded). + if instConf.Type() != instancetype.Any && len(instConf.ExpandedDevices()) > 0 && d.config["source"] != "" && d.config["path"] != "/" { isAvailable, err := d.state.Cluster.StorageVolumeIsAvailable(d.config["pool"], d.config["source"]) if err != nil { return fmt.Errorf("Check if volume is available: %v", err) diff --git a/lxd/device/gpu.go b/lxd/device/gpu.go index 30c5888040..9bb4c39c71 100644 --- a/lxd/device/gpu.go +++ b/lxd/device/gpu.go @@ -12,6 +12,7 @@ import ( "golang.org/x/sys/unix" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/resources" "github.com/lxc/lxd/shared" @@ -31,8 +32,8 @@ type gpu struct { } // validateConfig checks the supplied config for correctness. -func (d *gpu) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *gpu) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/infiniband_physical.go b/lxd/device/infiniband_physical.go index 482f39d817..2c0edefbc6 100644 --- a/lxd/device/infiniband_physical.go +++ b/lxd/device/infiniband_physical.go @@ -4,6 +4,7 @@ import ( "fmt" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/resources" "github.com/lxc/lxd/shared" @@ -14,8 +15,8 @@ type infinibandPhysical struct { } // validateConfig checks the supplied config for correctness. -func (d *infinibandPhysical) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *infinibandPhysical) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/infiniband_sriov.go b/lxd/device/infiniband_sriov.go index b6932e9753..305967a032 100644 --- a/lxd/device/infiniband_sriov.go +++ b/lxd/device/infiniband_sriov.go @@ -4,6 +4,7 @@ import ( "fmt" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/resources" "github.com/lxc/lxd/shared" @@ -15,8 +16,8 @@ type infinibandSRIOV struct { } // validateConfig checks the supplied config for correctness. -func (d *infinibandSRIOV) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *infinibandSRIOV) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go index 699caddf5a..eb93964ffd 100644 --- a/lxd/device/nic_bridged.go +++ b/lxd/device/nic_bridged.go @@ -23,6 +23,7 @@ import ( deviceConfig "github.com/lxc/lxd/lxd/device/config" "github.com/lxc/lxd/lxd/dnsmasq" firewallConsts "github.com/lxc/lxd/lxd/firewall/consts" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" @@ -48,8 +49,8 @@ type nicBridged struct { } // validateConfig checks the supplied config for correctness. -func (d *nicBridged) validateConfig() error { - if d.inst.Type() != instancetype.Container && d.inst.Type() != instancetype.VM { +func (d *nicBridged) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) { return ErrUnsupportedDevType } diff --git a/lxd/device/nic_ipvlan.go b/lxd/device/nic_ipvlan.go index 75c8227f8f..92ae30174e 100644 --- a/lxd/device/nic_ipvlan.go +++ b/lxd/device/nic_ipvlan.go @@ -5,6 +5,7 @@ import ( "strings" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" @@ -19,8 +20,8 @@ func (d *nicIPVLAN) CanHotPlug() (bool, []string) { } // validateConfig checks the supplied config for correctness. -func (d *nicIPVLAN) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *nicIPVLAN) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go index 03d34a9e47..46d67dd429 100644 --- a/lxd/device/nic_macvlan.go +++ b/lxd/device/nic_macvlan.go @@ -4,6 +4,7 @@ import ( "fmt" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/revert" "github.com/lxc/lxd/shared" @@ -14,8 +15,8 @@ type nicMACVLAN struct { } // validateConfig checks the supplied config for correctness. -func (d *nicMACVLAN) validateConfig() error { - if d.inst.Type() != instancetype.Container && d.inst.Type() != instancetype.VM { +func (d *nicMACVLAN) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) { return ErrUnsupportedDevType } diff --git a/lxd/device/nic_p2p.go b/lxd/device/nic_p2p.go index 2043597110..e0882a8b27 100644 --- a/lxd/device/nic_p2p.go +++ b/lxd/device/nic_p2p.go @@ -4,6 +4,7 @@ import ( "fmt" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/shared" ) @@ -13,8 +14,8 @@ type nicP2P struct { } // validateConfig checks the supplied config for correctness. -func (d *nicP2P) validateConfig() error { - if d.inst.Type() != instancetype.Container && d.inst.Type() != instancetype.VM { +func (d *nicP2P) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) { return ErrUnsupportedDevType } diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go index b8d4662b72..f8627373d7 100644 --- a/lxd/device/nic_physical.go +++ b/lxd/device/nic_physical.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/revert" "github.com/lxc/lxd/lxd/util" @@ -17,8 +18,8 @@ type nicPhysical struct { } // validateConfig checks the supplied config for correctness. -func (d *nicPhysical) validateConfig() error { - if d.inst.Type() != instancetype.Container && d.inst.Type() != instancetype.VM { +func (d *nicPhysical) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) { return ErrUnsupportedDevType } @@ -30,7 +31,7 @@ func (d *nicPhysical) validateConfig() error { "boot.priority", } - if d.inst.Type() == instancetype.Container { + if instConf.Type() == instancetype.Container { optionalFields = append(optionalFields, "mtu", "hwaddr", "vlan") } diff --git a/lxd/device/nic_routed.go b/lxd/device/nic_routed.go index 6077ce41bc..6198c1fb9c 100644 --- a/lxd/device/nic_routed.go +++ b/lxd/device/nic_routed.go @@ -5,6 +5,7 @@ import ( "strings" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" @@ -22,8 +23,8 @@ func (d *nicRouted) CanHotPlug() (bool, []string) { } // validateConfig checks the supplied config for correctness. -func (d *nicRouted) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *nicRouted) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go index 9269604381..572670616e 100644 --- a/lxd/device/nic_sriov.go +++ b/lxd/device/nic_sriov.go @@ -11,6 +11,7 @@ import ( "strings" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/revert" "github.com/lxc/lxd/shared" @@ -21,8 +22,8 @@ type nicSRIOV struct { } // validateConfig checks the supplied config for correctness. -func (d *nicSRIOV) validateConfig() error { - if d.inst.Type() != instancetype.Container && d.inst.Type() != instancetype.VM { +func (d *nicSRIOV) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) { return ErrUnsupportedDevType } @@ -38,7 +39,7 @@ func (d *nicSRIOV) validateConfig() error { } // For VMs only NIC properties that can be specified on the parent's VF settings are controllable. - if d.inst.Type() == instancetype.Container { + if instConf.Type() == instancetype.Container { optionalFields = append(optionalFields, "mtu") } diff --git a/lxd/device/none.go b/lxd/device/none.go index 44026a1933..dcd2a70dba 100644 --- a/lxd/device/none.go +++ b/lxd/device/none.go @@ -2,6 +2,7 @@ package device import ( deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" ) type none struct { @@ -9,7 +10,7 @@ type none struct { } // validateConfig checks the supplied config for correctness. -func (d *none) validateConfig() error { +func (d *none) validateConfig(instConf instance.ConfigReader) error { rules := map[string]func(string) error{} // No fields allowed. err := d.config.Validate(rules) if err != nil { diff --git a/lxd/device/proxy.go b/lxd/device/proxy.go index 1ac382907c..77a1394575 100644 --- a/lxd/device/proxy.go +++ b/lxd/device/proxy.go @@ -17,6 +17,7 @@ import ( deviceConfig "github.com/lxc/lxd/lxd/device/config" firewallConsts "github.com/lxc/lxd/lxd/firewall/consts" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/project" "github.com/lxc/lxd/shared" @@ -40,8 +41,8 @@ type proxyProcInfo struct { } // validateConfig checks the supplied config for correctness. -func (d *proxy) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *proxy) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/unix_common.go b/lxd/device/unix_common.go index ba32170f90..87de76f724 100644 --- a/lxd/device/unix_common.go +++ b/lxd/device/unix_common.go @@ -6,6 +6,7 @@ import ( "strings" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/shared" ) @@ -38,8 +39,8 @@ func (d *unixCommon) isRequired() bool { } // validateConfig checks the supplied config for correctness. -func (d *unixCommon) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *unixCommon) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/unix_hotplug.go b/lxd/device/unix_hotplug.go index 5e02f96176..628b580077 100644 --- a/lxd/device/unix_hotplug.go +++ b/lxd/device/unix_hotplug.go @@ -10,6 +10,7 @@ import ( udev "github.com/farjump/go-libudev" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/shared" ) @@ -41,8 +42,8 @@ func (d *unixHotplug) isRequired() bool { } // validateConfig checks the supplied config for correctness. -func (d *unixHotplug) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *unixHotplug) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType } diff --git a/lxd/device/usb.go b/lxd/device/usb.go index fd42b33f45..161f79a478 100644 --- a/lxd/device/usb.go +++ b/lxd/device/usb.go @@ -8,6 +8,7 @@ import ( "strings" deviceConfig "github.com/lxc/lxd/lxd/device/config" + "github.com/lxc/lxd/lxd/instance" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/shared" ) @@ -42,8 +43,8 @@ func (d *usb) isRequired() bool { } // validateConfig checks the supplied config for correctness. -func (d *usb) validateConfig() error { - if d.inst.Type() != instancetype.Container { +func (d *usb) validateConfig(instConf instance.ConfigReader) error { + if !instanceSupported(instConf.Type(), instancetype.Container) { return ErrUnsupportedDevType }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel