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

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) ===
Closes #43 

It seems bdev_specs are missing from the go binding ( in `go_lxc_create` ). It adds support for passing backing store options from Golang.
 
From 0f17eb8db8fefc6f0596f9d2a9076c3b2155ff6b Mon Sep 17 00:00:00 2001
From: dinesh <dinesh1...@gmail.com>
Date: Tue, 4 Aug 2020 17:30:00 +0530
Subject: [PATCH] support backing store options

---
 container.go              | 75 ++++++++++++++++++++++++++++++-----
 examples/create/create.go | 28 +++++++++++++
 lxc-binding.c             |  6 +--
 lxc-binding.h             |  2 +-
 options.go                | 19 +++++++++
 type.go                   | 82 ++++++++++++++++++++++++++++++++++++++-
 6 files changed, 197 insertions(+), 15 deletions(-)

diff --git a/container.go b/container.go
index 30c5ef6..0fe2440 100644
--- a/container.go
+++ b/container.go
@@ -407,17 +407,12 @@ func (c *Container) Create(options TemplateOptions) error 
{
        c.mu.Lock()
        defer c.mu.Unlock()
 
-       // FIXME: Support bdev_specs
-       //
-       // bdev_specs:
-       // zfs requires zfsroot
-       // lvm requires lvname/vgname/thinpool as well as fstype and fssize
-       // btrfs requires nothing
-       // dir requires nothing
        if err := c.makeSure(isNotDefined); err != nil {
                return err
        }
 
+       bdevspecs := buildBdevSpecs(options.BackendSpecs)
+
        // use download template if not set
        if options.Template == "" {
                options.Template = "download"
@@ -489,9 +484,9 @@ func (c *Container) Create(options TemplateOptions) error {
                }
                defer freeNullTerminatedArgs(cargs, len(args))
 
-               ret = bool(C.go_lxc_create(c.container, ctemplate, cbackend, 
C.int(c.verbosity), cargs))
+               ret = bool(C.go_lxc_create(c.container, ctemplate, cbackend, 
bdevspecs, C.int(c.verbosity), cargs))
        } else {
-               ret = bool(C.go_lxc_create(c.container, ctemplate, cbackend, 
C.int(c.verbosity), nil))
+               ret = bool(C.go_lxc_create(c.container, ctemplate, cbackend, 
bdevspecs, C.int(c.verbosity), nil))
        }
 
        if !ret {
@@ -1950,3 +1945,65 @@ func (c *Container) ErrorNum() int {
        cError := C.go_lxc_error_num(c.container)
        return int(cError)
 }
+
+func buildBdevSpecs(o *BackendStoreSpecs) *C.struct_bdev_specs {
+       if o == nil {
+               return nil
+       }
+
+       // bdev_specs:
+       // zfs requires zfsroot
+       // lvm requires lvname/vgname/thinpool as well as fstype and fssize
+       // btrfs requires nothing
+       // dir requires nothing
+
+       specs := C.struct_bdev_specs{}
+
+       if o.FSType != "" {
+               fstype := C.CString(o.FSType)
+               specs.fstype = fstype 
+               defer C.free(unsafe.Pointer(fstype))
+       }
+
+       if o.FSSize > 0  {
+               specs.fssize = C.uint64_t(o.FSSize)
+       }
+
+       if o.ZFS.Root != "" { 
+               zfsroot := C.CString(o.ZFS.Root)
+               specs.zfs.zfsroot = zfsroot
+               defer C.free(unsafe.Pointer(zfsroot))
+       }
+       
+       if o.LVM.VG != "" {
+               vg := C.CString(o.LVM.VG)
+               specs.lvm.vg = vg
+               defer C.free(unsafe.Pointer(vg))
+       }
+
+       if o.LVM.Thinpool != "" {
+               lv := C.CString(o.LVM.Thinpool)
+               specs.lvm.thinpool = lv
+               defer C.free(unsafe.Pointer(lv))
+       }
+
+       if o.RBD.Name != "" {
+               lv := C.CString(o.RBD.Name)
+               specs.rbd.rbdname = lv
+               defer C.free(unsafe.Pointer(lv))
+       }
+
+       if o.RBD.Pool != "" {
+               lv := C.CString(o.RBD.Pool)
+               specs.rbd.rbdpool = lv
+               defer C.free(unsafe.Pointer(lv))
+       }
+
+       if o.Dir != nil {
+               dir := C.CString(*o.Dir)
+               specs.dir = dir
+               defer C.free(unsafe.Pointer(dir))
+       }
+
+       return &specs
+}
\ No newline at end of file
diff --git a/examples/create/create.go b/examples/create/create.go
index 1e71d25..cd5cc75 100644
--- a/examples/create/create.go
+++ b/examples/create/create.go
@@ -23,6 +23,8 @@ var (
        verbose    bool
        flush      bool
        validation bool
+       fssize     string
+       bdevtype   string
 )
 
 func init() {
@@ -35,6 +37,11 @@ func init() {
        flag.BoolVar(&verbose, "verbose", false, "Verbose output")
        flag.BoolVar(&flush, "flush", false, "Flush the cache")
        flag.BoolVar(&validation, "validation", false, "GPG validation")
+
+       flag.StringVar(&bdevtype, "bdev", "dir", "backing store type")
+       flag.StringVar(&fssize, "fssize", "", "backing store size")
+       // TODO support more flags for zfs, lvm, or rbd
+
        flag.Parse()
 }
 
@@ -50,6 +57,20 @@ func main() {
                c.SetVerbosity(lxc.Verbose)
        }
 
+       var backend lxc.BackendStore
+       if err := (&backend).Set(bdevtype); err != nil {
+               log.Fatalf("ERROR: %s\n", err.Error())
+       }
+
+       var bdevSize lxc.ByteSize
+       if fssize != "" {
+               var err error
+               bdevSize, err = lxc.ParseBytes(fssize)
+               if err != nil {
+                       log.Fatalf("ERROR: %s\n", err.Error())
+               }
+       }
+
        options := lxc.TemplateOptions{
                Template:             template,
                Distro:               distro,
@@ -57,8 +78,15 @@ func main() {
                Arch:                 arch,
                FlushCache:           flush,
                DisableGPGValidation: validation,
+               Backend:              backend,
+               BackendSpecs: &lxc.BackendStoreSpecs{
+                       FSSize: uint64(bdevSize),
+               },
        }
 
+       c.SetLogFile("log")
+       c.SetLogLevel(lxc.DEBUG)
+
        if err := c.Create(options); err != nil {
                log.Printf("ERROR: %s\n", err.Error())
        }
diff --git a/lxc-binding.c b/lxc-binding.c
index 2c26162..ce21e15 100644
--- a/lxc-binding.c
+++ b/lxc-binding.c
@@ -75,11 +75,11 @@ bool go_lxc_want_close_all_fds(struct lxc_container *c, 
bool state) {
        return c->want_close_all_fds(c, state);
 }
 
-bool go_lxc_create(struct lxc_container *c, const char *t, const char 
*bdevtype, int flags, char * const argv[]) {
+bool go_lxc_create(struct lxc_container *c, const char *t, const char 
*bdevtype, struct bdev_specs *specs, int flags, char * const argv[]) {
        if (strncmp(t, "none", strlen(t)) == 0) {
-               return c->create(c, NULL, bdevtype, NULL, !!(flags & 
LXC_CREATE_QUIET), argv);
+               return c->create(c, NULL, bdevtype, specs, !!(flags & 
LXC_CREATE_QUIET), argv);
        }
-       return c->create(c, t, bdevtype, NULL, !!(flags & LXC_CREATE_QUIET), 
argv);
+       return c->create(c, t, bdevtype, specs, !!(flags & LXC_CREATE_QUIET), 
argv);
 }
 
 bool go_lxc_start(struct lxc_container *c, int useinit, char * const argv[]) {
diff --git a/lxc-binding.h b/lxc-binding.h
index b52e2cd..8f7f427 100644
--- a/lxc-binding.h
+++ b/lxc-binding.h
@@ -12,7 +12,7 @@ extern void go_lxc_clear_config(struct lxc_container *c);
 extern bool go_lxc_clear_config_item(struct lxc_container *c, const char *key);
 extern bool go_lxc_clone(struct lxc_container *c, const char *newname, const 
char *lxcpath, int flags, const char *bdevtype);
 extern bool go_lxc_console(struct lxc_container *c, int ttynum, int stdinfd, 
int stdoutfd, int stderrfd, int escape);
-extern bool go_lxc_create(struct lxc_container *c, const char *t, const char 
*bdevtype, int flags, char * const argv[]);
+extern bool go_lxc_create(struct lxc_container *c, const char *t, const char 
*bdevtype, struct bdev_specs *specs, int flags, char * const argv[]);
 extern bool go_lxc_defined(struct lxc_container *c);
 extern bool go_lxc_destroy(struct lxc_container *c);
 extern bool go_lxc_destroy_with_snapshots(struct lxc_container *c);
diff --git a/options.go b/options.go
index ae6b6fd..060abd5 100644
--- a/options.go
+++ b/options.go
@@ -71,6 +71,8 @@ type TemplateOptions struct {
        // Backend specifies the type of the backend.
        Backend BackendStore
 
+       BackendSpecs *BackendStoreSpecs
+
        // Distro specifies the name of the distribution.
        Distro string
 
@@ -105,6 +107,23 @@ type TemplateOptions struct {
        ExtraArgs []string
 }
 
+
+type BackendStoreSpecs struct {
+       FSType string
+       FSSize uint64
+       Dir *string
+       ZFS struct {
+               Root string
+       }
+       LVM struct {
+               VG, LV, Thinpool string
+       }
+       RBD struct {
+               Name, Pool string
+       }
+}
+
+
 // DownloadTemplateOptions is a convenient set of options for "download" 
template.
 var DownloadTemplateOptions = TemplateOptions{
        Template: "download",
diff --git a/type.go b/type.go
index ced3c33..c966531 100644
--- a/type.go
+++ b/type.go
@@ -9,7 +9,13 @@ package lxc
 // #include <lxc/lxccontainer.h>
 import "C"
 
-import "fmt"
+import (
+       "errors"
+       "fmt"
+       "strconv"
+       "strings"
+       "unicode"
+)
 
 // Verbosity type
 type Verbosity int
@@ -150,7 +156,7 @@ func (t State) String() string {
 type ByteSize float64
 
 const (
-       _ = iota
+       B = iota
        // KB - kilobyte
        KB ByteSize = 1 << (10 * iota)
        // MB - megabyte
@@ -191,6 +197,78 @@ func (b ByteSize) String() string {
        return fmt.Sprintf("%.2fB", b)
 }
 
+// Used to convert user input to ByteSize
+var unitMap = map[string]ByteSize{
+       "B":     B,
+       "BYTE":  B,
+       "BYTES": B,
+
+       "KB":        KB,
+       "KILOBYTE":  KB,
+       "KILOBYTES": KB,
+
+       "MB":        MB,
+       "MEGABYTE":  MB,
+       "MEGABYTES": MB,
+
+       "GB":        GB,
+       "GIGABYTE":  GB,
+       "GIGABYTES": GB,
+
+       "TB":        TB,
+       "TERABYTE":  TB,
+       "TERABYTES": TB,
+
+       "PB":        PB,
+       "PETABYTE":  PB,
+       "PETABYTES": PB,
+
+       "EB":       EB,
+       "EXABYTE":  EB,
+       "EXABYTES": EB,
+}
+
+// Inspired from https://github.com/inhies/go-bytesize
+
+// ParseBytes parses a byte size string. A byte size string is a number 
followed by
+// a unit suffix, such as "1024B" or "1 MB". Valid byte units are "B", "KB",
+// "MB", "GB", "TB", "PB" and "EB". You can also use the long
+// format of units, such as "kilobyte" or "kilobytes".
+func ParseBytes(s string) (ByteSize, error) {
+       // Remove leading and trailing whitespace
+       s = strings.TrimSpace(s)
+
+       split := make([]string, 0)
+       for i, r := range s {
+               if !unicode.IsDigit(r) {
+                       // Split the string by digit and size designator, 
remove whitespace
+                       split = append(split, strings.TrimSpace(string(s[:i])))
+                       split = append(split, strings.TrimSpace(string(s[i:])))
+                       break
+               }
+       }
+
+       // Check to see if we split successfully
+       if len(split) != 2 {
+               return 0, errors.New("Unrecognized size suffix")
+       }
+
+       // Check for MB, MEGABYTE, and MEGABYTES
+       unit, ok := unitMap[strings.ToUpper(split[1])]
+       if !ok {
+               return 0, errors.New("Unrecognized size suffix " + split[1])
+
+       }
+
+       value, err := strconv.ParseFloat(split[0], 64)
+       if err != nil {
+               return 0, err
+       }
+
+       bytesize := ByteSize(value * float64(unit))
+       return bytesize, nil
+}
+
 // LogLevel type specifies possible log levels.
 type LogLevel int
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to