1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
package device
import (
"fmt"
"net"
deviceConfig "github.com/lxc/incus/v6/internal/server/device/config"
"github.com/lxc/incus/v6/internal/server/instance"
"github.com/lxc/incus/v6/internal/server/instance/instancetype"
"github.com/lxc/incus/v6/internal/server/network"
"github.com/lxc/incus/v6/internal/server/state"
"github.com/lxc/incus/v6/shared/logger"
)
// deviceCommon represents the common struct for all devices.
type deviceCommon struct {
logger logger.Logger
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, s *state.State, name string, conf deviceConfig.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) error {
logCtx := logger.Ctx{"driver": conf["type"], "device": name}
if inst != nil {
logCtx["project"] = inst.Project().Name
logCtx["instance"] = inst.Name()
}
d.logger = logger.AddContext(logCtx)
d.inst = inst
d.name = name
d.config = conf
d.state = s
d.volatileGet = volatileGet
d.volatileSet = volatileSet
return nil
}
// Name returns the name of the device.
func (d *deviceCommon) Name() string {
return d.name
}
// Config returns the config for the device.
func (d *deviceCommon) Config() deviceConfig.Device {
return d.config
}
// 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 whether the device can be managed whilst the instance is running,
// Returns true if instance type is container, as majority of devices can be started/stopped when
// instance is running. If instance type is VM then returns false as this is not currently supported.
func (d *deviceCommon) CanHotPlug() bool {
return d.inst.Type() == instancetype.Container
}
// CanMigrate returns whether the device can be migrated to any other cluster member.
func (d *deviceCommon) CanMigrate() bool {
return false
}
// UpdatableFields returns an empty list of updatable fields as most devices do not support updates.
func (d *deviceCommon) UpdatableFields(oldDevice Type) []string {
return []string{}
}
// PreStartCheck indicates if the device is available for starting.
func (d *deviceCommon) PreStartCheck() error {
return nil
}
// Update returns an ErrCannotUpdate error as most devices do not support updates.
func (d *deviceCommon) Update(oldDevices deviceConfig.Devices, isRunning bool) error {
return ErrCannotUpdate
}
// 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
}
// generateHostName generates the name to use for the host side NIC interface based on the
// instances.nic.host_name setting.
// Accepts prefix argument to use with random interface generation.
// Accepts optional hwaddr MAC address to use for generating the interface name in mac mode.
// In mac mode the interface prefix is always "inc".
func (d *deviceCommon) generateHostName(prefix string, hwaddr string) (string, error) {
hostNameMode := d.state.GlobalConfig.InstancesNICHostname()
// Handle instances.nic.host_name mac mode if a MAC address has been supplied.
if hostNameMode == "mac" && hwaddr != "" {
mac, err := net.ParseMAC(hwaddr)
if err != nil {
return "", fmt.Errorf("Failed parsing MAC address %q: %w", hwaddr, err)
}
return network.MACDevName(mac), nil
}
// Handle instances.nic.host_name random mode or where no MAC address supplied.
return network.RandomDevName(prefix), nil
}
// setNICLink sets the link status (connected/disconnected) for the given NIC.
func (d *deviceCommon) setNICLink() error {
runConf := deviceConfig.RunConfig{}
runConf.NetworkInterface = []deviceConfig.RunConfigItem{
{Key: "devName", Value: d.name},
{Key: "connected", Value: d.config["connected"]},
}
return d.inst.DeviceEventHandler(&runConf)
}
|