[lxc-devel] [go-lxc/v2] Support backing store options
dinesh on Github
lxc-bot at linuxcontainers.org
Tue Aug 4 12:05:18 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 459 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200804/fea4d11b/attachment.bin>
-------------- next part --------------
From 0f17eb8db8fefc6f0596f9d2a9076c3b2155ff6b Mon Sep 17 00:00:00 2001
From: dinesh <dinesh1042 at 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
More information about the lxc-devel
mailing list