[lxc-devel] [lxd/master] Cluster performance improvements
stgraber on Github
lxc-bot at linuxcontainers.org
Tue Aug 7 22:39:59 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180807/77e31c3d/attachment.bin>
-------------- next part --------------
From 500c9d8e2e92fad5619332793736ff13505bea31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 7 Aug 2018 15:53:15 -0400
Subject: [PATCH 1/6] tests: Don't leak networks
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>
---
test/suites/clustering.sh | 3 +++
1 file changed, 3 insertions(+)
diff --git a/test/suites/clustering.sh b/test/suites/clustering.sh
index f30bf0ce4b..fc909aa040 100644
--- a/test/suites/clustering.sh
+++ b/test/suites/clustering.sh
@@ -148,6 +148,9 @@ test_clustering_membership() {
LXD_DIR="${LXD_ONE_DIR}" lxc cluster remove node3
! LXD_DIR="${LXD_FOUR_DIR}" lxc cluster list
+ # Cleanup network
+ LXD_DIR="${LXD_ONE_DIR}" lxc network delete net1 --target node2
+
LXD_DIR="${LXD_FIVE_DIR}" lxd shutdown
LXD_DIR="${LXD_FOUR_DIR}" lxd shutdown
LXD_DIR="${LXD_TWO_DIR}" lxd shutdown
From 70cf50cc7b64435cbdd4b8465ba877ceee1e0438 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 7 Aug 2018 16:04:44 -0400
Subject: [PATCH 2/6] lxd/containers: Add helpers for retrieving containers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/container.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/lxd/container.go b/lxd/container.go
index b01640aa24..b245d1800d 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -1172,6 +1172,66 @@ func containerLoadByName(s *state.State, name string) (container, error) {
return containerLXCLoad(s, args)
}
+func containerLoadAll(s *state.State) ([]container, error) {
+ // Get all the container arguments
+ var cts []db.ContainerArgs
+ err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
+ var err error
+ cts, err = tx.ContainerArgsList()
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Load the container structs
+ containers := []container{}
+ for _, args := range cts {
+ ct, err := containerLXCLoad(s, args)
+ if err != nil {
+ return nil, err
+ }
+
+ containers = append(containers, ct)
+ }
+
+ return containers, nil
+}
+
+func containerLoadNodeAll(s *state.State) ([]container, error) {
+ // Get all the container arguments
+ var cts []db.ContainerArgs
+ err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
+ var err error
+ cts, err = tx.ContainerArgsNodeList()
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Load the container structs
+ containers := []container{}
+ for _, args := range cts {
+ ct, err := containerLXCLoad(s, args)
+ if err != nil {
+ return nil, err
+ }
+
+ containers = append(containers, ct)
+ }
+
+ return containers, nil
+}
+
func containerBackupLoadByName(s *state.State, name string) (*backup, error) {
// Get the DB record
args, err := s.Cluster.ContainerGetBackup(name)
From 2c27fdc8d3615a2c1d4ad21ee54b3ca70ed0ff88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 7 Aug 2018 16:35:21 -0400
Subject: [PATCH 3/6] lxd: Port over to new containerLoadNodeAll function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/containers.go | 39 ++++++++--------------------
lxd/daemon.go | 9 ++-----
lxd/devices.go | 59 +++++++++----------------------------------
lxd/devlxd.go | 10 ++------
lxd/networks_utils.go | 22 ++++++----------
5 files changed, 35 insertions(+), 104 deletions(-)
diff --git a/lxd/containers.go b/lxd/containers.go
index b7a171c441..47612014bf 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -125,19 +125,14 @@ func (slice containerAutostartList) Swap(i, j int) {
func containersRestart(s *state.State) error {
// Get all the containers
- result, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ result, err := containerLoadNodeAll(s)
if err != nil {
return err
}
containers := []container{}
- for _, name := range result {
- c, err := containerLoadByName(s, name)
- if err != nil {
- return err
- }
-
+ for _, c := range result {
containers = append(containers, c)
}
@@ -200,10 +195,11 @@ func containersShutdown(s *state.State) error {
dbAvailable := true
// Get all the containers
- results, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
// Mark database as offline
dbAvailable = false
+ containers = []container{}
// List all containers on disk
files, err := ioutil.ReadDir(shared.VarPath("containers"))
@@ -212,29 +208,16 @@ func containersShutdown(s *state.State) error {
}
for _, file := range files {
- results = append(results, file.Name())
- }
- }
-
- containers := []container{}
-
- for _, name := range results {
- var c container
- var err error
-
- if dbAvailable {
- c, err = containerLoadByName(s, name)
- } else {
- c, err = containerLXCLoad(s, db.ContainerArgs{
- Name: name,
+ c, err := containerLXCLoad(s, db.ContainerArgs{
+ Name: file.Name(),
Config: make(map[string]string),
})
- }
- if err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
- containers = append(containers, c)
+ containers = append(containers, c)
+ }
}
sort.Sort(containerStopList(containers))
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 354c493033..f8703fe4bc 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -696,18 +696,13 @@ func (d *Daemon) Ready() error {
}
func (d *Daemon) numRunningContainers() (int, error) {
- results, err := d.cluster.ContainersNodeList(db.CTypeRegular)
+ results, err := containerLoadNodeAll(d.State())
if err != nil {
return 0, err
}
count := 0
- for _, r := range results {
- container, err := containerLoadByName(d.State(), r)
- if err != nil {
- continue
- }
-
+ for _, container := range results {
if container.IsRunning() {
count = count + 1
}
diff --git a/lxd/devices.go b/lxd/devices.go
index fde7f1f174..493b14a06b 100644
--- a/lxd/devices.go
+++ b/lxd/devices.go
@@ -18,7 +18,6 @@ import (
"syscall"
"unsafe"
- "github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/state"
"github.com/lxc/lxd/lxd/sys"
"github.com/lxc/lxd/lxd/util"
@@ -652,7 +651,7 @@ func deviceTaskBalance(s *state.State) {
}
// Iterate through the containers
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
logger.Error("Problem loading containers list", log.Ctx{"err": err})
return
@@ -660,12 +659,7 @@ func deviceTaskBalance(s *state.State) {
fixedContainers := map[int][]container{}
balancedContainers := map[container]int{}
- for _, name := range containers {
- c, err := containerLoadByName(s, name)
- if err != nil {
- continue
- }
-
+ for _, c := range containers {
conf := c.ExpandedConfig()
cpulimit, ok := conf["limits.cpu"]
if !ok || cpulimit == "" {
@@ -779,18 +773,12 @@ func deviceNetworkPriority(s *state.State, netif string) {
return
}
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
return
}
- for _, name := range containers {
- // Get the container struct
- c, err := containerLoadByName(s, name)
- if err != nil {
- continue
- }
-
+ for _, c := range containers {
// Extract the current priority
networkPriority := c.ExpandedConfig()["limits.network.priority"]
if networkPriority == "" {
@@ -810,18 +798,13 @@ func deviceNetworkPriority(s *state.State, netif string) {
}
func deviceUSBEvent(s *state.State, usb usbDevice) {
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
logger.Error("Problem loading containers list", log.Ctx{"err": err})
return
}
- for _, name := range containers {
- containerIf, err := containerLoadByName(s, name)
- if err != nil {
- continue
- }
-
+ for _, containerIf := range containers {
c, ok := containerIf.(*containerLXC)
if !ok {
logger.Errorf("Got device event on non-LXC container?")
@@ -1858,19 +1841,13 @@ func deviceInotifyDirDeleteEvent(s *state.State, target *sys.InotifyTargetInfo)
}
func deviceInotifyDirRescan(s *state.State) {
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
logger.Errorf("Failed to load containers: %s", err)
return
}
- for _, name := range containers {
- containerIf, err := containerLoadByName(s, name)
- if err != nil {
- logger.Errorf("Failed to load container \"%s\": %s", name, err)
- continue
- }
-
+ for _, containerIf := range containers {
c, ok := containerIf.(*containerLXC)
if !ok {
logger.Errorf("Received device event on non-LXC container")
@@ -1923,7 +1900,7 @@ func deviceInotifyDirCreateEvent(s *state.State, target *sys.InotifyTargetInfo)
return
}
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
logger.Errorf("Failed to load containers: %s", err)
return
@@ -1936,13 +1913,7 @@ func deviceInotifyDirCreateEvent(s *state.State, target *sys.InotifyTargetInfo)
// ancestors
del := createAncestorPaths(targetName)
keep := []string{}
- for _, name := range containers {
- containerIf, err := containerLoadByName(s, name)
- if err != nil {
- logger.Errorf("Failed to load container \"%s\": %s", name, err)
- continue
- }
-
+ for _, containerIf := range containers {
c, ok := containerIf.(*containerLXC)
if !ok {
logger.Errorf("Received device event on non-LXC container")
@@ -2026,7 +1997,7 @@ func deviceInotifyFileEvent(s *state.State, target *sys.InotifyTargetInfo) {
return
}
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(s)
if err != nil {
logger.Errorf("Failed to load containers: %s", err)
return
@@ -2036,13 +2007,7 @@ func deviceInotifyFileEvent(s *state.State, target *sys.InotifyTargetInfo) {
hasWatchers := false
// The absolute path of the file for which we received an event?
targetName := filepath.Join(parent.Path, target.Path)
- for _, name := range containers {
- containerIf, err := containerLoadByName(s, name)
- if err != nil {
- logger.Errorf("Failed to load container \"%s\": %s", name, err)
- continue
- }
-
+ for _, containerIf := range containers {
c, ok := containerIf.(*containerLXC)
if !ok {
logger.Errorf("Received device event on non-LXC container")
diff --git a/lxd/devlxd.go b/lxd/devlxd.go
index cac19791e1..814e69747b 100644
--- a/lxd/devlxd.go
+++ b/lxd/devlxd.go
@@ -19,7 +19,6 @@ import (
"github.com/gorilla/websocket"
"github.com/pborman/uuid"
- "github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/logger"
@@ -467,17 +466,12 @@ func findContainerForPid(pid int32, d *Daemon) (container, error) {
return nil, err
}
- containers, err := d.cluster.ContainersNodeList(db.CTypeRegular)
+ containers, err := containerLoadNodeAll(d.State())
if err != nil {
return nil, err
}
- for _, container := range containers {
- c, err := containerLoadByName(d.State(), container)
- if err != nil {
- return nil, err
- }
-
+ for _, c := range containers {
if !c.IsRunning() {
continue
}
diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index 4c63e29dd1..684614bbf0 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -758,12 +758,6 @@ func networkUpdateStatic(s *state.State, networkName string) error {
networkStaticLock.Lock()
defer networkStaticLock.Unlock()
- // Get all the containers
- containers, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
- if err != nil {
- return err
- }
-
// Get all the networks
var networks []string
if networkName == "" {
@@ -776,15 +770,15 @@ func networkUpdateStatic(s *state.State, networkName string) error {
networks = []string{networkName}
}
+ // Get all the containers
+ containers, err := containerLoadNodeAll(s)
+ if err != nil {
+ return err
+ }
+
// Build a list of dhcp host entries
entries := map[string][][]string{}
- for _, cName := range containers {
- // Load the container
- c, err := containerLoadByName(s, cName)
- if err != nil {
- continue
- }
-
+ for _, c := range containers {
// Go through all its devices (including profiles
for k, d := range c.ExpandedDevices() {
// Skip uninteresting entries
@@ -804,7 +798,7 @@ func networkUpdateStatic(s *state.State, networkName string) error {
entries[d["parent"]] = [][]string{}
}
- entries[d["parent"]] = append(entries[d["parent"]], []string{d["hwaddr"], cName, d["ipv4.address"], d["ipv6.address"]})
+ entries[d["parent"]] = append(entries[d["parent"]], []string{d["hwaddr"], c.Name(), d["ipv4.address"], d["ipv6.address"]})
}
}
From b287a8ad09103d5b6eebef9189987ffa9e4daee6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 7 Aug 2018 16:54:30 -0400
Subject: [PATCH 4/6] lxd: Port over to new containerLoadAll function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/container_lxc.go | 11 ++++-------
lxd/networks.go | 34 +++++++++-------------------------
lxd/storage_volumes_utils.go | 31 ++++++++-----------------------
3 files changed, 21 insertions(+), 55 deletions(-)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 1ae39c1034..a58811ddfd 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -780,7 +780,7 @@ func findIdmap(state *state.State, cName string, isolatedStr string, configBase
idmapLock.Lock()
defer idmapLock.Unlock()
- cs, err := state.Cluster.ContainersList(db.CTypeRegular)
+ cts, err := containerLoadAll(state)
if err != nil {
return nil, 0, err
}
@@ -788,17 +788,14 @@ func findIdmap(state *state.State, cName string, isolatedStr string, configBase
offset := state.OS.IdmapSet.Idmap[0].Hostid + 65536
mapentries := idmap.ByHostid{}
- for _, name := range cs {
+ for _, container := range cts {
+ name := container.Name()
+
/* Don't change our map Just Because. */
if name == cName {
continue
}
- container, err := containerLoadByName(state, name)
- if err != nil {
- return nil, 0, err
- }
-
if container.IsPrivileged() {
continue
}
diff --git a/lxd/networks.go b/lxd/networks.go
index 66b21a4c56..3c1ed5bd3b 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -421,19 +421,14 @@ func doNetworkGet(d *Daemon, name string) (api.Network, error) {
// Look for containers using the interface
if n.Type != "loopback" {
- cts, err := d.cluster.ContainersList(db.CTypeRegular)
+ cts, err := containerLoadAll(d.State())
if err != nil {
return api.Network{}, err
}
- for _, ct := range cts {
- c, err := containerLoadByName(d.State(), ct)
- if err != nil {
- return api.Network{}, err
- }
-
+ for _, c := range cts {
if networkIsInUse(c, n.Name) {
- n.UsedBy = append(n.UsedBy, fmt.Sprintf("/%s/containers/%s", version.APIVersion, ct))
+ n.UsedBy = append(n.UsedBy, fmt.Sprintf("/%s/containers/%s", version.APIVersion, c.Name()))
}
}
}
@@ -685,19 +680,13 @@ func networkLeasesGet(d *Daemon, r *http.Request) Response {
leases := []api.NetworkLease{}
// Get all the containers
- containers, err := d.cluster.ContainersList(db.CTypeRegular)
+ containers, err := containerLoadAll(d.State())
if err != nil {
return SmartError(err)
}
// Get static leases
- for _, cName := range containers {
- // Load the container
- c, err := containerLoadByName(d.State(), cName)
- if err != nil {
- continue
- }
-
+ for _, c := range containers {
// Go through all its devices (including profiles
for k, d := range c.ExpandedDevices() {
// Skip uninteresting entries
@@ -714,7 +703,7 @@ func networkLeasesGet(d *Daemon, r *http.Request) Response {
// Add the lease
if d["ipv4.address"] != "" {
leases = append(leases, api.NetworkLease{
- Hostname: cName,
+ Hostname: c.Name(),
Address: d["ipv4.address"],
Hwaddr: d["hwaddr"],
Type: "static",
@@ -723,7 +712,7 @@ func networkLeasesGet(d *Daemon, r *http.Request) Response {
if d["ipv6.address"] != "" {
leases = append(leases, api.NetworkLease{
- Hostname: cName,
+ Hostname: c.Name(),
Address: d["ipv6.address"],
Hwaddr: d["hwaddr"],
Type: "static",
@@ -870,17 +859,12 @@ func (n *network) IsRunning() bool {
func (n *network) IsUsed() bool {
// Look for containers using the interface
- cts, err := n.state.Cluster.ContainersList(db.CTypeRegular)
+ cts, err := containerLoadAll(n.state)
if err != nil {
return true
}
- for _, ct := range cts {
- c, err := containerLoadByName(n.state, ct)
- if err != nil {
- return true
- }
-
+ for _, c := range cts {
if networkIsInUse(c, n.name) {
return true
}
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index f552976693..6c1916dfaa 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -174,19 +174,14 @@ func storagePoolVolumeUpdate(state *state.State, poolName string, volumeName str
func storagePoolVolumeUsedByContainersGet(s *state.State, volumeName string,
volumeTypeName string) ([]string, error) {
- cts, err := s.Cluster.ContainersList(db.CTypeRegular)
+ cts, err := containerLoadAll(s)
if err != nil {
return []string{}, err
}
ctsUsingVolume := []string{}
volumeNameWithType := fmt.Sprintf("%s/%s", volumeTypeName, volumeName)
- for _, ct := range cts {
- c, err := containerLoadByName(s, ct)
- if err != nil {
- continue
- }
-
+ for _, c := range cts {
for _, dev := range c.LocalDevices() {
if dev["type"] != "disk" {
continue
@@ -196,7 +191,7 @@ func storagePoolVolumeUsedByContainersGet(s *state.State, volumeName string,
// "container////bla" but only against "container/bla".
cleanSource := filepath.Clean(dev["source"])
if cleanSource == volumeName || cleanSource == volumeNameWithType {
- ctsUsingVolume = append(ctsUsingVolume, ct)
+ ctsUsingVolume = append(ctsUsingVolume, c.Name())
}
}
}
@@ -209,17 +204,12 @@ func storagePoolVolumeUpdateUsers(d *Daemon, oldPoolName string,
s := d.State()
// update all containers
- cts, err := s.Cluster.ContainersList(db.CTypeRegular)
+ cts, err := containerLoadAll(s)
if err != nil {
return err
}
- for _, ct := range cts {
- c, err := containerLoadByName(s, ct)
- if err != nil {
- continue
- }
-
+ for _, c := range cts {
devices := c.LocalDevices()
for k := range devices {
if devices[k]["type"] != "disk" {
@@ -344,19 +334,14 @@ func storagePoolVolumeUpdateUsers(d *Daemon, oldPoolName string,
func storagePoolVolumeUsedByRunningContainersWithProfilesGet(s *state.State,
poolName string, volumeName string, volumeTypeName string,
runningOnly bool) ([]string, error) {
- cts, err := s.Cluster.ContainersList(db.CTypeRegular)
+ cts, err := containerLoadAll(s)
if err != nil {
return []string{}, err
}
ctsUsingVolume := []string{}
volumeNameWithType := fmt.Sprintf("%s/%s", volumeTypeName, volumeName)
- for _, ct := range cts {
- c, err := containerLoadByName(s, ct)
- if err != nil {
- continue
- }
-
+ for _, c := range cts {
if runningOnly && !c.IsRunning() {
continue
}
@@ -374,7 +359,7 @@ func storagePoolVolumeUsedByRunningContainersWithProfilesGet(s *state.State,
// "container////bla" but only against "container/bla".
cleanSource := filepath.Clean(dev["source"])
if cleanSource == volumeName || cleanSource == volumeNameWithType {
- ctsUsingVolume = append(ctsUsingVolume, ct)
+ ctsUsingVolume = append(ctsUsingVolume, c.Name())
}
}
}
From 89498fb5198f5343f58c8a2ffb1e5c0e98df7103 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 7 Aug 2018 17:43:13 -0400
Subject: [PATCH 5/6] lxd: Only get the profiles once
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/container.go | 48 ++++++++++++++++++++++++-----------
lxd/container_lxc.go | 57 ++++++++++++++++++++++++++++--------------
lxd/containers.go | 2 +-
lxd/containers_post.go | 2 +-
4 files changed, 74 insertions(+), 35 deletions(-)
diff --git a/lxd/container.go b/lxd/container.go
index b245d1800d..52349b711c 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -1169,7 +1169,7 @@ func containerLoadByName(s *state.State, name string) (container, error) {
return nil, err
}
- return containerLXCLoad(s, args)
+ return containerLXCLoad(s, args, nil)
}
func containerLoadAll(s *state.State) ([]container, error) {
@@ -1188,18 +1188,7 @@ func containerLoadAll(s *state.State) ([]container, error) {
return nil, err
}
- // Load the container structs
- containers := []container{}
- for _, args := range cts {
- ct, err := containerLXCLoad(s, args)
- if err != nil {
- return nil, err
- }
-
- containers = append(containers, ct)
- }
-
- return containers, nil
+ return containerLoadAllInternal(cts, s)
}
func containerLoadNodeAll(s *state.State) ([]container, error) {
@@ -1218,10 +1207,41 @@ func containerLoadNodeAll(s *state.State) ([]container, error) {
return nil, err
}
+ return containerLoadAllInternal(cts, s)
+}
+
+func containerLoadAllInternal(cts []db.ContainerArgs, s *state.State) ([]container, error) {
+ // Figure out what profiles are in use
+ profiles := map[string]api.Profile{}
+ for _, cArgs := range cts {
+ for _, profile := range cArgs.Profiles {
+ _, ok := profiles[profile]
+ if !ok {
+ profiles[profile] = api.Profile{}
+ }
+ }
+ }
+
+ // Get the profile data
+ for name := range profiles {
+ _, profile, err := s.Cluster.ProfileGet(name)
+ if err != nil {
+ return nil, err
+ }
+
+ profiles[name] = *profile
+ }
+
// Load the container structs
containers := []container{}
for _, args := range cts {
- ct, err := containerLXCLoad(s, args)
+ // Figure out the container's profiles
+ cProfiles := []api.Profile{}
+ for _, name := range args.Profiles {
+ cProfiles = append(cProfiles, profiles[name])
+ }
+
+ ct, err := containerLXCLoad(s, args, cProfiles)
if err != nil {
return nil, err
}
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index a58811ddfd..cde7b09e38 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -467,15 +467,20 @@ func containerLXCCreate(s *state.State, args db.ContainerArgs) (container, error
return c, nil
}
-func containerLXCLoad(s *state.State, args db.ContainerArgs) (container, error) {
+func containerLXCLoad(s *state.State, args db.ContainerArgs, profiles []api.Profile) (container, error) {
// Create the container struct
c := containerLXCInstantiate(s, args)
// Setup finalizer
runtime.SetFinalizer(c, containerLXCUnload)
- // Load the config.
- err := c.init()
+ // Expand config and devices
+ err := c.expandConfig(profiles)
+ if err != nil {
+ return nil, err
+ }
+
+ err = c.expandDevices(profiles)
if err != nil {
return nil, err
}
@@ -868,12 +873,12 @@ func findIdmap(state *state.State, cName string, isolatedStr string, configBase
func (c *containerLXC) init() error {
// Compute the expanded config and device list
- err := c.expandConfig()
+ err := c.expandConfig(nil)
if err != nil {
return err
}
- err = c.expandDevices()
+ err = c.expandDevices(nil)
if err != nil {
return err
}
@@ -1717,17 +1722,23 @@ func (c *containerLXC) initStorage() error {
}
// Config handling
-func (c *containerLXC) expandConfig() error {
+func (c *containerLXC) expandConfig(profiles []api.Profile) error {
// Fetch profile configs
profileConfigs := make([]map[string]string, len(c.profiles))
// Apply all the profiles
- for i, name := range c.profiles {
- profileConfig, err := c.state.Cluster.ProfileConfig(name)
- if err != nil {
- return err
+ if profiles != nil {
+ for i, profile := range profiles {
+ profileConfigs[i] = profile.Config
+ }
+ } else {
+ for i, name := range c.profiles {
+ profileConfig, err := c.state.Cluster.ProfileConfig(name)
+ if err != nil {
+ return err
+ }
+ profileConfigs[i] = profileConfig
}
- profileConfigs[i] = profileConfig
}
c.expandConfigFromProfiles(profileConfigs)
@@ -1754,15 +1765,23 @@ func (c *containerLXC) expandConfigFromProfiles(profileConfigs []map[string]stri
c.expandedConfig = config
}
-func (c *containerLXC) expandDevices() error {
+func (c *containerLXC) expandDevices(profiles []api.Profile) error {
// Fetch profile devices
profileDevices := make([]types.Devices, len(c.profiles))
- for _, p := range c.profiles {
- devices, err := c.state.Cluster.Devices(p, true)
- if err != nil {
- return err
+
+ // Apply all the profiles
+ if profiles != nil {
+ for i, profile := range profiles {
+ profileDevices[i] = profile.Devices
+ }
+ } else {
+ for _, p := range c.profiles {
+ devices, err := c.state.Cluster.Devices(p, true)
+ if err != nil {
+ return err
+ }
+ profileDevices = append(profileDevices, devices)
}
- profileDevices = append(profileDevices, devices)
}
c.expandDevicesFromProfiles(profileDevices)
@@ -3815,12 +3834,12 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
c.profiles = args.Profiles
// Expand the config and refresh the LXC config
- err = c.expandConfig()
+ err = c.expandConfig(nil)
if err != nil {
return err
}
- err = c.expandDevices()
+ err = c.expandDevices(nil)
if err != nil {
return err
}
diff --git a/lxd/containers.go b/lxd/containers.go
index 47612014bf..b2e2b4ae0b 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -211,7 +211,7 @@ func containersShutdown(s *state.State) error {
c, err := containerLXCLoad(s, db.ContainerArgs{
Name: file.Name(),
Config: make(map[string]string),
- })
+ }, nil)
if err != nil {
return err
}
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index 26db451744..202a4eb4ea 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -321,7 +321,7 @@ func createFromMigration(d *Daemon, req *api.ContainersPost) Response {
}
} else {
// Retrieve the future storage pool
- cM, err := containerLXCLoad(d.State(), args)
+ cM, err := containerLXCLoad(d.State(), args, nil)
if err != nil {
return InternalError(err)
}
From 15d380b1ec963399bc31599bfbee33064b4f3765 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 7 Aug 2018 18:25:32 -0400
Subject: [PATCH 6/6] lxd/containers: Speed up recursive list
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/containers_get.go | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/lxd/containers_get.go b/lxd/containers_get.go
index 3a4fe94e4d..6afd27f34b 100644
--- a/lxd/containers_get.go
+++ b/lxd/containers_get.go
@@ -40,6 +40,12 @@ func containersGet(d *Daemon, r *http.Request) Response {
}
func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
+ recursion := util.IsRecursionRequest(r)
+ resultString := []string{}
+ resultList := []*api.Container{}
+ resultMu := sync.Mutex{}
+
+ // Get the list and location of all containers
var result map[string][]string // Containers by node address
var nodes map[string]string // Node names by container
err := d.cluster.Transaction(func(tx *db.ClusterTx) error {
@@ -61,10 +67,18 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
return []string{}, err
}
- recursion := util.IsRecursionRequest(r)
- resultString := []string{}
- resultList := []*api.Container{}
- resultMu := sync.Mutex{}
+ // Get the local containers
+ nodeCts := map[string]container{}
+ if recursion {
+ cts, err := containerLoadNodeAll(d.State())
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ct := range cts {
+ nodeCts[ct.Name()] = ct
+ }
+ }
resultAppend := func(name string, c api.Container, err error) {
if err != nil {
@@ -130,11 +144,11 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
continue
}
- c, err := doContainerGet(d.State(), container)
+ c, _, err := nodeCts[container].Render()
if err != nil {
resultAppend(container, api.Container{}, err)
} else {
- resultAppend(container, *c, err)
+ resultAppend(container, *c.(*api.Container), err)
}
}
}
More information about the lxc-devel
mailing list