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

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) ===

From 592d0aa4f9784e8bc978db50e9f63a1fd512df3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Fri, 23 Feb 2018 19:23:33 -0500
Subject: [PATCH 1/5] lxd-p2c: Drop duplicate definition of Use
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd-p2c/main.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lxd-p2c/main.go b/lxd-p2c/main.go
index 5a9d71340..535f71305 100644
--- a/lxd-p2c/main.go
+++ b/lxd-p2c/main.go
@@ -15,7 +15,6 @@ type cmdGlobal struct {
 
 func main() {
        app := &cobra.Command{}
-       app.Use = "lxd-p2c"
        app.Short = "Physical to container migration tool"
        app.Long = `Description:
   Physical to container migration tool

From 7f7aca0e60bc90cd40a4086e7035a7e5b118530d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Fri, 23 Feb 2018 19:23:47 -0500
Subject: [PATCH 2/5] fuidshift: Drop duplicate definition of Use
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 fuidshift/main.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fuidshift/main.go b/fuidshift/main.go
index 3bf1f18b4..0909b976d 100644
--- a/fuidshift/main.go
+++ b/fuidshift/main.go
@@ -15,7 +15,6 @@ type cmdGlobal struct {
 
 func main() {
        app := &cobra.Command{}
-       app.Use = "fuidshift"
        app.Short = "UID/GID shifter"
        app.Long = `Description:
   UID/GID shifter

From c500a82f3920a9c5783df7a8ece10a8e3d273693 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Fri, 23 Feb 2018 20:47:28 -0500
Subject: [PATCH 3/5] lxd-benchmark: Port to cobra
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd-benchmark/main.go        | 205 +++++++++++++++++++++----------------------
 lxd-benchmark/main_delete.go |  50 +++++++++++
 lxd-benchmark/main_init.go   |  55 ++++++++++++
 lxd-benchmark/main_launch.go |  55 ++++++++++++
 lxd-benchmark/main_start.go  |  50 +++++++++++
 lxd-benchmark/main_stop.go   |  50 +++++++++++
 6 files changed, 362 insertions(+), 103 deletions(-)
 create mode 100644 lxd-benchmark/main_delete.go
 create mode 100644 lxd-benchmark/main_init.go
 create mode 100644 lxd-benchmark/main_launch.go
 create mode 100644 lxd-benchmark/main_start.go
 create mode 100644 lxd-benchmark/main_stop.go

diff --git a/lxd-benchmark/main.go b/lxd-benchmark/main.go
index 50cdfe87d..1d0da671e 100644
--- a/lxd-benchmark/main.go
+++ b/lxd-benchmark/main.go
@@ -1,135 +1,134 @@
 package main
 
 import (
-       "fmt"
        "os"
        "time"
 
+       "github.com/spf13/cobra"
+
        "github.com/lxc/lxd/client"
        "github.com/lxc/lxd/lxd-benchmark/benchmark"
        "github.com/lxc/lxd/shared"
-       "github.com/lxc/lxd/shared/gnuflag"
        "github.com/lxc/lxd/shared/version"
 )
 
-var argCount = gnuflag.Int("count", 1, "Number of containers to create")
-var argParallel = gnuflag.Int("parallel", -1, "Number of threads to use")
-var argImage = gnuflag.String("image", "ubuntu:", "Image to use for the test")
-var argPrivileged = gnuflag.Bool("privileged", false, "Use privileged 
containers")
-var argStart = gnuflag.Bool("start", true, "Start the container after 
creation")
-var argFreeze = gnuflag.Bool("freeze", false, "Freeze the container right 
after start")
-var argReportFile = gnuflag.String("report-file", "", "A CSV file to write 
test file to. If the file is present, it will be appended to.")
-var argReportLabel = gnuflag.String("report-label", "", "A label for the 
report entry. By default, the action is used.")
-
-func main() {
-       err := run(os.Args)
-       if err != nil {
-               fmt.Fprintf(os.Stderr, "error: %s\n", err)
-               os.Exit(1)
-       }
+type cmdGlobal struct {
+       flagHelp        bool
+       flagParallel    int
+       flagReportFile  string
+       flagReportLabel string
+       flagVersion     bool
 
-       os.Exit(0)
+       srv    lxd.ContainerServer
+       report *benchmark.CSVReport
 }
 
-func run(args []string) error {
-       // Parse command line
-       // "spawn" is being deprecated, use "launch" instead.
-       if len(os.Args) == 1 || !shared.StringInSlice(os.Args[1], 
[]string{"launch", "spawn", "start", "stop", "delete"}) {
-               if len(os.Args) > 1 && os.Args[1] == "--version" {
-                       fmt.Println(version.Version)
-                       return nil
-               }
-
-               out := os.Stderr
-               if len(os.Args) > 1 && os.Args[1] == "--help" {
-                       out = os.Stdout
-               }
-               gnuflag.SetOut(out)
-
-               fmt.Fprintf(out, "Usage: %s launch [--count=COUNT] 
[--image=IMAGE] [--privileged=BOOL] [--start=BOOL] [--freeze=BOOL] 
[--parallel=COUNT]\n", os.Args[0])
-               fmt.Fprintf(out, "       %s start [--parallel=COUNT]\n", 
os.Args[0])
-               fmt.Fprintf(out, "       %s stop [--parallel=COUNT]\n", 
os.Args[0])
-               fmt.Fprintf(out, "       %s delete [--parallel=COUNT]\n\n", 
os.Args[0])
-               gnuflag.PrintDefaults()
-               fmt.Fprintf(out, "\n")
-
-               if len(os.Args) > 1 && os.Args[1] == "--help" {
-                       return nil
-               }
-
-               return fmt.Errorf("A valid action (launch, start, stop, delete) 
must be passed")
-       }
-
-       gnuflag.Parse(true)
-
+func (c *cmdGlobal) Setup() error {
        // Connect to LXD
-       c, err := lxd.ConnectLXDUnix("", nil)
+       srv, err := lxd.ConnectLXDUnix("", nil)
        if err != nil {
                return err
        }
+       c.srv = srv
 
-       benchmark.PrintServerInfo(c)
+       // Print the initial header
+       benchmark.PrintServerInfo(srv)
 
-       var report *benchmark.CSVReport
-       if *argReportFile != "" {
-               report = &benchmark.CSVReport{Filename: *argReportFile}
-               if shared.PathExists(*argReportFile) {
-                       err := report.Load()
+       // Setup report handling
+       if c.flagReportFile != "" {
+               c.report = &benchmark.CSVReport{Filename: c.flagReportFile}
+               if shared.PathExists(c.flagReportFile) {
+                       err := c.report.Load()
                        if err != nil {
                                return err
                        }
                }
        }
 
-       action := os.Args[1]
-       var duration time.Duration
-       switch action {
-       // "spawn" is being deprecated.
-       case "launch", "spawn":
-               duration, err = benchmark.LaunchContainers(
-                       c, *argCount, *argParallel, *argImage, *argPrivileged, 
*argStart, *argFreeze)
-               if err != nil {
-                       return err
-               }
-       case "start":
-               containers, err := benchmark.GetContainers(c)
-               if err != nil {
-                       return err
-               }
-               duration, err = benchmark.StartContainers(c, containers, 
*argParallel)
-               if err != nil {
-                       return err
-               }
-       case "stop":
-               containers, err := benchmark.GetContainers(c)
-               if err != nil {
-                       return err
-               }
-               duration, err = benchmark.StopContainers(c, containers, 
*argParallel)
-               if err != nil {
-                       return err
-               }
-       case "delete":
-               containers, err := benchmark.GetContainers(c)
-               if err != nil {
-                       return err
-               }
-               duration, err = benchmark.DeleteContainers(c, containers, 
*argParallel)
-               if err != nil {
-                       return err
-               }
+       return nil
+}
+
+func (c *cmdGlobal) Teardown(action string, duration time.Duration) error {
+       // Nothing to do with not reporting
+       if c.report == nil {
+               return nil
        }
 
-       if report != nil {
-               label := action
-               if *argReportLabel != "" {
-                       label = *argReportLabel
-               }
-               report.AddRecord(label, duration)
-               err := report.Write()
-               if err != nil {
-                       return err
-               }
+       label := action
+       if c.flagReportLabel != "" {
+               label = c.flagReportLabel
+       }
+
+       c.report.AddRecord(label, duration)
+
+       err := c.report.Write()
+       if err != nil {
+               return err
        }
+
        return nil
 }
+
+func main() {
+       app := &cobra.Command{}
+       app.Use = "lxd-benchmark"
+       app.Short = "Benchmark performance of LXD"
+       app.Long = `Description:
+  Benchmark performance of LXD
+
+  This tool lets you benchmark various actions on a local LXD daemon.
+
+  It can be used to just to check how fast a given LXD host is, to
+  compare performance on different servers or for performance tracking
+  when doing changes to the LXD codebase.
+
+  A CSV report can be produced to be consumed by graphing software.
+`
+       app.Example = `  # Spawn 20 Ubuntu containers in batches of 4
+  lxd-benchmark launch --count 20 --parallel 4
+
+  # Create 50 Alpine containers in batches of 10
+  lxd-benchmark init --count 50 --parallel 10 images:alpine/edge
+
+  # Delete all test containers using dynamic batch size
+  lxd-benchmark delete`
+       app.SilenceUsage = true
+
+       // Global flags
+       globalCmd := cmdGlobal{}
+       app.PersistentFlags().BoolVar(&globalCmd.flagVersion, "version", false, 
"Print version number")
+       app.PersistentFlags().BoolVarP(&globalCmd.flagHelp, "help", "h", false, 
"Print help")
+       app.PersistentFlags().IntVarP(&globalCmd.flagParallel, "parallel", "P", 
-1, "Number of threads to use"+"``")
+       app.PersistentFlags().StringVar(&globalCmd.flagReportFile, 
"report-file", "", "Path to the CSV report file"+"``")
+       app.PersistentFlags().StringVar(&globalCmd.flagReportLabel, 
"report-label", "", "Label for the new entry in the report 
[default=ACTION]"+"``")
+
+       // Version handling
+       app.SetVersionTemplate("{{.Version}}\n")
+       app.Version = version.Version
+
+       // init sub-command
+       initCmd := cmdInit{global: &globalCmd}
+       app.AddCommand(initCmd.Command())
+
+       // launch sub-command
+       launchCmd := cmdLaunch{global: &globalCmd, init: &initCmd}
+       app.AddCommand(launchCmd.Command())
+
+       // start sub-command
+       startCmd := cmdStart{global: &globalCmd}
+       app.AddCommand(startCmd.Command())
+
+       // stop sub-command
+       stopCmd := cmdStop{global: &globalCmd}
+       app.AddCommand(stopCmd.Command())
+
+       // delete sub-command
+       deleteCmd := cmdDelete{global: &globalCmd}
+       app.AddCommand(deleteCmd.Command())
+
+       // Run the main command and handle errors
+       err := app.Execute()
+       if err != nil {
+               os.Exit(1)
+       }
+}
diff --git a/lxd-benchmark/main_delete.go b/lxd-benchmark/main_delete.go
new file mode 100644
index 000000000..5b0ed64c3
--- /dev/null
+++ b/lxd-benchmark/main_delete.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+       "github.com/spf13/cobra"
+
+       "github.com/lxc/lxd/lxd-benchmark/benchmark"
+)
+
+type cmdDelete struct {
+       cmd    *cobra.Command
+       global *cmdGlobal
+}
+
+func (c *cmdDelete) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "delete"
+       cmd.Short = "Delete containers"
+       cmd.RunE = c.Run
+
+       c.cmd = cmd
+       return cmd
+}
+
+func (c *cmdDelete) Run(cmd *cobra.Command, args []string) error {
+       // Run shared setup code
+       err := c.global.Setup()
+       if err != nil {
+               return err
+       }
+
+       // Get the containers
+       containers, err := benchmark.GetContainers(c.global.srv)
+       if err != nil {
+               return err
+       }
+
+       // Run the test
+       duration, err := benchmark.DeleteContainers(c.global.srv, containers, 
c.global.flagParallel)
+       if err != nil {
+               return err
+       }
+
+       // Run shared reporting and teardown code
+       err = c.global.Teardown("delete", duration)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
diff --git a/lxd-benchmark/main_init.go b/lxd-benchmark/main_init.go
new file mode 100644
index 000000000..b7ef8d30d
--- /dev/null
+++ b/lxd-benchmark/main_init.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+       "github.com/spf13/cobra"
+
+       "github.com/lxc/lxd/lxd-benchmark/benchmark"
+)
+
+type cmdInit struct {
+       cmd    *cobra.Command
+       global *cmdGlobal
+
+       flagCount      int
+       flagPrivileged bool
+}
+
+func (c *cmdInit) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "init [[<remote>:]<image>]"
+       cmd.Short = "Create containers"
+       cmd.RunE = c.Run
+       cmd.Flags().IntVarP(&c.flagCount, "count", "C", 1, "Number of 
containers to create"+"``")
+       cmd.Flags().BoolVar(&c.flagPrivileged, "privileged", false, "Use 
privileged containers")
+
+       c.cmd = cmd
+       return cmd
+}
+
+func (c *cmdInit) Run(cmd *cobra.Command, args []string) error {
+       // Run shared setup code
+       err := c.global.Setup()
+       if err != nil {
+               return err
+       }
+
+       // Choose the image
+       image := "ubuntu:"
+       if len(args) > 0 {
+               image = args[0]
+       }
+
+       // Run the test
+       duration, err := benchmark.LaunchContainers(c.global.srv, c.flagCount, 
c.global.flagParallel, image, c.flagPrivileged, false, false)
+       if err != nil {
+               return err
+       }
+
+       // Run shared reporting and teardown code
+       err = c.global.Teardown("init", duration)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
diff --git a/lxd-benchmark/main_launch.go b/lxd-benchmark/main_launch.go
new file mode 100644
index 000000000..419d16fca
--- /dev/null
+++ b/lxd-benchmark/main_launch.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+       "github.com/spf13/cobra"
+
+       "github.com/lxc/lxd/lxd-benchmark/benchmark"
+)
+
+type cmdLaunch struct {
+       cmd    *cobra.Command
+       global *cmdGlobal
+       init   *cmdInit
+
+       flagFreeze bool
+}
+
+func (c *cmdLaunch) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "launch [[<remote>:]<image>]"
+       cmd.Short = "Create and start containers"
+       cmd.RunE = c.Run
+       cmd.Flags().AddFlagSet(c.init.cmd.Flags())
+       cmd.Flags().BoolVarP(&c.flagFreeze, "freeze", "F", false, "Freeze the 
container right after start")
+
+       c.cmd = cmd
+       return cmd
+}
+
+func (c *cmdLaunch) Run(cmd *cobra.Command, args []string) error {
+       // Run shared setup code
+       err := c.global.Setup()
+       if err != nil {
+               return err
+       }
+
+       // Choose the image
+       image := "ubuntu:"
+       if len(args) > 0 {
+               image = args[0]
+       }
+
+       // Run the test
+       duration, err := benchmark.LaunchContainers(c.global.srv, 
c.init.flagCount, c.global.flagParallel, image, c.init.flagPrivileged, true, 
c.flagFreeze)
+       if err != nil {
+               return err
+       }
+
+       // Run shared reporting and teardown code
+       err = c.global.Teardown("launch", duration)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
diff --git a/lxd-benchmark/main_start.go b/lxd-benchmark/main_start.go
new file mode 100644
index 000000000..b6d9655c1
--- /dev/null
+++ b/lxd-benchmark/main_start.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+       "github.com/spf13/cobra"
+
+       "github.com/lxc/lxd/lxd-benchmark/benchmark"
+)
+
+type cmdStart struct {
+       cmd    *cobra.Command
+       global *cmdGlobal
+}
+
+func (c *cmdStart) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "start"
+       cmd.Short = "Start containers"
+       cmd.RunE = c.Run
+
+       c.cmd = cmd
+       return cmd
+}
+
+func (c *cmdStart) Run(cmd *cobra.Command, args []string) error {
+       // Run shared setup code
+       err := c.global.Setup()
+       if err != nil {
+               return err
+       }
+
+       // Get the containers
+       containers, err := benchmark.GetContainers(c.global.srv)
+       if err != nil {
+               return err
+       }
+
+       // Run the test
+       duration, err := benchmark.StartContainers(c.global.srv, containers, 
c.global.flagParallel)
+       if err != nil {
+               return err
+       }
+
+       // Run shared reporting and teardown code
+       err = c.global.Teardown("start", duration)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
diff --git a/lxd-benchmark/main_stop.go b/lxd-benchmark/main_stop.go
new file mode 100644
index 000000000..f41f42f67
--- /dev/null
+++ b/lxd-benchmark/main_stop.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+       "github.com/spf13/cobra"
+
+       "github.com/lxc/lxd/lxd-benchmark/benchmark"
+)
+
+type cmdStop struct {
+       cmd    *cobra.Command
+       global *cmdGlobal
+}
+
+func (c *cmdStop) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "stop"
+       cmd.Short = "Stop containers"
+       cmd.RunE = c.Run
+
+       c.cmd = cmd
+       return cmd
+}
+
+func (c *cmdStop) Run(cmd *cobra.Command, args []string) error {
+       // Run shared setup code
+       err := c.global.Setup()
+       if err != nil {
+               return err
+       }
+
+       // Get the containers
+       containers, err := benchmark.GetContainers(c.global.srv)
+       if err != nil {
+               return err
+       }
+
+       // Run the test
+       duration, err := benchmark.StopContainers(c.global.srv, containers, 
c.global.flagParallel)
+       if err != nil {
+               return err
+       }
+
+       // Run shared reporting and teardown code
+       err = c.global.Teardown("stop", duration)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}

From 9d3e3bf47ba4260211286cb12e6bdaab1c27f983 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Fri, 23 Feb 2018 20:54:51 -0500
Subject: [PATCH 4/5] fuidshift: Reshuffle code to match lxd-benchmark
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 fuidshift/main.go       | 32 ++++----------------------------
 fuidshift/main_shift.go | 29 +++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 28 deletions(-)

diff --git a/fuidshift/main.go b/fuidshift/main.go
index 0909b976d..4fc45d9d9 100644
--- a/fuidshift/main.go
+++ b/fuidshift/main.go
@@ -3,8 +3,6 @@ package main
 import (
        "os"
 
-       "github.com/spf13/cobra"
-
        "github.com/lxc/lxd/shared/version"
 )
 
@@ -14,28 +12,14 @@ type cmdGlobal struct {
 }
 
 func main() {
-       app := &cobra.Command{}
-       app.Short = "UID/GID shifter"
-       app.Long = `Description:
-  UID/GID shifter
-
-  This tool lets you remap a filesystem tree, switching it from one
-  set of UID/GID ranges to another.
-
-  This is mostly useful when retrieving a wrongly shifted filesystem tree
-  from a backup or broken system and having to remap everything either to
-  the host UID/GID range (uid/gid 0 is root) or to an existing container's
-  range.
-
-
-  A range is represented as 
<u|b|g>:<first_container_id>:<first_host_id>:<size>.
-  Where "u" means shift uid, "g" means shift gid and "b" means shift uid and 
gid.
-`
-       app.Example = `  fuidshift my-dir/ b:0:100000:65536 u:10000:1000:1`
+       // shift command (main)
+       shiftCmd := cmdShift{}
+       app := shiftCmd.Command()
        app.SilenceUsage = true
 
        // Global flags
        globalCmd := cmdGlobal{}
+       shiftCmd.global = &globalCmd
        app.PersistentFlags().BoolVar(&globalCmd.flagVersion, "version", false, 
"Print version number")
        app.PersistentFlags().BoolVarP(&globalCmd.flagHelp, "help", "h", false, 
"Print help")
 
@@ -43,14 +27,6 @@ func main() {
        app.SetVersionTemplate("{{.Version}}\n")
        app.Version = version.Version
 
-       // shift command (main)
-       shiftCmd := cmdShift{global: &globalCmd}
-       app.Flags().BoolVarP(&shiftCmd.flagTestMode, "test", "t", false, "Test 
mode (no change to files)")
-       app.Flags().BoolVarP(&shiftCmd.flagReverse, "reverse", "r", false, 
"Perform a reverse mapping")
-       app.Use = "fuidshift <directory> <range> [<range>...]"
-       app.RunE = shiftCmd.Run
-       app.Args = cobra.ArbitraryArgs
-
        // Run the main command and handle errors
        err := app.Execute()
        if err != nil {
diff --git a/fuidshift/main_shift.go b/fuidshift/main_shift.go
index 32c939bc0..74403aaed 100644
--- a/fuidshift/main_shift.go
+++ b/fuidshift/main_shift.go
@@ -10,12 +10,41 @@ import (
 )
 
 type cmdShift struct {
+       cmd    *cobra.Command
        global *cmdGlobal
 
        flagReverse  bool
        flagTestMode bool
 }
 
+func (c *cmdShift) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "fuidshift <directory> <range> [<range>...]"
+       cmd.Short = "UID/GID shifter"
+       cmd.Long = `Description:
+  UID/GID shifter
+
+  This tool lets you remap a filesystem tree, switching it from one
+  set of UID/GID ranges to another.
+
+  This is mostly useful when retrieving a wrongly shifted filesystem tree
+  from a backup or broken system and having to remap everything either to
+  the host UID/GID range (uid/gid 0 is root) or to an existing container's
+  range.
+
+
+  A range is represented as 
<u|b|g>:<first_container_id>:<first_host_id>:<size>.
+  Where "u" means shift uid, "g" means shift gid and "b" means shift uid and 
gid.
+`
+       cmd.Example = `  fuidshift my-dir/ b:0:100000:65536 u:10000:1000:1`
+       cmd.RunE = c.Run
+       cmd.Flags().BoolVarP(&c.flagTestMode, "test", "t", false, "Test mode 
(no change to files)")
+       cmd.Flags().BoolVarP(&c.flagReverse, "reverse", "r", false, "Perform a 
reverse mapping")
+
+       c.cmd = cmd
+       return cmd
+}
+
 func (c *cmdShift) Run(cmd *cobra.Command, args []string) error {
        // Help and usage
        if len(args) == 0 {

From 038e9ae9986e2867219ac41145947b4723e14cd5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Fri, 23 Feb 2018 21:02:48 -0500
Subject: [PATCH 5/5] lxd-p2c: Reshuffle code to match lxd-benchmark
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 lxd-p2c/main.go         | 40 ++++++++--------------------------------
 lxd-p2c/main_migrate.go | 29 +++++++++++++++++++++++++++++
 lxd-p2c/main_netcat.go  | 13 +++++++++++++
 3 files changed, 50 insertions(+), 32 deletions(-)

diff --git a/lxd-p2c/main.go b/lxd-p2c/main.go
index 535f71305..a350214ed 100644
--- a/lxd-p2c/main.go
+++ b/lxd-p2c/main.go
@@ -14,24 +14,17 @@ type cmdGlobal struct {
 }
 
 func main() {
-       app := &cobra.Command{}
-       app.Short = "Physical to container migration tool"
-       app.Long = `Description:
-  Physical to container migration tool
-
-  This tool lets you turn any Linux filesystem (including your current one)
-  into a LXD container on a remote LXD host.
-
-  It will setup a clean mount tree made of the root filesystem and any
-  additional mount you list, then transfer this through LXD's migration
-  API to create a new container from it.
-
-  The same set of options as ` + "`lxc launch`" + ` are also supported.
-`
+       // migrate command (main)
+       migrateCmd := cmdMigrate{}
+       app := migrateCmd.Command()
        app.SilenceUsage = true
 
+       // Workaround for main command
+       app.Args = cobra.ArbitraryArgs
+
        // Global flags
        globalCmd := cmdGlobal{}
+       migrateCmd.global = &globalCmd
        app.PersistentFlags().BoolVar(&globalCmd.flagVersion, "version", false, 
"Print version number")
        app.PersistentFlags().BoolVarP(&globalCmd.flagHelp, "help", "h", false, 
"Print help")
 
@@ -39,26 +32,9 @@ func main() {
        app.SetVersionTemplate("{{.Version}}\n")
        app.Version = version.Version
 
-       // migrate command (main)
-       migrateCmd := cmdMigrate{global: &globalCmd}
-       app.Flags().StringArrayVarP(&migrateCmd.flagConfig, "config", "c", nil, 
"Configuration key and value to set on the container"+"``")
-       app.Flags().StringVarP(&migrateCmd.flagNetwork, "network", "n", "", 
"Network to use for the container"+"``")
-       app.Flags().StringArrayVarP(&migrateCmd.flagProfile, "profile", "p", 
nil, "Profile to apply to the container"+"``")
-       app.Flags().StringVarP(&migrateCmd.flagStorage, "storage", "s", "", 
"Storage pool to use for the container"+"``")
-       app.Flags().StringVarP(&migrateCmd.flagType, "type", "t", "", "Instance 
type to use for the container"+"``")
-       app.Flags().BoolVar(&migrateCmd.flagNoProfiles, "no-profiles", false, 
"Create the container with no profiles applied")
-       app.Use = "lxd-p2c <target URL> <container name> <filesystem root> 
[<filesystem mounts>...]"
-       app.RunE = migrateCmd.Run
-       app.Args = cobra.ArbitraryArgs
-
        // netcat sub-command
        netcatCmd := cmdNetcat{global: &globalCmd}
-       appNetcat := &cobra.Command{}
-       appNetcat.Use = "netcat <address>"
-       appNetcat.Hidden = true
-       appNetcat.Short = "Sends stdin data to a unix socket"
-       appNetcat.RunE = netcatCmd.Run
-       app.AddCommand(appNetcat)
+       app.AddCommand(netcatCmd.Command())
 
        // Run the main command and handle errors
        err := app.Execute()
diff --git a/lxd-p2c/main_migrate.go b/lxd-p2c/main_migrate.go
index 9b25cec09..39c5f4536 100644
--- a/lxd-p2c/main_migrate.go
+++ b/lxd-p2c/main_migrate.go
@@ -17,6 +17,7 @@ import (
 )
 
 type cmdMigrate struct {
+       cmd    *cobra.Command
        global *cmdGlobal
 
        flagConfig     []string
@@ -27,6 +28,34 @@ type cmdMigrate struct {
        flagNoProfiles bool
 }
 
+func (c *cmdMigrate) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+       cmd.Use = "lxd-p2c <target URL> <container name> <filesystem root> 
[<filesystem mounts>...]"
+       cmd.Short = "Physical to container migration tool"
+       cmd.Long = `Description:
+  Physical to container migration tool
+
+  This tool lets you turn any Linux filesystem (including your current one)
+  into a LXD container on a remote LXD host.
+
+  It will setup a clean mount tree made of the root filesystem and any
+  additional mount you list, then transfer this through LXD's migration
+  API to create a new container from it.
+
+  The same set of options as ` + "`lxc launch`" + ` are also supported.
+`
+       cmd.RunE = c.Run
+       cmd.Flags().StringArrayVarP(&c.flagConfig, "config", "c", nil, 
"Configuration key and value to set on the container"+"``")
+       cmd.Flags().StringVarP(&c.flagNetwork, "network", "n", "", "Network to 
use for the container"+"``")
+       cmd.Flags().StringArrayVarP(&c.flagProfile, "profile", "p", nil, 
"Profile to apply to the container"+"``")
+       cmd.Flags().StringVarP(&c.flagStorage, "storage", "s", "", "Storage 
pool to use for the container"+"``")
+       cmd.Flags().StringVarP(&c.flagType, "type", "t", "", "Instance type to 
use for the container"+"``")
+       cmd.Flags().BoolVar(&c.flagNoProfiles, "no-profiles", false, "Create 
the container with no profiles applied")
+
+       c.cmd = cmd
+       return cmd
+}
+
 func (c *cmdMigrate) Run(cmd *cobra.Command, args []string) error {
        // Help and usage
        if len(args) == 0 {
diff --git a/lxd-p2c/main_netcat.go b/lxd-p2c/main_netcat.go
index 20350a27d..53814bd16 100644
--- a/lxd-p2c/main_netcat.go
+++ b/lxd-p2c/main_netcat.go
@@ -13,9 +13,22 @@ import (
 )
 
 type cmdNetcat struct {
+       cmd    *cobra.Command
        global *cmdGlobal
 }
 
+func (c *cmdNetcat) Command() *cobra.Command {
+       cmd := &cobra.Command{}
+
+       cmd.Use = "netcat <address>"
+       cmd.Short = "Sends stdin data to a unix socket"
+       cmd.RunE = c.Run
+       cmd.Hidden = true
+
+       c.cmd = cmd
+       return cmd
+}
+
 func (c *cmdNetcat) Run(cmd *cobra.Command, args []string) error {
        // Help and usage
        if len(args) == 0 {
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to