The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3749

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) ===
This is a mechanical refactoring of the logic that fills in the
cmdInitData structure given the configuration parameters passed via
auto or collected in interactive mode.

It makes it a bit easier to both see in a blick what the high-level
logic workflow is and what individual configuration parameters
actually translate to low-level data to send via APIs.

Signed-off-by: Free Ekanayaka <[email protected]>
From 477cc8dc13034697374471a6eb80c97594b85ed6 Mon Sep 17 00:00:00 2001
From: Free Ekanayaka <[email protected]>
Date: Fri, 5 May 2017 08:42:17 +0200
Subject: [PATCH] Extract logic to fill init data to standalone methods

This is a mechanical refactoring of the logic that fills in the
cmdInitData structure given the configuration parameters passed via
auto or collected in interactive mode.

It makes it a bit easier to both see in a blick what the high-level
logic workflow is and what individual configuration parameters
actually translate to low-level data to send via APIs.

Signed-off-by: Free Ekanayaka <[email protected]>
---
 lxd/main_init.go  | 287 ++++++++++++++++++++++++++++++++----------------------
 shared/network.go |  15 +++
 2 files changed, 184 insertions(+), 118 deletions(-)

diff --git a/lxd/main_init.go b/lxd/main_init.go
index 9a3db166c..d91de668e 100644
--- a/lxd/main_init.go
+++ b/lxd/main_init.go
@@ -41,10 +41,6 @@ type CmdInit struct {
 
 // Run triggers the execution of the init command.
 func (cmd *CmdInit) Run() error {
-       // Figure what storage drivers among the supported ones are actually
-       // available on this system.
-       availableStoragePoolsDrivers := cmd.availableStoragePoolsDrivers()
-
        // Check that command line arguments don't conflict with each other
        err := cmd.validateArgs()
        if err != nil {
@@ -57,36 +53,13 @@ func (cmd *CmdInit) Run() error {
                return fmt.Errorf("Unable to talk to LXD: %s", err)
        }
 
-       err = cmd.runAutoOrInteractive(client, availableStoragePoolsDrivers)
-
-       if err == nil {
-               cmd.Context.Output("LXD has been successfully configured.\n")
-       }
-
-       return err
-}
-
-// Run the logic for auto or interactive mode.
-//
-// XXX: this logic is going to be refactored into two separate runAuto
-// and runInteractive methods, sharing relevant logic with
-// runPreseed. The idea being that both runAuto and runInteractive
-// will end up populating the same low-level cmdInitData structure
-// passed to the common run() method.
-func (cmd *CmdInit) runAutoOrInteractive(c lxd.ContainerServer, 
backendsAvailable []string) error {
-       var defaultPrivileged int // controls whether we set 
security.privileged=true
-       var storage *cmdInitStorageParams
-       var networking *cmdInitNetworkingParams
-
-       defaultPrivileged = -1
-
        // Check that we have no containers or images in the store
-       containers, err := c.GetContainerNames()
+       containers, err := client.GetContainerNames()
        if err != nil {
                return fmt.Errorf("Unable to list the LXD containers: %s", err)
        }
 
-       images, err := c.GetImageFingerprints()
+       images, err := client.GetImageFingerprints()
        if err != nil {
                return fmt.Errorf("Unable to list the LXD images: %s", err)
        }
@@ -95,137 +68,215 @@ func (cmd *CmdInit) runAutoOrInteractive(c 
lxd.ContainerServer, backendsAvailabl
                return fmt.Errorf("You have existing containers or images. lxd 
init requires an empty LXD.")
        }
 
+       data := &cmdInitData{}
+
+       // Copy the data from the current default profile, if it exists.
+       cmd.fillDataWithCurrentServerConfig(data, client)
+
+       // Copy the data from the current server config.
+       cmd.fillDataWithCurrentDefaultProfile(data, client)
+
+       // Figure what storage drivers among the supported ones are actually
+       // available on this system.
+       backendsAvailable := cmd.availableStoragePoolsDrivers()
+
        if cmd.Args.Auto {
-               if cmd.Args.StorageBackend == "" {
-                       cmd.Args.StorageBackend = "dir"
-               }
+               err = cmd.fillDataAuto(data, client, backendsAvailable)
+       } else {
+               err = cmd.fillDataInteractive(data, client, backendsAvailable)
+       }
 
-               err = cmd.validateArgsAuto(backendsAvailable)
-               if err != nil {
-                       return err
-               }
+       if err != nil {
+               return err
+       }
+
+       // Apply the desired configuration.
+       err = cmd.apply(client, data)
+       if err != nil {
+               return err
+       }
+       cmd.Context.Output("LXD has been successfully configured.\n")
 
-               networking = &cmdInitNetworkingParams{
+       return nil
+}
+
+// Fill the given configuration data with parameters collected from
+// the --auto command line.
+func (cmd *CmdInit) fillDataAuto(data *cmdInitData, client 
lxd.ContainerServer, backendsAvailable []string) error {
+       if cmd.Args.StorageBackend == "" {
+               cmd.Args.StorageBackend = "dir"
+       }
+       err := cmd.validateArgsAuto(backendsAvailable)
+       if err != nil {
+               return err
+       }
+
+       if cmd.Args.NetworkAddress != "" {
+               // If no port was provided, use the default one
+               if cmd.Args.NetworkPort == -1 {
+                       cmd.Args.NetworkPort = 8443
+               }
+               networking := &cmdInitNetworkingParams{
                        Address:       cmd.Args.NetworkAddress,
                        Port:          cmd.Args.NetworkPort,
                        TrustPassword: cmd.Args.TrustPassword,
                }
+               cmd.fillDataWithNetworking(data, networking)
+       }
 
-               if cmd.Args.StorageBackend == "zfs" {
-                       storage = &cmdInitStorageParams{
-                               Backend:  cmd.Args.StorageBackend,
-                               LoopSize: cmd.Args.StorageCreateLoop,
-                               Device:   cmd.Args.StorageCreateDevice,
-                               Pool:     cmd.Args.StoragePool,
-                       }
-
-                       if cmd.Args.StorageCreateDevice != "" {
-                               storage.Mode = "device"
-                       } else if cmd.Args.StorageCreateLoop != -1 {
-                               storage.Mode = "loop"
-                       } else {
-                               storage.Mode = "existing"
-                       }
+       if cmd.Args.StorageBackend == "zfs" {
+               storage := &cmdInitStorageParams{
+                       Backend:  cmd.Args.StorageBackend,
+                       LoopSize: cmd.Args.StorageCreateLoop,
+                       Device:   cmd.Args.StorageCreateDevice,
+                       Pool:     cmd.Args.StoragePool,
                }
 
-       } else {
-               storage, err = cmd.askStorage(c, backendsAvailable)
+               if cmd.Args.StorageCreateDevice != "" {
+                       storage.Mode = "device"
+               } else if cmd.Args.StorageCreateLoop != -1 {
+                       storage.Mode = "loop"
+               } else {
+                       storage.Mode = "existing"
+               }
+               err = cmd.fillDataWithStorage(data, storage)
                if err != nil {
                        return err
                }
+       }
+       return nil
+}
 
-               defaultPrivileged = cmd.askDefaultPrivileged()
-               networking = cmd.askNetworking()
-
+// Fill the given configuration data with parameters collected with
+// interactive questions.
+func (cmd *CmdInit) fillDataInteractive(data *cmdInitData, client 
lxd.ContainerServer, backendsAvailable []string) error {
+       storage, err := cmd.askStorage(client, backendsAvailable)
+       if err != nil {
+               return err
        }
+       defaultPrivileged := cmd.askDefaultPrivileged()
+       networking := cmd.askNetworking()
 
-       // Destroy any existing loop device
-       for _, file := range []string{"zfs.img"} {
-               os.Remove(shared.VarPath(file))
+       err = cmd.fillDataWithStorage(data, storage)
+       if err != nil {
+               return err
        }
 
-       server, _, err := c.GetServer()
+       err = cmd.fillDataWithDefaultPrivileged(data, defaultPrivileged)
        if err != nil {
                return err
        }
 
-       data := &cmdInitData{}
-       data.ServerPut = server.Writable()
+       cmd.fillDataWithNetworking(data, networking)
 
-       // If there's a default profile, and certain conditions are
-       // met we'll update its root disk device and/or eth0 network
-       // device, as well as its privileged mode (see below).
-       defaultProfile, _, getDefaultProfileErr := c.GetProfile("default")
-
-       if storage != nil {
-               if storage.Mode == "loop" {
-                       storage.Device = shared.VarPath("zfs.img")
-                       f, err := os.Create(storage.Device)
-                       if err != nil {
-                               return fmt.Errorf("Failed to open %s: %s", 
storage.Device, err)
-                       }
+       return nil
+}
 
-                       err = f.Chmod(0600)
-                       if err != nil {
-                               return fmt.Errorf("Failed to chmod %s: %s", 
storage.Device, err)
-                       }
+// Fill the given data with the current server configuration.
+func (cmd *CmdInit) fillDataWithCurrentServerConfig(data *cmdInitData, client 
lxd.ContainerServer) error {
+       server, _, err := client.GetServer()
+       if err != nil {
+               return err
+       }
+       data.ServerPut = server.Writable()
+       return nil
+}
 
-                       err = f.Truncate(int64(storage.LoopSize * 1024 * 1024 * 
1024))
-                       if err != nil {
-                               return fmt.Errorf("Failed to create sparse file 
%s: %s", storage.Device, err)
-                       }
+// Fill the given data with the current default profile, if it exists.
+func (cmd *CmdInit) fillDataWithCurrentDefaultProfile(data *cmdInitData, 
client lxd.ContainerServer) {
+       defaultProfile, _, err := client.GetProfile("default")
+       if err == nil {
+               // Copy the default profile configuration (that we have
+               // possibly modified above).
+               data.Profiles = []api.ProfilesPost{{Name: "default"}}
+               data.Profiles[0].ProfilePut = defaultProfile.ProfilePut
+       }
+}
 
-                       err = f.Close()
-                       if err != nil {
-                               return fmt.Errorf("Failed to close %s: %s", 
storage.Device, err)
-                       }
+// Fill the given init data with a new storage pool structure matching the
+// given storage parameters.
+func (cmd *CmdInit) fillDataWithStorage(data *cmdInitData, storage 
*cmdInitStorageParams) error {
+       if storage == nil {
+               return nil
+       }
+
+       if storage.Mode == "loop" {
+               storage.Device = shared.VarPath("zfs.img")
+               f, err := os.Create(storage.Device)
+               if err != nil {
+                       return fmt.Errorf("Failed to open %s: %s", 
storage.Device, err)
                }
 
-               if shared.StringInSlice(storage.Mode, []string{"loop", 
"device"}) {
-                       output, err := shared.RunCommand(
-                               "zpool",
-                               "create", storage.Pool, storage.Device,
-                               "-f", "-m", "none", "-O", "compression=on")
-                       if err != nil {
-                               return fmt.Errorf("Failed to create the ZFS 
pool: %s", output)
-                       }
+               err = f.Chmod(0600)
+               if err != nil {
+                       return fmt.Errorf("Failed to chmod %s: %s", 
storage.Device, err)
                }
 
-               data.Config["storage.zfs_pool_name"] = storage.Pool
-       }
+               err = f.Truncate(int64(storage.LoopSize * 1024 * 1024 * 1024))
+               if err != nil {
+                       return fmt.Errorf("Failed to create sparse file %s: 
%s", storage.Device, err)
+               }
 
-       if defaultPrivileged != -1 && getDefaultProfileErr != nil {
-               return getDefaultProfileErr
-       } else if defaultPrivileged == 0 {
-               defaultProfile.Config["security.privileged"] = ""
-       } else if defaultPrivileged == 1 {
-               defaultProfile.Config["security.privileged"] = "true"
+               err = f.Close()
+               if err != nil {
+                       return fmt.Errorf("Failed to close %s: %s", 
storage.Device, err)
+               }
        }
 
-       if networking != nil {
-               data.Config["core.https_address"] = fmt.Sprintf("%s:%d", 
networking.Address, networking.Port)
-               if networking.TrustPassword != "" {
-                       data.Config["core.trust_password"] = 
networking.TrustPassword
+       if shared.StringInSlice(storage.Mode, []string{"loop", "device"}) {
+               output, err := shared.RunCommand(
+                       "zpool",
+                       "create", storage.Pool, storage.Device,
+                       "-f", "-m", "none", "-O", "compression=on")
+               if err != nil {
+                       return fmt.Errorf("Failed to create the ZFS pool: %s", 
output)
                }
+       } else {
+               logger.Warnf("Did not find profile \"default\" so no default 
storage pool will be set. Manual intervention needed.")
        }
 
-       if getDefaultProfileErr == nil {
-               // Copy the default profile configuration (that we have
-               // possibly modified above).
-               data.Profiles = []api.ProfilesPost{{Name: "default"}}
-               data.Profiles[0].ProfilePut = defaultProfile.ProfilePut
-       }
+       data.Config["storage.zfs_pool_name"] = storage.Pool
 
-       err = cmd.run(c, data)
-       if err != nil {
+       return nil
+}
+
+// Fill the default profile in the given init data with options about whether
+// to run in privileged mode.
+func (cmd *CmdInit) fillDataWithDefaultPrivileged(data *cmdInitData, 
defaultPrivileged int) error {
+       if defaultPrivileged == -1 {
                return nil
        }
-
+       if len(data.Profiles) == 0 {
+               return fmt.Errorf("error: profile 'default' profile not found")
+       }
+       defaultProfile := data.Profiles[0]
+       if defaultPrivileged == 0 {
+               defaultProfile.Config["security.privileged"] = ""
+       } else if defaultPrivileged == 1 {
+               defaultProfile.Config["security.privileged"] = "true"
+       }
        return nil
 }
 
+// Fill the given init data with server config details matching the
+// given networking parameters.
+func (cmd *CmdInit) fillDataWithNetworking(data *cmdInitData, networking 
*cmdInitNetworkingParams) {
+       if networking == nil {
+               return
+       }
+       data.Config["core.https_address"] = fmt.Sprintf("%s:%d", 
networking.Address, networking.Port)
+       if networking.TrustPassword != "" {
+               data.Config["core.trust_password"] = networking.TrustPassword
+       }
+}
+
 // Apply the configuration specified in the given init data.
-func (cmd *CmdInit) run(client lxd.ContainerServer, data *cmdInitData) error {
+func (cmd *CmdInit) apply(client lxd.ContainerServer, data *cmdInitData) error 
{
+       // Destroy any existing loop device
+       for _, file := range []string{"zfs.img"} {
+               os.Remove(shared.VarPath(file))
+       }
+
        // Functions that should be invoked to revert back to initial
        // state any change that was successfully applied, in case
        // anything goes wrong after that change.
@@ -406,7 +457,7 @@ func (cmd *CmdInit) availableStoragePoolsDrivers() []string 
{
 
 // Return an error if the given profile has already a device with the
 // given name.
-func (cmd *CmdInit) profileDeviceAlreadyExists(profile *api.Profile, 
deviceName string) error {
+func (cmd *CmdInit) profileDeviceAlreadyExists(profile *api.ProfilesPost, 
deviceName string) error {
        _, ok := profile.Devices[deviceName]
        if ok {
                return fmt.Errorf("Device already exists: %s", deviceName)
diff --git a/shared/network.go b/shared/network.go
index e9857e547..51f1d796a 100644
--- a/shared/network.go
+++ b/shared/network.go
@@ -332,3 +332,18 @@ func WebsocketMirror(conn *websocket.Conn, w 
io.WriteCloser, r io.ReadCloser, Re
 var WebsocketUpgrader = websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool { return true },
 }
+
+// AllocatePort asks the kernel for a free open port that is ready to use
+func AllocatePort() (int, error) {
+       addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+       if err != nil {
+               return -1, err
+       }
+
+       l, err := net.ListenTCP("tcp", addr)
+       if err != nil {
+               return -1, err
+       }
+       defer l.Close()
+       return l.Addr().(*net.TCPAddr).Port, nil
+}
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to