[lxc-devel] [lxd/master] Bits needed by lxd-bridge init scripts
stgraber on Github
lxc-bot at linuxcontainers.org
Wed Mar 23 01:49:57 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 780 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160323/2778016f/attachment.bin>
-------------- next part --------------
From f1b3135b3985912e14d077a95883a4dd5cc0de24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 19:47:54 -0400
Subject: [PATCH 1/7] Rename IsMock to MockMode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
And don't bother setting it to false, that's the default.
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/daemon.go | 17 ++++++++---------
lxd/db_test.go | 8 ++++----
lxd/db_update.go | 4 ++--
lxd/main.go | 1 -
lxd/main_test.go | 2 +-
lxd/storage.go | 4 ++--
6 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 5a69b8e..e7933f7 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -90,7 +90,7 @@ type Daemon struct {
configValues map[string]string
- IsMock bool
+ MockMode bool
imagesDownloading map[string]chan bool
imagesDownloadingLock sync.RWMutex
@@ -528,7 +528,6 @@ func (d *Daemon) UpdateHTTPsPort(oldAddress string, newAddress string) error {
func startDaemon(group string) (*Daemon, error) {
d := &Daemon{
group: group,
- IsMock: false,
imagesDownloading: map[string]chan bool{},
imagesDownloadingLock: sync.RWMutex{},
}
@@ -575,11 +574,11 @@ func (d *Daemon) Init() error {
}
}
- if !d.IsMock {
- shared.Log.Info("LXD is starting",
+ if d.MockMode {
+ shared.Log.Info("Mock LXD is starting",
log.Ctx{"path": shared.VarPath("")})
} else {
- shared.Log.Info("Mock LXD is starting",
+ shared.Log.Info("LXD is starting",
log.Ctx{"path": shared.VarPath("")})
}
@@ -744,7 +743,7 @@ func (d *Daemon) Init() error {
}
/* Setup the storage driver */
- if !d.IsMock {
+ if !d.MockMode {
err = d.SetupStorageDriver()
if err != nil {
return fmt.Errorf("Failed to setup storage: %s", err)
@@ -824,7 +823,7 @@ func (d *Daemon) Init() error {
return err
}
- if !d.IsMock {
+ if !d.MockMode {
/* Start the scheduler */
go deviceEventListener(d)
@@ -992,7 +991,7 @@ func (d *Daemon) Init() error {
})
// Restore containers
- if !d.IsMock {
+ if !d.MockMode {
/* Restart containers */
go containersRestart(d)
@@ -1072,7 +1071,7 @@ func (d *Daemon) Stop() error {
shared.Log.Debug("Stopping /dev/lxd handler")
d.devlxd.Close()
- if d.IsMock || forceStop {
+ if d.MockMode || forceStop {
return nil
}
diff --git a/lxd/db_test.go b/lxd/db_test.go
index 28055bd..6441717 100644
--- a/lxd/db_test.go
+++ b/lxd/db_test.go
@@ -37,7 +37,7 @@ func createTestDb(t *testing.T) (db *sql.DB) {
}
var err error
- d := &Daemon{IsMock: true}
+ d := &Daemon{MockMode: true}
err = initializeDbObject(d, ":memory:")
db = d.db
@@ -195,7 +195,7 @@ func Test_initializing_db_is_indempotent(t *testing.T) {
var err error
// This calls "createDb" once already.
- d := &Daemon{IsMock: true}
+ d := &Daemon{MockMode: true}
err = initializeDbObject(d, ":memory:")
db = d.db
@@ -230,7 +230,7 @@ func Test_running_dbUpdateFromV6_adds_on_delete_cascade(t *testing.T) {
var err error
var count int
- d := &Daemon{IsMock: true}
+ d := &Daemon{MockMode: true}
err = initializeDbObject(d, ":memory:")
defer d.db.Close()
@@ -372,7 +372,7 @@ INSERT INTO containers_config (container_id, key, value) VALUES (1, 'thekey', 't
// The "foreign key" on containers_config now points to nothing.
// Let's run the schema upgrades.
- d := &Daemon{IsMock: true}
+ d := &Daemon{MockMode: true}
d.db = db
err = dbUpdate(d, 1)
diff --git a/lxd/db_update.go b/lxd/db_update.go
index 31c3612..7637a26 100644
--- a/lxd/db_update.go
+++ b/lxd/db_update.go
@@ -334,7 +334,7 @@ INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));`
}
func dbUpdateFromV11(d *Daemon) error {
- if d.IsMock {
+ if d.MockMode {
// No need to move snapshots no mock runs,
// dbUpdateFromV12 will then set the db version to 13
return nil
@@ -412,7 +412,7 @@ INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));`
}
func dbUpdateFromV10(d *Daemon) error {
- if d.IsMock {
+ if d.MockMode {
// No need to move lxc to containers in mock runs,
// dbUpdateFromV12 will then set the db version to 13
return nil
diff --git a/lxd/main.go b/lxd/main.go
index b3c33e0..fcbc724 100644
--- a/lxd/main.go
+++ b/lxd/main.go
@@ -422,7 +422,6 @@ func cleanShutdown() error {
func activateIfNeeded() error {
// Don't start a full daemon, we just need DB access
d := &Daemon{
- IsMock: false,
imagesDownloading: map[string]chan bool{},
imagesDownloadingLock: sync.RWMutex{},
}
diff --git a/lxd/main_test.go b/lxd/main_test.go
index 4c619c5..7a61429 100644
--- a/lxd/main_test.go
+++ b/lxd/main_test.go
@@ -12,7 +12,7 @@ import (
func mockStartDaemon() (*Daemon, error) {
d := &Daemon{
- IsMock: true,
+ MockMode: true,
imagesDownloading: map[string]chan bool{},
imagesDownloadingLock: sync.RWMutex{},
}
diff --git a/lxd/storage.go b/lxd/storage.go
index 5b3863a..915fa05 100644
--- a/lxd/storage.go
+++ b/lxd/storage.go
@@ -196,7 +196,7 @@ func newStorage(d *Daemon, sType storageType) (storage, error) {
}
func newStorageWithConfig(d *Daemon, sType storageType, config map[string]interface{}) (storage, error) {
- if d.IsMock {
+ if d.MockMode {
return d.Storage, nil
}
@@ -236,7 +236,7 @@ func storageForFilename(d *Daemon, filename string) (storage, error) {
config := make(map[string]interface{})
storageType := storageTypeDir
- if d.IsMock {
+ if d.MockMode {
return newStorageWithConfig(d, storageTypeMock, config)
}
From 9a39490dc1a02c559eab5060ee756cea5283427c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 19:57:22 -0400
Subject: [PATCH 2/7] Cleanup daemon initialization
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/daemon.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lxd/daemon.go b/lxd/daemon.go
index e7933f7..8099d75 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -528,8 +528,6 @@ func (d *Daemon) UpdateHTTPsPort(oldAddress string, newAddress string) error {
func startDaemon(group string) (*Daemon, error) {
d := &Daemon{
group: group,
- imagesDownloading: map[string]chan bool{},
- imagesDownloadingLock: sync.RWMutex{},
}
if err := d.Init(); err != nil {
@@ -551,6 +549,9 @@ func haveMacAdmin() bool {
}
func (d *Daemon) Init() error {
+ /* Initialize some variables */
+ d.imagesDownloading = map[string]chan bool{}
+
d.shutdownChan = make(chan bool)
/* Set the executable path */
From c30ad17ad30003fc3b39607ae79969fae4bb31ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 20:00:44 -0400
Subject: [PATCH 3/7] Remove the startDaemon function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Most code paths don't use it anyway
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/daemon.go | 13 -------------
lxd/devlxd_test.go | 3 ++-
lxd/main.go | 4 ++--
3 files changed, 4 insertions(+), 16 deletions(-)
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 8099d75..de7f016 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -524,19 +524,6 @@ func (d *Daemon) UpdateHTTPsPort(oldAddress string, newAddress string) error {
return nil
}
-// StartDaemon starts the shared daemon with the provided configuration.
-func startDaemon(group string) (*Daemon, error) {
- d := &Daemon{
- group: group,
- }
-
- if err := d.Init(); err != nil {
- return nil, err
- }
-
- return d, nil
-}
-
func haveMacAdmin() bool {
c, err := capability.NewPid(0)
if err != nil {
diff --git a/lxd/devlxd_test.go b/lxd/devlxd_test.go
index 92f3b34..62d200b 100644
--- a/lxd/devlxd_test.go
+++ b/lxd/devlxd_test.go
@@ -120,7 +120,8 @@ func TestHttpRequest(t *testing.T) {
}
defer os.RemoveAll(testDir)
- d, err := startDaemon("")
+ d := &Daemon{}
+ err := d.Init()
if err != nil {
t.Fatal(err)
}
diff --git a/lxd/main.go b/lxd/main.go
index fcbc724..8e7939c 100644
--- a/lxd/main.go
+++ b/lxd/main.go
@@ -325,8 +325,8 @@ func daemon() error {
}()
}
- d, err := startDaemon(*argGroup)
-
+ d := &Daemon{group: *argGroup}
+ err := d.Init()
if err != nil {
if d != nil && d.db != nil {
d.db.Close()
From f91b1571cc5aba55562a52a9c8c27a331f1fa9b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 20:24:47 -0400
Subject: [PATCH 4/7] Add a setup mode allowing to delay part of startup
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In this mode, containers are restarted and images aren't processed until
after we exit setup mode.
This is needed to configure the default profile through the API before
containers start using it.
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/api_internal.go | 18 +++++++
lxd/daemon.go | 141 ++++++++++++++++++++++++++++------------------------
lxd/main.go | 32 +++++++++++-
3 files changed, 126 insertions(+), 65 deletions(-)
diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 46d372e..f0b9f35 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -1,6 +1,7 @@
package main
import (
+ "fmt"
"net/http"
"strconv"
@@ -8,11 +9,27 @@ import (
)
var apiInternal = []Command{
+ internalReadyCmd,
internalShutdownCmd,
internalContainerOnStartCmd,
internalContainerOnStopCmd,
}
+func internalReady(d *Daemon, r *http.Request) Response {
+ if !d.SetupMode {
+ return InternalError(fmt.Errorf("The server isn't currently in setup mode"))
+ }
+
+ err := d.Ready()
+ if err != nil {
+ return InternalError(err)
+ }
+
+ d.SetupMode = false
+
+ return EmptySyncResponse
+}
+
func internalShutdown(d *Daemon, r *http.Request) Response {
d.shutdownChan <- true
@@ -63,5 +80,6 @@ func internalContainerOnStop(d *Daemon, r *http.Request) Response {
}
var internalShutdownCmd = Command{name: "shutdown", put: internalShutdown}
+var internalReadyCmd = Command{name: "ready", put: internalReady}
var internalContainerOnStartCmd = Command{name: "containers/{id}/onstart", get: internalContainerOnStart}
var internalContainerOnStopCmd = Command{name: "containers/{id}/onstop", get: internalContainerOnStop}
diff --git a/lxd/daemon.go b/lxd/daemon.go
index de7f016..abd9c14 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -90,7 +90,8 @@ type Daemon struct {
configValues map[string]string
- MockMode bool
+ MockMode bool
+ SetupMode bool
imagesDownloading map[string]chan bool
imagesDownloadingLock sync.RWMutex
@@ -562,11 +563,15 @@ func (d *Daemon) Init() error {
}
}
+ /* Print welcome message */
if d.MockMode {
- shared.Log.Info("Mock LXD is starting",
+ shared.Log.Info("LXD is starting in mock mode",
+ log.Ctx{"path": shared.VarPath("")})
+ } else if d.SetupMode {
+ shared.Log.Info("LXD is starting in setup mode",
log.Ctx{"path": shared.VarPath("")})
} else {
- shared.Log.Info("LXD is starting",
+ shared.Log.Info("LXD is starting in normal mode",
log.Ctx{"path": shared.VarPath("")})
}
@@ -738,25 +743,6 @@ func (d *Daemon) Init() error {
}
}
- /* Prune images */
- d.pruneChan = make(chan bool)
- go func() {
- pruneExpiredImages(d)
- for {
- timer := time.NewTimer(24 * time.Hour)
- timeChan := timer.C
- select {
- case <-timeChan:
- /* run once per day */
- pruneExpiredImages(d)
- case <-d.pruneChan:
- /* run when image.remote_cache_expiry is changed */
- pruneExpiredImages(d)
- timer.Stop()
- }
- }
- }()
-
/* Load all config values from the database */
_, err = d.ConfigValuesGet()
if err != nil {
@@ -766,41 +752,6 @@ func (d *Daemon) Init() error {
/* set the initial proxy function based on config values in the DB */
d.updateProxy()
- /* Auto-update images */
- d.resetAutoUpdateChan = make(chan bool)
- go func() {
- autoUpdateImages(d)
-
- for {
- interval, _ := d.ConfigValueGet("images.auto_update_interval")
- if interval == "" {
- interval = "6"
- }
-
- intervalInt, err := strconv.Atoi(interval)
- if err != nil {
- intervalInt = 0
- }
-
- if intervalInt > 0 {
- timer := time.NewTimer(time.Duration(intervalInt) * time.Hour)
- timeChan := timer.C
-
- select {
- case <-timeChan:
- autoUpdateImages(d)
- case <-d.resetAutoUpdateChan:
- timer.Stop()
- }
- } else {
- select {
- case <-d.resetAutoUpdateChan:
- continue
- }
- }
- }
- }()
-
/* Setup /dev/lxd */
d.devlxd, err = createAndBindDevLxd()
if err != nil {
@@ -978,18 +929,80 @@ func (d *Daemon) Init() error {
return nil
})
- // Restore containers
- if !d.MockMode {
- /* Restart containers */
- go containersRestart(d)
-
- /* Re-balance in case things changed while LXD was down */
- deviceTaskBalance(d)
+ if !d.MockMode && !d.SetupMode {
+ err := d.Ready()
+ if err != nil {
+ return err
+ }
}
return nil
}
+func (d *Daemon) Ready() error {
+ /* Prune images */
+ d.pruneChan = make(chan bool)
+ go func() {
+ pruneExpiredImages(d)
+ for {
+ timer := time.NewTimer(24 * time.Hour)
+ timeChan := timer.C
+ select {
+ case <-timeChan:
+ /* run once per day */
+ pruneExpiredImages(d)
+ case <-d.pruneChan:
+ /* run when image.remote_cache_expiry is changed */
+ pruneExpiredImages(d)
+ timer.Stop()
+ }
+ }
+ }()
+
+ /* Auto-update images */
+ d.resetAutoUpdateChan = make(chan bool)
+ go func() {
+ autoUpdateImages(d)
+
+ for {
+ interval, _ := d.ConfigValueGet("images.auto_update_interval")
+ if interval == "" {
+ interval = "6"
+ }
+
+ intervalInt, err := strconv.Atoi(interval)
+ if err != nil {
+ intervalInt = 0
+ }
+
+ if intervalInt > 0 {
+ timer := time.NewTimer(time.Duration(intervalInt) * time.Hour)
+ timeChan := timer.C
+
+ select {
+ case <-timeChan:
+ autoUpdateImages(d)
+ case <-d.resetAutoUpdateChan:
+ timer.Stop()
+ }
+ } else {
+ select {
+ case <-d.resetAutoUpdateChan:
+ continue
+ }
+ }
+ }
+ }()
+
+ /* Restore containers */
+ go containersRestart(d)
+
+ /* Re-balance in case things changed while LXD was down */
+ deviceTaskBalance(d)
+
+ return nil
+}
+
// CheckTrustState returns True if the client is trusted else false.
func (d *Daemon) CheckTrustState(cert x509.Certificate) bool {
for k, v := range d.clientCerts {
diff --git a/lxd/main.go b/lxd/main.go
index 8e7939c..a2145b8 100644
--- a/lxd/main.go
+++ b/lxd/main.go
@@ -76,6 +76,8 @@ func run() error {
fmt.Printf(" [--storage-create-device=DEVICE] [--storage-create-loop=SIZE] [--storage-pool=POOL]\n")
fmt.Printf(" [--trust-password=]\n")
fmt.Printf(" Setup storage and networking\n")
+ fmt.Printf(" ready\n")
+ fmt.Printf(" Tells LXD that any setup-mode configuration has been done and that it can start containers.\n")
fmt.Printf(" shutdown [--timeout=60]\n")
fmt.Printf(" Perform a clean shutdown of LXD and all running containers\n")
fmt.Printf(" waitready [--timeout=15]\n")
@@ -208,6 +210,8 @@ func run() error {
return callHook(os.Args[1:])
case "init":
return setupLXD()
+ case "ready":
+ return cmdReady()
case "shutdown":
return cleanShutdown()
case "waitready":
@@ -325,7 +329,9 @@ func daemon() error {
}()
}
- d := &Daemon{group: *argGroup}
+ d := &Daemon{
+ group: *argGroup,
+ SetupMode: shared.PathExists(shared.VarPath(".setup_mode"))}
err := d.Init()
if err != nil {
if d != nil && d.db != nil {
@@ -380,6 +386,30 @@ func daemon() error {
return ret
}
+func cmdReady() error {
+ c, err := lxd.NewClient(&lxd.DefaultConfig, "local")
+ if err != nil {
+ return err
+ }
+
+ req, err := http.NewRequest("PUT", c.BaseURL+"/internal/ready", nil)
+ if err != nil {
+ return err
+ }
+
+ raw, err := c.Http.Do(req)
+ if err != nil {
+ return err
+ }
+
+ _, err = lxd.HoistResponse(raw, lxd.Sync)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
func cleanShutdown() error {
var timeout int
From 2dc8ccdf93f01fcb25b77c834ca4a9496be9b544 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 20:29:44 -0400
Subject: [PATCH 5/7] Cleanup function names in main.go
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/main.go | 41 ++++++++++++++++++++++-------------------
1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/lxd/main.go b/lxd/main.go
index a2145b8..d7ab929 100644
--- a/lxd/main.go
+++ b/lxd/main.go
@@ -196,26 +196,29 @@ func run() error {
// "forkputfile", "forkgetfile", "forkmount" and "forkumount" are handled specially in nsexec.go
// "forkgetnet" is partially handled in nsexec.go (setns)
switch os.Args[1] {
+ // Main commands
case "activateifneeded":
- return activateIfNeeded()
+ return cmdActivateIfNeeded()
case "daemon":
- return daemon()
- case "forkgetnet":
- return printnet()
- case "forkmigrate":
- return MigrateContainer(os.Args[1:])
- case "forkstart":
- return startContainer(os.Args[1:])
+ return cmdDaemon()
case "callhook":
- return callHook(os.Args[1:])
+ return cmdCallHook(os.Args[1:])
case "init":
- return setupLXD()
+ return cmdInit()
case "ready":
return cmdReady()
case "shutdown":
- return cleanShutdown()
+ return cmdShutdown()
case "waitready":
- return waitReady()
+ return cmdWaitReady()
+
+ // Internal commands
+ case "forkgetnet":
+ return printnet()
+ case "forkmigrate":
+ return MigrateContainer(os.Args[1:])
+ case "forkstart":
+ return startContainer(os.Args[1:])
}
}
@@ -225,10 +228,10 @@ func run() error {
return fmt.Errorf("Unknown arguments")
}
- return daemon()
+ return cmdDaemon()
}
-func callHook(args []string) error {
+func cmdCallHook(args []string) error {
if len(args) < 4 {
return fmt.Errorf("Invalid arguments")
}
@@ -297,7 +300,7 @@ func callHook(args []string) error {
return nil
}
-func daemon() error {
+func cmdDaemon() error {
if *argCPUProfile != "" {
f, err := os.Create(*argCPUProfile)
if err != nil {
@@ -410,7 +413,7 @@ func cmdReady() error {
return nil
}
-func cleanShutdown() error {
+func cmdShutdown() error {
var timeout int
if *argTimeout == -1 {
@@ -449,7 +452,7 @@ func cleanShutdown() error {
return nil
}
-func activateIfNeeded() error {
+func cmdActivateIfNeeded() error {
// Don't start a full daemon, we just need DB access
d := &Daemon{
imagesDownloading: map[string]chan bool{},
@@ -505,7 +508,7 @@ func activateIfNeeded() error {
return nil
}
-func waitReady() error {
+func cmdWaitReady() error {
var timeout int
if *argTimeout == -1 {
@@ -538,7 +541,7 @@ func waitReady() error {
return nil
}
-func setupLXD() error {
+func cmdInit() error {
var storageBackend string // dir or zfs
var storageMode string // existing, loop or device
var storageLoopSize int // Size in GB
From c8eb881fccf1bbe388dbb377115afc1133845f52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 21:21:59 -0400
Subject: [PATCH 6/7] Improve waitready
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Make it wait for the daemon to actually be ready.
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/api_internal.go | 8 +++++++-
lxd/daemon.go | 4 ++++
lxd/main.go | 20 +++++++++++++++++++-
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index f0b9f35..ad32446 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -30,6 +30,12 @@ func internalReady(d *Daemon, r *http.Request) Response {
return EmptySyncResponse
}
+func internalWaitReady(d *Daemon, r *http.Request) Response {
+ <-d.readyChan
+
+ return EmptySyncResponse
+}
+
func internalShutdown(d *Daemon, r *http.Request) Response {
d.shutdownChan <- true
@@ -80,6 +86,6 @@ func internalContainerOnStop(d *Daemon, r *http.Request) Response {
}
var internalShutdownCmd = Command{name: "shutdown", put: internalShutdown}
-var internalReadyCmd = Command{name: "ready", put: internalReady}
+var internalReadyCmd = Command{name: "ready", put: internalReady, get: internalWaitReady}
var internalContainerOnStartCmd = Command{name: "containers/{id}/onstart", get: internalContainerOnStart}
var internalContainerOnStopCmd = Command{name: "containers/{id}/onstop", get: internalContainerOnStop}
diff --git a/lxd/daemon.go b/lxd/daemon.go
index abd9c14..becbdb6 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -76,6 +76,7 @@ type Daemon struct {
lxcpath string
mux *mux.Router
tomb tomb.Tomb
+ readyChan chan bool
pruneChan chan bool
shutdownChan chan bool
resetAutoUpdateChan chan bool
@@ -540,6 +541,7 @@ func (d *Daemon) Init() error {
/* Initialize some variables */
d.imagesDownloading = map[string]chan bool{}
+ d.readyChan = make(chan bool)
d.shutdownChan = make(chan bool)
/* Set the executable path */
@@ -1000,6 +1002,8 @@ func (d *Daemon) Ready() error {
/* Re-balance in case things changed while LXD was down */
deviceTaskBalance(d)
+ close(d.readyChan)
+
return nil
}
diff --git a/lxd/main.go b/lxd/main.go
index d7ab929..0a4bbd4 100644
--- a/lxd/main.go
+++ b/lxd/main.go
@@ -520,7 +520,25 @@ func cmdWaitReady() error {
finger := make(chan error, 1)
go func() {
for {
- _, err := lxd.NewClient(&lxd.DefaultConfig, "local")
+ c, err := lxd.NewClient(&lxd.DefaultConfig, "local")
+ if err != nil {
+ time.Sleep(500 * time.Millisecond)
+ continue
+ }
+
+ req, err := http.NewRequest("GET", c.BaseURL+"/internal/ready", nil)
+ if err != nil {
+ time.Sleep(500 * time.Millisecond)
+ continue
+ }
+
+ raw, err := c.Http.Do(req)
+ if err != nil {
+ time.Sleep(500 * time.Millisecond)
+ continue
+ }
+
+ _, err = lxd.HoistResponse(raw, lxd.Sync)
if err != nil {
time.Sleep(500 * time.Millisecond)
continue
From 20f44913ae1d1c7d8a7c6b74c829c3aa47651957 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 22 Mar 2016 21:47:56 -0400
Subject: [PATCH 7/7] Implement device set/unset
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>
---
lxc/config.go | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lxc/profile.go | 12 ++++--
po/lxd.pot | 48 ++++++++++++-----------
3 files changed, 154 insertions(+), 25 deletions(-)
diff --git a/lxc/config.go b/lxc/config.go
index 1bece90..54e8452 100644
--- a/lxc/config.go
+++ b/lxc/config.go
@@ -59,6 +59,8 @@ func (c *configCmd) usage() string {
`Manage configuration.
lxc config device add <[remote:]container> <name> <type> [key=value]... Add a device to a container.
+lxc config device set <[remote:]container> <name> <key> <value> Set a device property.
+lxc config device unset <[remote:]container> <name> <key> Unset a device property.
lxc config device list [remote:]<container> List devices for container.
lxc config device show [remote:]<container> Show full device details for container.
lxc config device remove [remote:]<container> <name> Remove device from container.
@@ -411,6 +413,10 @@ func (c *configCmd) run(config *lxd.Config, args []string) error {
return c.deviceAdd(config, "container", args)
case "remove":
return c.deviceRm(config, "container", args)
+ case "set":
+ return c.deviceSet(config, "container", args)
+ case "unset":
+ return c.deviceUnset(config, "container", args)
case "show":
return c.deviceShow(config, "container", args)
default:
@@ -612,6 +618,119 @@ func (c *configCmd) deviceAdd(config *lxd.Config, which string, args []string) e
return err
}
+func (c *configCmd) deviceSet(config *lxd.Config, which string, args []string) error {
+ if len(args) < 6 {
+ return errArgs
+ }
+
+ remote, name := config.ParseRemoteAndContainer(args[2])
+
+ client, err := lxd.NewClient(config, remote)
+ if err != nil {
+ return err
+ }
+
+ devname := args[3]
+ key := args[4]
+ value := args[5]
+
+ if which == "profile" {
+ st, err := client.ProfileConfig(name)
+ if err != nil {
+ return err
+ }
+
+ dev, ok := st.Devices[devname]
+ if !ok {
+ return fmt.Errorf(i18n.G("The device doesn't exist"))
+ }
+
+ dev[key] = value
+ st.Devices[devname] = dev
+
+ err = client.PutProfile(name, *st)
+ if err != nil {
+ return err
+ }
+ } else {
+ st, err := client.ContainerInfo(name)
+ if err != nil {
+ return err
+ }
+
+ dev, ok := st.Devices[devname]
+ if !ok {
+ return fmt.Errorf(i18n.G("The device doesn't exist"))
+ }
+
+ dev[key] = value
+ st.Devices[devname] = dev
+
+ err = client.UpdateContainerConfig(name, st.Brief())
+ if err != nil {
+ return err
+ }
+ }
+
+ return err
+}
+
+func (c *configCmd) deviceUnset(config *lxd.Config, which string, args []string) error {
+ if len(args) < 5 {
+ return errArgs
+ }
+
+ remote, name := config.ParseRemoteAndContainer(args[2])
+
+ client, err := lxd.NewClient(config, remote)
+ if err != nil {
+ return err
+ }
+
+ devname := args[3]
+ key := args[4]
+
+ if which == "profile" {
+ st, err := client.ProfileConfig(name)
+ if err != nil {
+ return err
+ }
+
+ dev, ok := st.Devices[devname]
+ if !ok {
+ return fmt.Errorf(i18n.G("The device doesn't exist"))
+ }
+
+ delete(dev, key)
+ st.Devices[devname] = dev
+
+ err = client.PutProfile(name, *st)
+ if err != nil {
+ return err
+ }
+ } else {
+ st, err := client.ContainerInfo(name)
+ if err != nil {
+ return err
+ }
+
+ dev, ok := st.Devices[devname]
+ if !ok {
+ return fmt.Errorf(i18n.G("The device doesn't exist"))
+ }
+
+ delete(dev, key)
+ st.Devices[devname] = dev
+
+ err = client.UpdateContainerConfig(name, st.Brief())
+ if err != nil {
+ return err
+ }
+ }
+
+ return err
+}
+
func (c *configCmd) deviceRm(config *lxd.Config, which string, args []string) error {
if len(args) < 4 {
return errArgs
diff --git a/lxc/profile.go b/lxc/profile.go
index ebcf1aa..1b42ce2 100644
--- a/lxc/profile.go
+++ b/lxc/profile.go
@@ -69,9 +69,11 @@ lxc profile apply <container> <profiles>
lxc profile apply bar,default # Apply default second now
Devices:
-lxc profile device list <profile> List devices in the given profile.
-lxc profile device show <profile> Show full device details in the given profile.
-lxc profile device remove <profile> <name> Remove a device from a profile.
+lxc profile device list <profile> List devices in the given profile.
+lxc profile device show <profile> Show full device details in the given profile.
+lxc profile device remove <profile> <name> Remove a device from a profile.
+lxc profile device set <[remote:]container> <name> <key> <value> Set a device property.
+lxc profile device unset <[remote:]container> <name> <key> Unset a device property.
lxc profile device add <profile name> <device name> <device type> [key=value]...
Add a profile device, such as a disk or a nic, to the containers
using the specified profile.`)
@@ -276,6 +278,10 @@ func (c *profileCmd) doProfileDevice(config *lxd.Config, args []string) error {
return cfg.deviceList(config, "profile", args)
case "show":
return cfg.deviceShow(config, "profile", args)
+ case "set":
+ return cfg.deviceSet(config, "profile", args)
+ case "unset":
+ return cfg.deviceUnset(config, "profile", args)
default:
return errArgs
}
diff --git a/po/lxd.pot b/po/lxd.pot
index c2ec8cf..ca5c42a 100644
--- a/po/lxd.pot
+++ b/po/lxd.pot
@@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: lxd\n"
"Report-Msgid-Bugs-To: lxc-devel at lists.linuxcontainers.org\n"
- "POT-Creation-Date: 2016-03-16 15:52-0400\n"
+ "POT-Creation-Date: 2016-03-22 21:30-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
"Language-Team: LANGUAGE <LL at li.org>\n"
@@ -74,7 +74,7 @@ msgstr ""
msgid "'/' not allowed in snapshot name"
msgstr ""
-#: lxc/profile.go:223
+#: lxc/profile.go:225
msgid "(none)"
msgstr ""
@@ -121,7 +121,7 @@ msgstr ""
msgid "Available commands:"
msgstr ""
-#: lxc/config.go:269
+#: lxc/config.go:271
msgid "COMMON NAME"
msgstr ""
@@ -129,17 +129,17 @@ msgstr ""
msgid "CREATED AT"
msgstr ""
-#: lxc/config.go:113
+#: lxc/config.go:115
#, c-format
msgid "Can't read from stdin: %s"
msgstr ""
-#: lxc/config.go:126 lxc/config.go:159 lxc/config.go:181
+#: lxc/config.go:128 lxc/config.go:161 lxc/config.go:183
#, c-format
msgid "Can't unset key '%s', it's not currently set."
msgstr ""
-#: lxc/profile.go:334
+#: lxc/profile.go:336
msgid "Cannot provide container name to list"
msgstr ""
@@ -167,7 +167,7 @@ msgstr ""
msgid "Config key/value to apply to the new container"
msgstr ""
-#: lxc/config.go:493 lxc/config.go:558 lxc/image.go:669 lxc/profile.go:187
+#: lxc/config.go:495 lxc/config.go:560 lxc/image.go:669 lxc/profile.go:189
#, c-format
msgid "Config parsing error: %s"
msgstr ""
@@ -251,12 +251,12 @@ msgid "Delete containers or container snapshots.\n"
"Destroy containers or snapshots with any attached data (configuration, snapshots, ...)."
msgstr ""
-#: lxc/config.go:610
+#: lxc/config.go:612
#, c-format
msgid "Device %s added to %s"
msgstr ""
-#: lxc/config.go:640
+#: lxc/config.go:642
#, c-format
msgid "Device %s removed from %s"
msgstr ""
@@ -265,7 +265,7 @@ msgstr ""
msgid "EPHEMERAL"
msgstr ""
-#: lxc/config.go:271
+#: lxc/config.go:273
msgid "EXPIRY DATE"
msgstr ""
@@ -306,7 +306,7 @@ msgstr ""
msgid "Expires: never"
msgstr ""
-#: lxc/config.go:268 lxc/image.go:591 lxc/image.go:616
+#: lxc/config.go:270 lxc/image.go:591 lxc/image.go:616
msgid "FINGERPRINT"
msgstr ""
@@ -349,7 +349,7 @@ msgstr ""
msgid "IPV6"
msgstr ""
-#: lxc/config.go:270
+#: lxc/config.go:272
msgid "ISSUE DATE"
msgstr ""
@@ -502,9 +502,11 @@ msgid "Manage configuration profiles.\n"
" lxc profile apply bar,default # Apply default second now\n"
"\n"
"Devices:\n"
- "lxc profile device list <profile> List devices in the given profile.\n"
- "lxc profile device show <profile> Show full device details in the given profile.\n"
- "lxc profile device remove <profile> <name> Remove a device from a profile.\n"
+ "lxc profile device list <profile> List devices in the given profile.\n"
+ "lxc profile device show <profile> Show full device details in the given profile.\n"
+ "lxc profile device remove <profile> <name> Remove a device from a profile.\n"
+ "lxc profile device set <[remote:]container> <name> <key> <value> Set a device property.\n"
+ "lxc profile device unset <[remote:]container> <name> <key> Unset a device property.\n"
"lxc profile device add <profile name> <device name> <device type> [key=value]...\n"
" Add a profile device, such as a disk or a nic, to the containers\n"
" using the specified profile."
@@ -514,6 +516,8 @@ msgstr ""
msgid "Manage configuration.\n"
"\n"
"lxc config device add <[remote:]container> <name> <type> [key=value]... Add a device to a container.\n"
+ "lxc config device set <[remote:]container> <name> <key> <value> Set a device property.\n"
+ "lxc config device unset <[remote:]container> <name> <key> Unset a device property.\n"
"lxc config device list [remote:]<container> List devices for container.\n"
"lxc config device show [remote:]<container> Show full device details for container.\n"
"lxc config device remove [remote:]<container> <name> Remove device from container.\n"
@@ -682,11 +686,11 @@ msgstr ""
msgid "New alias to define at target"
msgstr ""
-#: lxc/config.go:280
+#: lxc/config.go:282
msgid "No certificate provided to add"
msgstr ""
-#: lxc/config.go:303
+#: lxc/config.go:305
msgid "No fingerprint specified."
msgstr ""
@@ -754,11 +758,11 @@ msgid "Presents details on how to use LXD.\n"
"lxd help [--all]"
msgstr ""
-#: lxc/profile.go:188
+#: lxc/profile.go:190
msgid "Press enter to open the editor again"
msgstr ""
-#: lxc/config.go:494 lxc/config.go:559 lxc/image.go:670
+#: lxc/config.go:496 lxc/config.go:561 lxc/image.go:670
msgid "Press enter to start the editor again"
msgstr ""
@@ -785,17 +789,17 @@ msgstr ""
msgid "Processes: %d"
msgstr ""
-#: lxc/profile.go:225
+#: lxc/profile.go:227
#, c-format
msgid "Profile %s applied to %s"
msgstr ""
-#: lxc/profile.go:139
+#: lxc/profile.go:141
#, c-format
msgid "Profile %s created"
msgstr ""
-#: lxc/profile.go:209
+#: lxc/profile.go:211
#, c-format
msgid "Profile %s deleted"
msgstr ""
More information about the lxc-devel
mailing list