[lxc-devel] [lxd/master] Improve shutdown logic for cluster nodes

monstermunchkin on Github lxc-bot at linuxcontainers.org
Wed Aug 1 14:31:20 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 314 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180801/3c3f2a12/attachment.bin>
-------------- next part --------------
From c205f2704d2342274a9fc0d4ff78c47dfe834b5d Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Mon, 30 Jul 2018 18:42:51 +0200
Subject: [PATCH 1/2] lxd: Improve shutdown logic for cluster nodes

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 lxd/containers.go | 38 ++++++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/lxd/containers.go b/lxd/containers.go
index 726d0ee0f9..aa0da82a8d 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"io/ioutil"
 	"sort"
 	"strconv"
 	"sync"
@@ -196,16 +197,39 @@ func (slice containerStopList) Swap(i, j int) {
 func containersShutdown(s *state.State) error {
 	var wg sync.WaitGroup
 
+	dbAvailable := true
+
 	// Get all the containers
 	results, err := s.Cluster.ContainersList(db.CTypeRegular)
 	if err != nil {
-		return err
+		// Mark database as offline
+		dbAvailable = false
+
+		// List all containers on disk
+		files, err := ioutil.ReadDir(shared.VarPath("containers"))
+		if err != nil {
+			return err
+		}
+
+		for _, file := range files {
+			results = append(results, file.Name())
+		}
 	}
 
 	containers := []container{}
 
 	for _, name := range results {
-		c, err := containerLoadByName(s, name)
+		var c container
+		var err error
+
+		if dbAvailable {
+			c, err = containerLoadByName(s, name)
+		} else {
+			c, err = containerLXCLoad(s, db.ContainerArgs{
+				Name:   name,
+				Config: make(map[string]string),
+			})
+		}
 		if err != nil {
 			return err
 		}
@@ -215,10 +239,12 @@ func containersShutdown(s *state.State) error {
 
 	sort.Sort(containerStopList(containers))
 
-	// Reset all container states
-	err = s.Cluster.ContainersResetState()
-	if err != nil {
-		return err
+	if dbAvailable {
+		// Reset all container states
+		err = s.Cluster.ContainersResetState()
+		if err != nil {
+			return err
+		}
 	}
 
 	var lastPriority int = 0

From d259e0db569caf08a1e7102c9108773e344a2ae6 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 1 Aug 2018 16:29:53 +0200
Subject: [PATCH 2/2] test: Add test for cluster shutdown logic

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 test/suites/clustering.sh | 65 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/test/suites/clustering.sh b/test/suites/clustering.sh
index 28bd389134..f30bf0ce4b 100644
--- a/test/suites/clustering.sh
+++ b/test/suites/clustering.sh
@@ -903,3 +903,68 @@ test_clustering_join_api() {
   kill_lxd "${LXD_TWO_DIR}"
   kill_lxd "${LXD_ONE_DIR}"
 }
+
+test_clustering_shutdown_nodes() {
+  setup_clustering_bridge
+  prefix="lxd$$"
+  bridge="${prefix}"
+
+  setup_clustering_netns 1
+  LXD_ONE_DIR=$(mktemp -d -p "${TEST_DIR}" XXX)
+  chmod +x "${LXD_ONE_DIR}"
+  ns1="${prefix}1"
+  spawn_lxd_and_bootstrap_cluster "${ns1}" "${bridge}" "${LXD_ONE_DIR}"
+
+  # Add a newline at the end of each line. YAML as weird rules..
+  cert=$(sed ':a;N;$!ba;s/\n/\n\n/g' "${LXD_ONE_DIR}/server.crt")
+
+  # Spawn a second node
+  setup_clustering_netns 2
+  LXD_TWO_DIR=$(mktemp -d -p "${TEST_DIR}" XXX)
+  chmod +x "${LXD_TWO_DIR}"
+  ns2="${prefix}2"
+  spawn_lxd_and_join_cluster "${ns2}" "${bridge}" "${cert}" 2 1 "${LXD_TWO_DIR}"
+
+  # Spawn a third node
+  setup_clustering_netns 3
+  LXD_THREE_DIR=$(mktemp -d -p "${TEST_DIR}" XXX)
+  chmod +x "${LXD_THREE_DIR}"
+  ns3="${prefix}3"
+  spawn_lxd_and_join_cluster "${ns3}" "${bridge}" "${cert}" 3 1 "${LXD_THREE_DIR}"
+
+  # Init a container on node2, using a client connected to node1
+  LXD_DIR="${LXD_ONE_DIR}" ensure_import_testimage
+  LXD_DIR="${LXD_ONE_DIR}" lxc launch --target node1 testimage foo
+
+  # Get container PID
+  LXD_DIR="${LXD_ONE_DIR}" lxc info foo | grep Pid | cut -d' ' -f2 > foo.pid
+
+  # Get server PIDs
+  LXD_DIR="${LXD_ONE_DIR}" lxc info | awk '/server_pid/{print $2}' > one.pid
+  LXD_DIR="${LXD_TWO_DIR}" lxc info | awk '/server_pid/{print $2}' > two.pid
+  LXD_DIR="${LXD_THREE_DIR}" lxc info | awk '/server_pid/{print $2}' > three.pid
+
+  LXD_DIR="${LXD_TWO_DIR}" lxd shutdown
+  wait "$(cat two.pid)"
+  LXD_DIR="${LXD_THREE_DIR}" lxd shutdown
+  wait "$(cat three.pid)"
+  # Make sure the database is not available to the first node
+  sleep 5
+  LXD_DIR="${LXD_ONE_DIR}" lxd shutdown
+
+  # Wait for LXD to terminate, otherwise the db will not be empty, and the
+  # cleanup code will fail
+  wait "$(cat one.pid)"
+
+  # Container foo shouldn't be running anymore
+  ! ps -q "$(cat foo.pid)"
+
+  rm -f one.pid two.pid three.pid foo.pid
+
+  teardown_clustering_netns
+  teardown_clustering_bridge
+
+  kill_lxd "${LXD_TWO_DIR}"
+  kill_lxd "${LXD_ONE_DIR}"
+  kill_lxd "${LXD_THREE_DIR}"
+}


More information about the lxc-devel mailing list