The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8190
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) === As requested, this is a draft pull request for issue #7869, having implemented most of the things mentioned in the most recent comments. As noted in the description of commit ead2141 the Info() function in driver_qemu.go isn't quite working yet, there's some runtime bugs that I haven't sorted out relating to finding the path of the qemu binary. Additionally, there seems to be some kind of race condition in the creation of the driver cache, as either ``lxc`` or ``qemu`` can end up appearing first in the list, though I am unsure where this would be generated so it is not listed in any particular commit.
From f74d2cd2be44a6f79e5629b5d50a56af0c9df8b4 Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Sat, 21 Nov 2020 20:17:37 -0600 Subject: [PATCH 1/7] lxd/instance: WIP support for cached drivers in /1.0 Implemented functions based on the storagePoolDriversCache system to create a cache for the lxd/qemu drivers, working on issue #7869. Because there are only two drivers to be added at this point, the creation of the cache is hard-coded to only include LXC/QEMU, though this could be expanded similar to the storage pool at a later date. The current implementation's QEMU path is hard-coded to a known functional value on my local system to ensure that the caching functionality works, and a final version will need to pull the value of qemuBinary (/qemuPath?) as described in the issue comments on github. Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/instance.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/lxd/instance.go b/lxd/instance.go index 45aed86b17..674ffa890e 100644 --- a/lxd/instance.go +++ b/lxd/instance.go @@ -8,6 +8,8 @@ import ( "path/filepath" "strconv" "strings" + "sync" + "sync/atomic" "time" "github.com/pkg/errors" @@ -932,3 +934,64 @@ func containerDetermineNextSnapshotName(d *Daemon, c instance.Instance, defaultP return pattern, nil } + +// Instance Driver Cache +// I don't forsee anything trying to simultaneously edit/read these values, but in a case of Cargo Cult Programming I'm going to go ahead +// and use the atomic value setup from the storage cache for the time being. Worst case it's a very tiny performance hit? +var instanceDriversCacheVal atomic.Value +var instanceDriversCacheLock sync.Mutex + +// Declare qemuBinary so it can be set by qemuStart for use here +var qemuPath string = "qemu-system-x86_64" //hard coded value is for testing purposes only + +//SetQemuPath Setter function for the qemuPath variable +//Attempts to call this from driver_qemu.go result in it being an undefined function in that scope. +//Clearly I'm doing something wrong. +func SetQemuPath(path string) { + qemuPath = path + return +} + +func readInstanceDriversCache() map[string]string { + // Get the cached list of instance drivers in use on this LXD instance + // and call Create if the cache is empty. + + drivers := instanceDriversCacheVal.Load() + if drivers == nil { + createInstanceDriversCache() + drivers = instanceDriversCacheVal.Load() + } + + return drivers.(map[string]string) +} + +func createInstanceDriversCache() { + // Create the list of instance drivers in use on this LXD instance + // namely LXC and QEMU. Given that LXC and QEMU cannot update while + // the LXD instance is running, this shouldn't ever be called more + // than once. + + data := map[string]string{} + + // Get LXC driver information + data["lxc"] = liblxc.Version() + + // Get QEMU driver information + + //Need to update this to use qemuBinary properly. There's also likely a more graceful way of doing the byte slice -> string conversion + out, err := exec.Command(qemuPath, "--version").Output() + + if err != nil { + data["qemu"] = "0" + } else { + fieldOut := strings.Fields(string(out)) + data["qemu"] = fieldOut[3] + } + + //Store the value in the cache + instanceDriversCacheLock.Lock() + instanceDriversCacheVal.Store(data) + instanceDriversCacheLock.Unlock() + + return +} From 72956b3a3dbfefa4225014f21d239c24c4669455 Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Sat, 21 Nov 2020 20:17:59 -0600 Subject: [PATCH 2/7] lxd/api_1.0: Add support for cached driver values Pulls the Driver and DriverVersion values from a cache to prevent hitting go-lxc repeatedly. Supports any additional drivers present in the cache, such as qemu. Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/api_1.0.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go index 72212579a2..cac3539e4d 100644 --- a/lxd/api_1.0.go +++ b/lxd/api_1.0.go @@ -6,8 +6,6 @@ import ( "os" "strings" - liblxc "gopkg.in/lxc/go-lxc.v2" - lxd "github.com/lxc/lxd/client" "github.com/lxc/lxd/lxd/cluster" "github.com/lxc/lxd/lxd/config" @@ -201,8 +199,6 @@ func api10Get(d *Daemon, r *http.Request) response.Response { Architectures: architectures, Certificate: certificate, CertificateFingerprint: certificateFingerprint, - Driver: "lxc", - DriverVersion: liblxc.Version(), Kernel: uname.Sysname, KernelArchitecture: uname.Machine, KernelVersion: uname.Release, @@ -226,6 +222,22 @@ func api10Get(d *Daemon, r *http.Request) response.Response { "shiftfs": fmt.Sprintf("%v", d.os.Shiftfs), } + instanceDrivers := readInstanceDriversCache() + for driver, version := range instanceDrivers { + if env.Driver != "" { + env.Driver = env.Driver + " | " + driver + } else { + env.Driver = driver + } + + // Get the version of the instance drivers in use. + if env.DriverVersion != "" { + env.DriverVersion = env.DriverVersion + " | " + version + } else { + env.DriverVersion = version + } + } + if d.os.LXCFeatures != nil { env.LXCFeatures = map[string]string{} for k, v := range d.os.LXCFeatures { From 79de4e522f0bef3c29803a200b2f02b970a0ec7b Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Wed, 25 Nov 2020 18:04:01 -0600 Subject: [PATCH 3/7] lxd/instance: Add support for Info() to Instance interface Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/instance/instance_interface.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lxd/instance/instance_interface.go b/lxd/instance/instance_interface.go index c096230bf3..d6d94d6d99 100644 --- a/lxd/instance/instance_interface.go +++ b/lxd/instance/instance_interface.go @@ -57,6 +57,7 @@ type Instance interface { RegisterDevices() SaveConfigFile() error + Info() Info IsPrivileged() bool // Snapshots & migration & backups. @@ -164,3 +165,9 @@ type CriuMigrationArgs struct { PreDumpDir string Features liblxc.CriuFeatures } + +// Info represents information about an instance driver. +type Info struct { + Name string // Name of an instance driver, e.g. "lxc" + Version string // Version number of a loaded instance driver +} From 257cfd19bba4d9bf6d60a29de8e48fa737c8e1ce Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Wed, 25 Nov 2020 18:06:19 -0600 Subject: [PATCH 4/7] lxd/instance/drivers: Implement Info() function Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/instance/drivers/driver_lxc.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lxd/instance/drivers/driver_lxc.go b/lxd/instance/drivers/driver_lxc.go index 054c698372..db680fe9e7 100644 --- a/lxd/instance/drivers/driver_lxc.go +++ b/lxd/instance/drivers/driver_lxc.go @@ -7042,3 +7042,11 @@ func (c *lxc) SaveConfigFile() error { return nil } + +// Returns "lxc" and the currently loaded version of LXC +func (c *lxc) Info() instance.Info { + return instance.Info{ + Name: "lxc", + Version: liblxc.Version(), + } +} From c159ffb80233550cb6c196fe39aa8137c7d74e32 Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Wed, 25 Nov 2020 18:09:41 -0600 Subject: [PATCH 5/7] lxd/instance/drivers: Add drivers package support for supported drivers. Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/instance/drivers/load.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lxd/instance/drivers/load.go b/lxd/instance/drivers/load.go index f478c75ed4..757032f351 100644 --- a/lxd/instance/drivers/load.go +++ b/lxd/instance/drivers/load.go @@ -15,6 +15,11 @@ import ( "github.com/lxc/lxd/shared/api" ) +var instanceDrivers = map[string]func() instance.Instance{ + "lxc": func() instance.Instance { return &lxc{} }, + "qemu": func() instance.Instance { return &qemu{} }, +} + func init() { // Expose load to the instance package, to avoid circular imports. instance.Load = load @@ -96,3 +101,15 @@ func create(s *state.State, args db.InstanceArgs) (instance.Instance, error) { return nil, fmt.Errorf("Instance type invalid") } + +// SupportedInstanceDrivers returns a slice of Info structs for all supported drivers +func SupportedInstanceDrivers() []instance.Info { + supportedDrivers := make([]instance.Info, 0, len(instanceDrivers)) + + for _, instanceDriver := range instanceDrivers { + driver := instanceDriver() + supportedDrivers = append(supportedDrivers, driver.Info()) + } + + return supportedDrivers +} From f2f193362cafbd0badef81d7d812f19fa65e3b9e Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Wed, 25 Nov 2020 18:12:35 -0600 Subject: [PATCH 6/7] lxd/main: Remove driver-specific logic from instance.go Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/instance.go | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/lxd/instance.go b/lxd/instance.go index 674ffa890e..a4813a7922 100644 --- a/lxd/instance.go +++ b/lxd/instance.go @@ -21,6 +21,7 @@ import ( "github.com/lxc/lxd/lxd/db" deviceConfig "github.com/lxc/lxd/lxd/device/config" "github.com/lxc/lxd/lxd/instance" + "github.com/lxc/lxd/lxd/instance/drivers" "github.com/lxc/lxd/lxd/instance/instancetype" "github.com/lxc/lxd/lxd/operations" "github.com/lxc/lxd/lxd/project" @@ -935,26 +936,10 @@ func containerDetermineNextSnapshotName(d *Daemon, c instance.Instance, defaultP return pattern, nil } -// Instance Driver Cache -// I don't forsee anything trying to simultaneously edit/read these values, but in a case of Cargo Cult Programming I'm going to go ahead -// and use the atomic value setup from the storage cache for the time being. Worst case it's a very tiny performance hit? var instanceDriversCacheVal atomic.Value var instanceDriversCacheLock sync.Mutex -// Declare qemuBinary so it can be set by qemuStart for use here -var qemuPath string = "qemu-system-x86_64" //hard coded value is for testing purposes only - -//SetQemuPath Setter function for the qemuPath variable -//Attempts to call this from driver_qemu.go result in it being an undefined function in that scope. -//Clearly I'm doing something wrong. -func SetQemuPath(path string) { - qemuPath = path - return -} - func readInstanceDriversCache() map[string]string { - // Get the cached list of instance drivers in use on this LXD instance - // and call Create if the cache is empty. drivers := instanceDriversCacheVal.Load() if drivers == nil { @@ -968,24 +953,13 @@ func readInstanceDriversCache() map[string]string { func createInstanceDriversCache() { // Create the list of instance drivers in use on this LXD instance // namely LXC and QEMU. Given that LXC and QEMU cannot update while - // the LXD instance is running, this shouldn't ever be called more - // than once. + // the LXD instance is running, only one cache is ever needed. data := map[string]string{} - // Get LXC driver information - data["lxc"] = liblxc.Version() - - // Get QEMU driver information - - //Need to update this to use qemuBinary properly. There's also likely a more graceful way of doing the byte slice -> string conversion - out, err := exec.Command(qemuPath, "--version").Output() - - if err != nil { - data["qemu"] = "0" - } else { - fieldOut := strings.Fields(string(out)) - data["qemu"] = fieldOut[3] + info := drivers.SupportedInstanceDrivers() + for _, entry := range info { + data[entry.Name] = entry.Version } //Store the value in the cache From ead2141f80ca05346b012c4f0bf59618103f1051 Mon Sep 17 00:00:00 2001 From: Alex Oliver <oliver.ale...@gmail.com> Date: Wed, 25 Nov 2020 18:26:30 -0600 Subject: [PATCH 7/7] lxd/instance/drivers: Implement Info() in driver_qemu.go There seems to be some kind of runtime bug in the code where the vm.architecture value is 0 when in this function, and as a result the binary for qemu cannot be found, and the version number cannot be properly found. Bug is reproducable on a system with qemu version 4.2.1 installed Signed-off-by: Alex J Oliver <oliver.ale...@gmail.com> --- lxd/instance/drivers/driver_qemu.go | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go index abd05b2e85..c10c116e97 100644 --- a/lxd/instance/drivers/driver_qemu.go +++ b/lxd/instance/drivers/driver_qemu.go @@ -5157,3 +5157,52 @@ func (vm *qemu) writeInstanceData() error { return nil } + +// Returns "qemu" and the currently loaded qemu version, 0 if not found. +// Unsure if this is the proper behavior for a not found, but the logic is there. +// TODO: This seems to be getting a 0 value for vm.architecture, and as a result cannot find the binary, giving a 0 for the version no. +func (vm *qemu) Info() instance.Info { + + var qemuVersion, qemuBinary, qemuPath string + var out []byte + var err error + qemuBinary, _, err = vm.qemuArchConfig() + println("vm architecture ", vm.architecture) + println("qemuBinary: " + qemuBinary) + if err == nil { + qemuPath, err = exec.LookPath(qemuBinary) + if err == nil { + out, err = exec.Command(qemuPath, "--version").Output() + if err != nil { + qemuVersion = "0" + } else { + qemuVersion = strings.Fields(string(out))[3] + } + } else { + qemuVersion = "-1" + } + } else { + qemuVersion = "-2" + } + // if err != nil { + // qemuVersion = "0" + // println("QEMUBINARY ERROR %d", err) + // } + + // qemuPath, err := exec.LookPath(qemuBinary) + // if err != nil { + // qemuVersion = "0" + // } + + //out, err = exec.Command(qemuPath, "--version").Output() + // if err != nil { + // qemuVersion = "0" + // } else { + // qemuVersion = strings.Fields(string(out))[3] + // } + + return instance.Info{ + Name: "qemu", + Version: qemuVersion, + } +}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel