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