mirror of
https://github.com/lxc/go-lxc.git
synced 2026-02-05 06:46:38 +01:00
[major] make API more idiomatic, make go vet and golint happy and modify examples accordingly
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
examples/clone
|
||||
examples/concurrent_create
|
||||
examples/concurrent_destroy
|
||||
examples/concurrent_shutdown
|
||||
|
||||
9
Makefile
9
Makefile
@@ -1,6 +1,11 @@
|
||||
all: format vet lint
|
||||
format:
|
||||
@gofmt -s -w *.go
|
||||
test:
|
||||
@sudo `which go` test -v
|
||||
docs:
|
||||
@`which godoc` github.com/caglar10ur/lxc
|
||||
doc:
|
||||
@`which godoc` github.com/caglar10ur/lxc | less
|
||||
vet:
|
||||
`which vet` .
|
||||
lint:
|
||||
`which golint` .
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* backendstore.go: Go bindings for lxc
|
||||
*
|
||||
* Copyright © 2013, S.Çağlar Onur
|
||||
*
|
||||
* Authors:
|
||||
* S.Çağlar Onur <caglar@10ur.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package lxc
|
||||
|
||||
type BackendStore int
|
||||
|
||||
const (
|
||||
BTRFS BackendStore = iota
|
||||
DIRECTORY
|
||||
LVM
|
||||
ZFS
|
||||
OVERLAYFS
|
||||
LOOPBACK
|
||||
)
|
||||
|
||||
// BackendStore as string
|
||||
func (t BackendStore) String() string {
|
||||
switch t {
|
||||
case DIRECTORY:
|
||||
return "Directory"
|
||||
case ZFS:
|
||||
return "ZFS"
|
||||
case BTRFS:
|
||||
return "BtrFS"
|
||||
case LVM:
|
||||
return "LVM"
|
||||
case OVERLAYFS:
|
||||
return "OverlayFS"
|
||||
case LOOPBACK:
|
||||
return "Loopback"
|
||||
}
|
||||
return "<INVALID>"
|
||||
}
|
||||
48
bytesize.go
48
bytesize.go
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* bytesize.go: Go bindings for lxc
|
||||
*
|
||||
* Taken from http://golang.org/doc/effective_go.html#constants
|
||||
*
|
||||
*/
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ByteSize float64
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
KB ByteSize = 1 << (10 * iota)
|
||||
MB
|
||||
GB
|
||||
TB
|
||||
PB
|
||||
EB
|
||||
ZB
|
||||
YB
|
||||
)
|
||||
|
||||
func (b ByteSize) String() string {
|
||||
switch {
|
||||
case b >= YB:
|
||||
return fmt.Sprintf("%.2fYB", b/YB)
|
||||
case b >= ZB:
|
||||
return fmt.Sprintf("%.2fZB", b/ZB)
|
||||
case b >= EB:
|
||||
return fmt.Sprintf("%.2fEB", b/EB)
|
||||
case b >= PB:
|
||||
return fmt.Sprintf("%.2fPB", b/PB)
|
||||
case b >= TB:
|
||||
return fmt.Sprintf("%.2fTB", b/TB)
|
||||
case b >= GB:
|
||||
return fmt.Sprintf("%.2fGB", b/GB)
|
||||
case b >= MB:
|
||||
return fmt.Sprintf("%.2fMB", b/MB)
|
||||
case b >= KB:
|
||||
return fmt.Sprintf("%.2fKB", b/KB)
|
||||
}
|
||||
return fmt.Sprintf("%.2fB", b)
|
||||
}
|
||||
621
container.go
621
container.go
@@ -29,6 +29,7 @@ package lxc
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -36,395 +37,645 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
network_key = "lxc.network"
|
||||
)
|
||||
|
||||
// Container struct
|
||||
type Container struct {
|
||||
container *C.struct_lxc_container
|
||||
verbosity Verbosity
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// Returns container's name
|
||||
// Name returns container's name
|
||||
func (lxc *Container) Name() string {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return C.GoString(lxc.container.name)
|
||||
}
|
||||
|
||||
// Returns whether the container is already defined or not
|
||||
// Defined returns whether the container is already defined or not
|
||||
func (lxc *Container) Defined() bool {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return bool(C.lxc_container_defined(lxc.container))
|
||||
}
|
||||
|
||||
// Returns whether the container is already running or not
|
||||
// Running returns whether the container is already running or not
|
||||
func (lxc *Container) Running() bool {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return bool(C.lxc_container_running(lxc.container))
|
||||
}
|
||||
|
||||
// Returns the container's state
|
||||
// State returns the container's state
|
||||
func (lxc *Container) State() State {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return stateMap[C.GoString(C.lxc_container_state(lxc.container))]
|
||||
}
|
||||
|
||||
// Returns the container's PID
|
||||
// InitPID returns the container's PID
|
||||
func (lxc *Container) InitPID() int {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return int(C.lxc_container_init_pid(lxc.container))
|
||||
}
|
||||
|
||||
// Returns whether the daemonize flag is set
|
||||
// Daemonize returns whether the daemonize flag is set
|
||||
func (lxc *Container) Daemonize() bool {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return bool(lxc.container.daemonize != 0)
|
||||
}
|
||||
|
||||
// Sets the daemonize flag
|
||||
// SetDaemonize sets the daemonize flag
|
||||
func (lxc *Container) SetDaemonize() {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
C.lxc_container_want_daemonize(lxc.container)
|
||||
}
|
||||
|
||||
// Freezes the running container
|
||||
func (lxc *Container) Freeze() bool {
|
||||
// SetVerbosity sets the verbosity level of some API calls
|
||||
func (lxc *Container) SetVerbosity(verbosity Verbosity) {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
return bool(C.lxc_container_freeze(lxc.container))
|
||||
|
||||
lxc.verbosity = verbosity
|
||||
}
|
||||
|
||||
// Unfreezes the frozen container
|
||||
func (lxc *Container) Unfreeze() bool {
|
||||
// Freeze freezes the running container
|
||||
func (lxc *Container) Freeze() error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
if lxc.State() == FROZEN {
|
||||
return fmt.Errorf("container %q is already frozen", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
return bool(C.lxc_container_unfreeze(lxc.container))
|
||||
|
||||
if !bool(C.lxc_container_freeze(lxc.container)) {
|
||||
return fmt.Errorf("freezing the container %q failed", lxc.Name())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates the container using given template and arguments
|
||||
func (lxc *Container) Create(template string, args ...string) bool {
|
||||
// Unfreeze unfreezes the frozen container
|
||||
func (lxc *Container) Unfreeze() error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
if lxc.State() != FROZEN {
|
||||
return fmt.Errorf("container %q is not frozen", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
if !bool(C.lxc_container_unfreeze(lxc.container)) {
|
||||
return fmt.Errorf("unfreezing the container %q failed", lxc.Name())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create creates the container using given template and arguments
|
||||
func (lxc *Container) Create(template string, args ...string) error {
|
||||
if lxc.Defined() {
|
||||
return fmt.Errorf("container %q is already defined", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
ctemplate := C.CString(template)
|
||||
defer C.free(unsafe.Pointer(ctemplate))
|
||||
|
||||
ret := false
|
||||
if args != nil {
|
||||
cargs := makeArgs(args)
|
||||
defer freeArgs(cargs)
|
||||
return bool(C.lxc_container_create(lxc.container, ctemplate, &cargs[0]))
|
||||
|
||||
ret = bool(C.lxc_container_create(lxc.container, ctemplate, C.int(lxc.verbosity), &cargs[0]))
|
||||
} else {
|
||||
ret = bool(C.lxc_container_create(lxc.container, ctemplate, C.int(lxc.verbosity), nil))
|
||||
}
|
||||
return bool(C.lxc_container_create(lxc.container, ctemplate, nil))
|
||||
|
||||
if !ret {
|
||||
return fmt.Errorf("creating the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Starts the container
|
||||
func (lxc *Container) Start(useinit bool, args ...string) bool {
|
||||
// Start starts the container
|
||||
func (lxc *Container) Start(useinit bool, args ...string) error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if lxc.Running() {
|
||||
return fmt.Errorf("container %q is already running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
ret := false
|
||||
|
||||
cuseinit := 0
|
||||
if useinit {
|
||||
cuseinit = 1
|
||||
}
|
||||
|
||||
if args != nil {
|
||||
cargs := makeArgs(args)
|
||||
defer freeArgs(cargs)
|
||||
return bool(C.lxc_container_start(lxc.container, C.int(cuseinit), &cargs[0]))
|
||||
|
||||
ret = bool(C.lxc_container_start(lxc.container, C.int(cuseinit), &cargs[0]))
|
||||
} else {
|
||||
ret = bool(C.lxc_container_start(lxc.container, C.int(cuseinit), nil))
|
||||
}
|
||||
return bool(C.lxc_container_start(lxc.container, C.int(cuseinit), nil))
|
||||
|
||||
if !ret {
|
||||
return fmt.Errorf("starting the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stops the container
|
||||
func (lxc *Container) Stop() bool {
|
||||
// Stop stops the container
|
||||
func (lxc *Container) Stop() error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return fmt.Errorf("container %q is already stoped", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
return bool(C.lxc_container_stop(lxc.container))
|
||||
|
||||
if !bool(C.lxc_container_stop(lxc.container)) {
|
||||
return fmt.Errorf("stoping the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reboots the container
|
||||
func (lxc *Container) Reboot() bool {
|
||||
// Reboot reboots the container
|
||||
func (lxc *Container) Reboot() error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
return bool(C.lxc_container_reboot(lxc.container))
|
||||
|
||||
if !bool(C.lxc_container_reboot(lxc.container)) {
|
||||
return fmt.Errorf("rebooting the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdowns the container
|
||||
func (lxc *Container) Shutdown(timeout int) bool {
|
||||
// Shutdown shutdowns the container
|
||||
func (lxc *Container) Shutdown(timeout int) error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
return bool(C.lxc_container_shutdown(lxc.container, C.int(timeout)))
|
||||
|
||||
if !bool(C.lxc_container_shutdown(lxc.container, C.int(timeout))) {
|
||||
return fmt.Errorf("shutting down the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroys the container
|
||||
func (lxc *Container) Destroy() bool {
|
||||
// Destroy destroys the container
|
||||
func (lxc *Container) Destroy() error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if lxc.Running() {
|
||||
return fmt.Errorf("container %q is running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
return bool(C.lxc_container_destroy(lxc.container))
|
||||
|
||||
if !bool(C.lxc_container_destroy(lxc.container)) {
|
||||
return fmt.Errorf("destroying the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: consider other parameters
|
||||
// FIXME: Clone or CloneToOverlayFS, CloneToLVM, SnapshotToLVM etc?
|
||||
func (lxc *Container) Clone(name string, backend BackendStore) bool {
|
||||
// Clone clones the container
|
||||
func (lxc *Container) Clone(name string, flags int, backend BackendStore) error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if lxc.Running() {
|
||||
return fmt.Errorf("container %q is running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
if backend == OVERLAYFS {
|
||||
return bool(C.lxc_container_clone(lxc.container, cname, C.int(CLONE_SNAPSHOT), C.CString("overlayfs")))
|
||||
} else {
|
||||
return bool(C.lxc_container_clone(lxc.container, cname, 0, nil))
|
||||
if !bool(C.lxc_container_clone(lxc.container, cname, C.int(flags), C.CString(backend.String()))) {
|
||||
return fmt.Errorf("cloning the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lxc *Container) CloneToOverlayFS(name string) bool {
|
||||
return lxc.Clone(name, OVERLAYFS)
|
||||
// CloneToDirectory clones the container using Directory backendstore
|
||||
func (lxc *Container) CloneToDirectory(name string) error {
|
||||
return lxc.Clone(name, 0, Directory)
|
||||
}
|
||||
|
||||
// Waits till the container changes its state or timeouts
|
||||
// CloneToOverlayFS clones the container using OverlayFS backendstore
|
||||
func (lxc *Container) CloneToOverlayFS(name string) error {
|
||||
return lxc.Clone(name, CloneSnapshot, OverlayFS)
|
||||
}
|
||||
|
||||
// Wait waits till the container changes its state or timeouts
|
||||
func (lxc *Container) Wait(state State, timeout int) bool {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
cstate := C.CString(state.String())
|
||||
defer C.free(unsafe.Pointer(cstate))
|
||||
|
||||
return bool(C.lxc_container_wait(lxc.container, cstate, C.int(timeout)))
|
||||
}
|
||||
|
||||
// Returns the container's configuration file's name
|
||||
// ConfigFileName returns the container's configuration file's name
|
||||
func (lxc *Container) ConfigFileName() string {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return C.GoString(C.lxc_container_config_file_name(lxc.container))
|
||||
}
|
||||
|
||||
// Returns the value of the given key
|
||||
// ConfigItem returns the value of the given key
|
||||
func (lxc *Container) ConfigItem(key string) []string {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
ckey := C.CString(key)
|
||||
defer C.free(unsafe.Pointer(ckey))
|
||||
|
||||
ret := strings.TrimSpace(C.GoString(C.lxc_container_get_config_item(lxc.container, ckey)))
|
||||
return strings.Split(ret, "\n")
|
||||
}
|
||||
|
||||
// Sets the value of given key
|
||||
func (lxc *Container) SetConfigItem(key string, value string) bool {
|
||||
// SetConfigItem sets the value of given key
|
||||
func (lxc *Container) SetConfigItem(key string, value string) error {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
ckey := C.CString(key)
|
||||
defer C.free(unsafe.Pointer(ckey))
|
||||
|
||||
cvalue := C.CString(value)
|
||||
defer C.free(unsafe.Pointer(cvalue))
|
||||
return bool(C.lxc_container_set_config_item(lxc.container, ckey, cvalue))
|
||||
|
||||
if !bool(C.lxc_container_set_config_item(lxc.container, ckey, cvalue)) {
|
||||
return fmt.Errorf("setting config item for the container %q failed (key: %s, value: %s)", lxc.Name(), key, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the value of the given key
|
||||
// CgroupItem returns the value of the given key
|
||||
func (lxc *Container) CgroupItem(key string) []string {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
ckey := C.CString(key)
|
||||
defer C.free(unsafe.Pointer(ckey))
|
||||
|
||||
ret := strings.TrimSpace(C.GoString(C.lxc_container_get_cgroup_item(lxc.container, ckey)))
|
||||
return strings.Split(ret, "\n")
|
||||
}
|
||||
|
||||
// Sets the value of given key
|
||||
func (lxc *Container) SetCgroupItem(key string, value string) bool {
|
||||
// SetCgroupItem sets the value of given key
|
||||
func (lxc *Container) SetCgroupItem(key string, value string) error {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
ckey := C.CString(key)
|
||||
defer C.free(unsafe.Pointer(ckey))
|
||||
|
||||
cvalue := C.CString(value)
|
||||
defer C.free(unsafe.Pointer(cvalue))
|
||||
return bool(C.lxc_container_set_cgroup_item(lxc.container, ckey, cvalue))
|
||||
|
||||
if !bool(C.lxc_container_set_cgroup_item(lxc.container, ckey, cvalue)) {
|
||||
return fmt.Errorf("setting cgroup item for the container %q failed (key: %s, value: %s)", lxc.Name(), key, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clears the value of given key
|
||||
func (lxc *Container) ClearConfigItem(key string) bool {
|
||||
// ClearConfigItem clears the value of given key
|
||||
func (lxc *Container) ClearConfigItem(key string) error {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
ckey := C.CString(key)
|
||||
defer C.free(unsafe.Pointer(ckey))
|
||||
return bool(C.lxc_container_clear_config_item(lxc.container, ckey))
|
||||
|
||||
if !bool(C.lxc_container_clear_config_item(lxc.container, ckey)) {
|
||||
return fmt.Errorf("clearing cgroup item for the container %q failed (key: %s)", lxc.Name(), key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the keys
|
||||
// Keys returns the keys
|
||||
func (lxc *Container) Keys(key string) []string {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
ckey := C.CString(key)
|
||||
defer C.free(unsafe.Pointer(ckey))
|
||||
|
||||
ret := strings.TrimSpace(C.GoString(C.lxc_container_get_keys(lxc.container, ckey)))
|
||||
return strings.Split(ret, "\n")
|
||||
}
|
||||
|
||||
// Loads the configuration file from given path
|
||||
func (lxc *Container) LoadConfigFile(path string) bool {
|
||||
// LoadConfigFile loads the configuration file from given path
|
||||
func (lxc *Container) LoadConfigFile(path string) error {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
return bool(C.lxc_container_load_config(lxc.container, cpath))
|
||||
|
||||
if !bool(C.lxc_container_load_config(lxc.container, cpath)) {
|
||||
return fmt.Errorf("loading config file for the container %q failed (path: %s)", lxc.Name(), path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Saves the configuration file to given path
|
||||
func (lxc *Container) SaveConfigFile(path string) bool {
|
||||
// SaveConfigFile saves the configuration file to given path
|
||||
func (lxc *Container) SaveConfigFile(path string) error {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
return bool(C.lxc_container_save_config(lxc.container, cpath))
|
||||
|
||||
if !bool(C.lxc_container_save_config(lxc.container, cpath)) {
|
||||
return fmt.Errorf("saving config file for the container %q failed (path: %s)", lxc.Name(), path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the configuration file's path
|
||||
// ConfigPath returns the configuration file's path
|
||||
func (lxc *Container) ConfigPath() string {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
return C.GoString(C.lxc_container_get_config_path(lxc.container))
|
||||
}
|
||||
|
||||
// Sets the configuration file's path
|
||||
func (lxc *Container) SetConfigPath(path string) bool {
|
||||
// SetConfigPath sets the configuration file's path
|
||||
func (lxc *Container) SetConfigPath(path string) error {
|
||||
lxc.Lock()
|
||||
defer lxc.Unlock()
|
||||
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
return bool(C.lxc_container_set_config_path(lxc.container, cpath))
|
||||
|
||||
if !bool(C.lxc_container_set_config_path(lxc.container, cpath)) {
|
||||
return fmt.Errorf("setting config file for the container %q failed (path: %s)", lxc.Name(), path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NumberOfNetworkInterfaces returns the number of network interfaces
|
||||
func (lxc *Container) NumberOfNetworkInterfaces() int {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
return len(lxc.ConfigItem(network_key))
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
// Unreachable code but required for compatibility with Go 1.0.3 see -- https://groups.google.com/d/msg/golang-nuts/OXcMGoGYSLg/nfH_zvhnBHsJ
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (lxc *Container) MemoryUsageInBytes() (ByteSize, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
memUsed, err := strconv.ParseFloat(lxc.CgroupItem("memory.usage_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(memUsed), err
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (lxc *Container) SwapUsageInBytes() (ByteSize, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
swapUsed, err := strconv.ParseFloat(lxc.CgroupItem("memory.memsw.usage_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(swapUsed), err
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (lxc *Container) MemoryLimitInBytes() (ByteSize, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
memLimit, err := strconv.ParseFloat(lxc.CgroupItem("memory.limit_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(memLimit), err
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (lxc *Container) SwapLimitInBytes() (ByteSize, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
swapLimit, err := strconv.ParseFloat(lxc.CgroupItem("memory.memsw.limit_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(swapLimit), err
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// Returns the total CPU time (in nanoseconds) consumed by all tasks in this cgroup (including tasks lower in the hierarchy).
|
||||
func (lxc *Container) CPUTime() (time.Duration, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
cpuUsage, err := strconv.ParseInt(lxc.CgroupItem("cpuacct.usage")[0], 10, 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return time.Duration(cpuUsage), err
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// Returns the CPU time (in nanoseconds) consumed on each CPU by all tasks in this cgroup (including tasks lower in the hierarchy).
|
||||
func (lxc *Container) CPUTimePerCPU() ([]time.Duration, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
var cpuTimes []time.Duration
|
||||
|
||||
if lxc.Running() {
|
||||
for _, v := range strings.Split(lxc.CgroupItem("cpuacct.usage_percpu")[0], " ") {
|
||||
cpuUsage, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuTimes = append(cpuTimes, time.Duration(cpuUsage))
|
||||
}
|
||||
return cpuTimes, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Returns the number of CPU cycles (in the units defined by USER_HZ on the system) consumed by tasks in this cgroup and its children in both user mode and system (kernel) mode.
|
||||
func (lxc *Container) CPUStats() ([]int64, error) {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
if lxc.Running() {
|
||||
cpuStat := lxc.CgroupItem("cpuacct.stat")
|
||||
user, _ := strconv.ParseInt(strings.Split(cpuStat[0], " ")[1], 10, 64)
|
||||
system, _ := strconv.ParseInt(strings.Split(cpuStat[1], " ")[1], 10, 64)
|
||||
return []int64{user, system}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (lxc *Container) ConsoleGetFD(ttynum int) int {
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
if lxc.Running() {
|
||||
return int(C.lxc_container_console_getfd(lxc.container, C.int(ttynum)))
|
||||
return len(lxc.ConfigItem("lxc.network"))
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (lxc *Container) Console(ttynum, stdinfd, stdoutfd, stderrfd, escape int) bool {
|
||||
// MemoryUsageInBytes returns memory usage in bytes
|
||||
func (lxc *Container) MemoryUsageInBytes() (ByteSize, error) {
|
||||
if !lxc.Defined() {
|
||||
return -1, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return -1, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
if lxc.Running() {
|
||||
return bool(C.lxc_container_console(lxc.container, C.int(ttynum), C.int(stdinfd), C.int(stdoutfd), C.int(stderrfd), C.int(escape)))
|
||||
memUsed, err := strconv.ParseFloat(lxc.CgroupItem("memory.usage_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return false
|
||||
return ByteSize(memUsed), err
|
||||
}
|
||||
|
||||
// SwapUsageInBytes returns swap usage in bytes
|
||||
func (lxc *Container) SwapUsageInBytes() (ByteSize, error) {
|
||||
if !lxc.Defined() {
|
||||
return -1, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return -1, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
swapUsed, err := strconv.ParseFloat(lxc.CgroupItem("memory.memsw.usage_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(swapUsed), err
|
||||
}
|
||||
|
||||
// MemoryLimitInBytes returns memory limit in bytes
|
||||
func (lxc *Container) MemoryLimitInBytes() (ByteSize, error) {
|
||||
if !lxc.Defined() {
|
||||
return -1, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return -1, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
memLimit, err := strconv.ParseFloat(lxc.CgroupItem("memory.limit_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(memLimit), err
|
||||
}
|
||||
|
||||
// SwapLimitInBytes returns the swap limit in bytes
|
||||
func (lxc *Container) SwapLimitInBytes() (ByteSize, error) {
|
||||
if !lxc.Defined() {
|
||||
return -1, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return -1, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
swapLimit, err := strconv.ParseFloat(lxc.CgroupItem("memory.memsw.limit_in_bytes")[0], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ByteSize(swapLimit), err
|
||||
}
|
||||
|
||||
// CPUTime returns the total CPU time (in nanoseconds) consumed by all tasks in this cgroup (including tasks lower in the hierarchy).
|
||||
func (lxc *Container) CPUTime() (time.Duration, error) {
|
||||
if !lxc.Defined() {
|
||||
return -1, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return -1, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
cpuUsage, err := strconv.ParseInt(lxc.CgroupItem("cpuacct.usage")[0], 10, 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return time.Duration(cpuUsage), err
|
||||
}
|
||||
|
||||
// CPUTimePerCPU returns the CPU time (in nanoseconds) consumed on each CPU by all tasks in this cgroup (including tasks lower in the hierarchy).
|
||||
func (lxc *Container) CPUTimePerCPU() ([]time.Duration, error) {
|
||||
if !lxc.Defined() {
|
||||
return nil, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return nil, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
var cpuTimes []time.Duration
|
||||
|
||||
for _, v := range strings.Split(lxc.CgroupItem("cpuacct.usage_percpu")[0], " ") {
|
||||
cpuUsage, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpuTimes = append(cpuTimes, time.Duration(cpuUsage))
|
||||
}
|
||||
return cpuTimes, nil
|
||||
}
|
||||
|
||||
// CPUStats returns the number of CPU cycles (in the units defined by USER_HZ on the system) consumed by tasks in this cgroup and its children in both user mode and system (kernel) mode.
|
||||
func (lxc *Container) CPUStats() ([]int64, error) {
|
||||
if !lxc.Defined() {
|
||||
return nil, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return nil, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
cpuStat := lxc.CgroupItem("cpuacct.stat")
|
||||
user, err := strconv.ParseInt(strings.Split(cpuStat[0], " ")[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
system, err := strconv.ParseInt(strings.Split(cpuStat[1], " ")[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []int64{user, system}, nil
|
||||
}
|
||||
|
||||
// ConsoleGetFD allocates a console tty from container
|
||||
func (lxc *Container) ConsoleGetFD(ttynum int) (int, error) {
|
||||
if !lxc.Defined() {
|
||||
return -1, fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return -1, fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
ret := int(C.lxc_container_console_getfd(lxc.container, C.int(ttynum)))
|
||||
if ret < 0 {
|
||||
return -1, fmt.Errorf("allocating a console tty container %q failed", lxc.Name())
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Console allocates and runs a console tty from container
|
||||
func (lxc *Container) Console(ttynum, stdinfd, stdoutfd, stderrfd, escape int) error {
|
||||
if !lxc.Defined() {
|
||||
return fmt.Errorf("there is no container named %q", lxc.Name())
|
||||
}
|
||||
|
||||
if !lxc.Running() {
|
||||
return fmt.Errorf("container %q is not running", lxc.Name())
|
||||
}
|
||||
|
||||
lxc.RLock()
|
||||
defer lxc.RUnlock()
|
||||
|
||||
if !bool(C.lxc_container_console(lxc.container, C.int(ttynum), C.int(stdinfd), C.int(stdoutfd), C.int(stderrfd), C.int(escape))) {
|
||||
return fmt.Errorf("allocating a console for the container %q failed", lxc.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
56
examples/clone.go
Normal file
56
examples/clone.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* clone.go
|
||||
*
|
||||
* Copyright © 2013, S.Çağlar Onur
|
||||
*
|
||||
* Authors:
|
||||
* S.Çağlar Onur <caglar@10ur.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/caglar10ur/lxc"
|
||||
)
|
||||
|
||||
var (
|
||||
name string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&name, "name", "rubik", "Name of the original container")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
directoryClone := name + "Directory"
|
||||
overlayClone := name + "OverlayFS"
|
||||
|
||||
fmt.Printf("Cloning the container using Directory backend...\n")
|
||||
if err := c.CloneToDirectory(directoryClone); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
|
||||
fmt.Printf("Cloning the container using OverlayFS backend...\n")
|
||||
if err := c.CloneToOverlayFS(overlayClone); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -40,12 +40,12 @@ func main() {
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
z := lxc.NewContainer(strconv.Itoa(i))
|
||||
defer lxc.PutContainer(z)
|
||||
c := lxc.NewContainer(strconv.Itoa(i))
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
fmt.Printf("Creating the container (%d)...\n", i)
|
||||
if !z.Create("ubuntu", "amd64", "quantal") {
|
||||
fmt.Printf("Creating the container (%d) failed...\n", i)
|
||||
if err := c.Create("ubuntu", "amd64", "quantal"); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
@@ -44,8 +44,8 @@ func main() {
|
||||
defer lxc.PutContainer(z)
|
||||
|
||||
fmt.Printf("Destroying the container (%d)...\n", i)
|
||||
if !z.Destroy() {
|
||||
fmt.Printf("Destroying the container (%d) failed...\n", i)
|
||||
if err := z.Destroy(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
@@ -43,11 +43,9 @@ func main() {
|
||||
z := lxc.NewContainer(strconv.Itoa(i))
|
||||
defer lxc.PutContainer(z)
|
||||
|
||||
if z.Defined() && z.Running() {
|
||||
fmt.Printf("Shutting down the container (%d)...\n", i)
|
||||
if !z.Shutdown(30) {
|
||||
fmt.Printf("Shutting down the container (%d) failed...\n", i)
|
||||
}
|
||||
fmt.Printf("Shutting down the container (%d)...\n", i)
|
||||
if err := z.Shutdown(30); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
@@ -43,12 +43,10 @@ func main() {
|
||||
z := lxc.NewContainer(strconv.Itoa(i))
|
||||
defer lxc.PutContainer(z)
|
||||
|
||||
if z.Defined() && !z.Running() {
|
||||
z.SetDaemonize()
|
||||
fmt.Printf("Starting the container (%d)...\n", i)
|
||||
if !z.Start(false) {
|
||||
fmt.Printf("Starting the container (%d) failed...\n", i)
|
||||
}
|
||||
z.SetDaemonize()
|
||||
fmt.Printf("Starting the container (%d)...\n", i)
|
||||
if err := z.Start(false); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
@@ -43,11 +43,10 @@ func main() {
|
||||
z := lxc.NewContainer(strconv.Itoa(i))
|
||||
defer lxc.PutContainer(z)
|
||||
|
||||
if z.Defined() && z.Running() {
|
||||
fmt.Printf("Stopping the container (%d)...\n", i)
|
||||
if !z.Stop() {
|
||||
fmt.Printf("Stopping the container (%d) failed...\n", i)
|
||||
}
|
||||
z.SetDaemonize()
|
||||
fmt.Printf("Stoping the container (%d)...\n", i)
|
||||
if err := z.Stop(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
@@ -44,28 +44,28 @@ func main() {
|
||||
go func(i int) {
|
||||
name := strconv.Itoa(rand.Intn(10))
|
||||
|
||||
z := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(z)
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
// sleep for a while to simulate some dummy work
|
||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))
|
||||
|
||||
if z.Defined() {
|
||||
if !z.Running() {
|
||||
z.SetDaemonize()
|
||||
// fmt.Printf("Starting the container (%s)...\n", name)
|
||||
if !z.Start(false) {
|
||||
fmt.Printf("Starting the container (%s) failed...\n", name)
|
||||
if c.Defined() {
|
||||
if !c.Running() {
|
||||
c.SetDaemonize()
|
||||
fmt.Printf("Starting the container (%s)...\n", name)
|
||||
if err := c.Start(false); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
} else {
|
||||
// fmt.Printf("Stopping the container (%s)...\n", name)
|
||||
if !z.Stop() {
|
||||
fmt.Printf("Stopping the container (%s) failed...\n", name)
|
||||
fmt.Printf("Stopping the container (%s)...\n", name)
|
||||
if err := c.Stop(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !z.Create("ubuntu", "amd64", "quantal") {
|
||||
fmt.Printf("Creating the container (%s) failed...\n", name)
|
||||
if err := c.Create("ubuntu", "amd64", "quantal"); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
|
||||
@@ -41,14 +41,8 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
if c.Running() {
|
||||
fmt.Printf("Attaching to container's console...\n")
|
||||
c.Console(-1, 0, 1, 2, 1)
|
||||
} else {
|
||||
fmt.Printf("Container is not running...\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Attaching to container's console...\n")
|
||||
if err := c.Console(-1, 0, 1, 2, 1); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,9 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if !c.Defined() {
|
||||
fmt.Printf("Creating container...\n")
|
||||
c.Create("ubuntu", "amd64", "quantal")
|
||||
} else {
|
||||
fmt.Printf("Container is already created...\n")
|
||||
fmt.Printf("Creating container...\n")
|
||||
c.SetVerbosity(lxc.Verbose)
|
||||
if err := c.Create("ubuntu", "amd64", "quantal"); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,8 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
fmt.Printf("Destroying container...\n")
|
||||
c.Destroy()
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Destroying container...\n")
|
||||
if err := c.Destroy(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +41,9 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
if c.Running() {
|
||||
fmt.Printf("Freezing the container...\n")
|
||||
c.Freeze()
|
||||
c.Wait(lxc.FROZEN, 10)
|
||||
} else {
|
||||
fmt.Printf("Container is not running...\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Freezing the container...\n")
|
||||
if err := c.Freeze(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
c.Wait(lxc.FROZEN, 10)
|
||||
}
|
||||
|
||||
@@ -41,14 +41,8 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
if c.Running() {
|
||||
fmt.Printf("Shutting down the container...\n")
|
||||
c.Shutdown(30)
|
||||
} else {
|
||||
fmt.Printf("Container is already stopped...\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Shutting down the container...\n")
|
||||
if err := c.Shutdown(30); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +41,9 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
if !c.Running() {
|
||||
fmt.Printf("Starting the container...\n")
|
||||
c.SetDaemonize()
|
||||
c.Start(false)
|
||||
} else {
|
||||
fmt.Printf("Container is already running...\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Starting the container...\n")
|
||||
c.SetDaemonize()
|
||||
if err := c.Start(false); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,18 +43,18 @@ func main() {
|
||||
|
||||
if c.Running() {
|
||||
// mem
|
||||
mem_used, _ := c.MemoryUsageInBytes()
|
||||
fmt.Printf("mem_used: %s\n", mem_used)
|
||||
memUsed, _ := c.MemoryUsageInBytes()
|
||||
fmt.Printf("mem_used: %s\n", memUsed)
|
||||
|
||||
mem_limit, _ := c.MemoryLimitInBytes()
|
||||
fmt.Printf("mem_limit: %s\n", mem_limit)
|
||||
memLimit, _ := c.MemoryLimitInBytes()
|
||||
fmt.Printf("mem_limit: %s\n", memLimit)
|
||||
|
||||
// swap
|
||||
swap_used, _ := c.SwapUsageInBytes()
|
||||
fmt.Printf("memsw_used: %s\n", swap_used)
|
||||
swapUsed, _ := c.SwapUsageInBytes()
|
||||
fmt.Printf("memsw_used: %s\n", swapUsed)
|
||||
|
||||
swap_limit, _ := c.SwapLimitInBytes()
|
||||
fmt.Printf("memsw_used: %s\n", swap_limit)
|
||||
swapLimit, _ := c.SwapLimitInBytes()
|
||||
fmt.Printf("memsw_used: %s\n", swapLimit)
|
||||
} else {
|
||||
fmt.Printf("Container is not running...\n")
|
||||
}
|
||||
|
||||
@@ -41,14 +41,8 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
if c.Running() {
|
||||
fmt.Printf("Stopping the container...\n")
|
||||
c.Stop()
|
||||
} else {
|
||||
fmt.Printf("Container is already stopped...\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Stopping the container...\n")
|
||||
if err := c.Stop(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +41,9 @@ func main() {
|
||||
c := lxc.NewContainer(name)
|
||||
defer lxc.PutContainer(c)
|
||||
|
||||
if c.Defined() {
|
||||
if c.State() == lxc.FROZEN {
|
||||
fmt.Printf("Unfreezing the container...\n")
|
||||
c.Unfreeze()
|
||||
c.Wait(lxc.RUNNING, 10)
|
||||
} else {
|
||||
fmt.Printf("Container is not running...\n")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No such container...\n")
|
||||
fmt.Printf("Unfreezing the container...\n")
|
||||
if err := c.Unfreeze(); err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
}
|
||||
c.Wait(lxc.RUNNING, 10)
|
||||
}
|
||||
|
||||
4
lxc.c
4
lxc.c
@@ -55,8 +55,8 @@ void lxc_container_want_daemonize(struct lxc_container *c) {
|
||||
c->want_daemonize(c);
|
||||
}
|
||||
|
||||
bool lxc_container_create(struct lxc_container *c, char *t, char **argv) {
|
||||
return c->create(c, t, NULL, NULL, LXC_CREATE_QUIET, argv);
|
||||
bool lxc_container_create(struct lxc_container *c, char *t, int flags, char **argv) {
|
||||
return c->create(c, t, NULL, NULL, !!(flags & LXC_CREATE_QUIET), argv);
|
||||
}
|
||||
|
||||
bool lxc_container_start(struct lxc_container *c, int useinit, char ** argv) {
|
||||
|
||||
68
lxc.go
68
lxc.go
@@ -21,9 +21,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//Go (golang) Bindings for LXC (Linux Containers)
|
||||
//
|
||||
//This package implements Go bindings for the LXC C API.
|
||||
// Package lxc provides Go (golang) Bindings for LXC (Linux Containers) C API.
|
||||
package lxc
|
||||
|
||||
// #cgo linux LDFLAGS: -llxc -lutil
|
||||
@@ -39,20 +37,21 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Timeout
|
||||
WAIT_FOREVER int = iota - 1
|
||||
DONT_WAIT
|
||||
// WaitForever timeout
|
||||
WaitForever int = iota - 1
|
||||
// DontWait timeout
|
||||
DontWait
|
||||
)
|
||||
|
||||
const (
|
||||
CLONE_KEEPNAME int = 1 << iota
|
||||
CLONE_COPYHOOKS
|
||||
CLONE_KEEPMACADDR
|
||||
CLONE_SNAPSHOT
|
||||
)
|
||||
|
||||
const (
|
||||
CREATE_QUIET int = 1 << iota
|
||||
// CloneKeepName means don't edit the rootfs to change the hostname.
|
||||
CloneKeepName int = 1 << iota
|
||||
// CloneCopyHooks means copy all hooks into the container directory.
|
||||
CloneCopyHooks
|
||||
// CloneKeepMACAddr means don't change the mac address on network interfaces.
|
||||
CloneKeepMACAddr
|
||||
// CloneSnapshot means snapshot the original filesystem(s).
|
||||
CloneSnapshot
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -61,57 +60,62 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// NewContainer returns a new container struct
|
||||
func NewContainer(name string) *Container {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return &Container{container: C.lxc_container_new(cname, nil)}
|
||||
|
||||
return &Container{container: C.lxc_container_new(cname, nil), verbosity: Quiet}
|
||||
}
|
||||
|
||||
// Increments reference counter of the container object
|
||||
// GetContainer increments reference counter of the container object
|
||||
func GetContainer(lxc *Container) bool {
|
||||
return C.lxc_container_get(lxc.container) == 1
|
||||
}
|
||||
|
||||
// Decrements reference counter of the container object
|
||||
// PutContainer decrements reference counter of the container object
|
||||
func PutContainer(lxc *Container) bool {
|
||||
return C.lxc_container_put(lxc.container) == 1
|
||||
}
|
||||
|
||||
// Returns LXC version
|
||||
// Version returns LXC version
|
||||
func Version() string {
|
||||
return C.GoString(C.lxc_get_version())
|
||||
}
|
||||
|
||||
// Returns default config path
|
||||
// DefaultConfigPath returns default config path
|
||||
func DefaultConfigPath() string {
|
||||
return C.GoString(C.lxc_get_default_config_path())
|
||||
}
|
||||
|
||||
// Returns default LVM volume group
|
||||
// DefaultLvmVg returns default LVM volume group
|
||||
func DefaultLvmVg() string {
|
||||
return C.GoString(C.lxc_get_default_lvm_vg())
|
||||
}
|
||||
|
||||
// Returns default ZFS root
|
||||
// DefaultZfsRoot returns default ZFS root
|
||||
func DefaultZfsRoot() string {
|
||||
return C.GoString(C.lxc_get_default_zfs_root())
|
||||
}
|
||||
|
||||
// Returns the names of containers on the system.
|
||||
func ContainerNames() []string {
|
||||
// FIXME: Support custom config paths
|
||||
matches, err := filepath.Glob(filepath.Join(DefaultConfigPath(), "/*/config"))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// ContainerNames returns the names of containers on the system.
|
||||
func ContainerNames(paths ...string) []string {
|
||||
if paths == nil {
|
||||
matches, err := filepath.Glob(filepath.Join(DefaultConfigPath(), "/*/config"))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, v := range matches {
|
||||
matches[i] = filepath.Base(filepath.Dir(v))
|
||||
for i, v := range matches {
|
||||
matches[i] = filepath.Base(filepath.Dir(v))
|
||||
}
|
||||
return matches
|
||||
}
|
||||
return matches
|
||||
// FIXME: Support custom config paths
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the containers on the system.
|
||||
// Containers returns the containers on the system.
|
||||
func Containers() []Container {
|
||||
var containers []Container
|
||||
|
||||
|
||||
11
lxc.h
11
lxc.h
@@ -22,18 +22,20 @@
|
||||
*/
|
||||
|
||||
extern bool lxc_container_clear_config_item(struct lxc_container *, char *);
|
||||
extern bool lxc_container_create(struct lxc_container *, char *, char **);
|
||||
extern bool lxc_container_clone(struct lxc_container *, const char *, int, const char *);
|
||||
extern bool lxc_container_console(struct lxc_container *, int, int, int, int, int);
|
||||
extern bool lxc_container_create(struct lxc_container *, char *, int, char **);
|
||||
extern bool lxc_container_defined(struct lxc_container *);
|
||||
extern bool lxc_container_destroy(struct lxc_container *);
|
||||
extern bool lxc_container_freeze(struct lxc_container *);
|
||||
extern bool lxc_container_load_config(struct lxc_container *, char *);
|
||||
extern bool lxc_container_reboot(struct lxc_container *);
|
||||
extern bool lxc_container_running(struct lxc_container *);
|
||||
extern bool lxc_container_save_config(struct lxc_container *, char *);
|
||||
extern bool lxc_container_set_cgroup_item(struct lxc_container *, char *key, char *);
|
||||
extern bool lxc_container_set_config_item(struct lxc_container *, char *, char *);
|
||||
extern bool lxc_container_set_config_path(struct lxc_container *, char *);
|
||||
extern bool lxc_container_shutdown(struct lxc_container *, int);
|
||||
extern bool lxc_container_reboot(struct lxc_container *);
|
||||
extern bool lxc_container_start(struct lxc_container *, int, char **);
|
||||
extern bool lxc_container_stop(struct lxc_container *);
|
||||
extern bool lxc_container_unfreeze(struct lxc_container *);
|
||||
@@ -44,13 +46,10 @@ extern char* lxc_container_get_config_item(struct lxc_container *, char *);
|
||||
extern char* lxc_container_get_keys(struct lxc_container *, char *);
|
||||
extern const char* lxc_container_get_config_path(struct lxc_container *);
|
||||
extern const char* lxc_container_state(struct lxc_container *);
|
||||
extern int lxc_container_console_getfd(struct lxc_container *, int);
|
||||
extern pid_t lxc_container_init_pid(struct lxc_container *);
|
||||
extern void lxc_container_want_daemonize(struct lxc_container *);
|
||||
|
||||
extern bool lxc_container_clone(struct lxc_container *, const char *, int, const char *);
|
||||
extern int lxc_container_console_getfd(struct lxc_container *, int);
|
||||
extern bool lxc_container_console(struct lxc_container *, int, int, int, int, int);
|
||||
|
||||
//FIXME: Missing API functionality
|
||||
// char** (*get_ips)(struct lxc_container *c, char* interface, char* family, int scope);
|
||||
// int (*attach)(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process);
|
||||
|
||||
200
lxc_test.go
200
lxc_test.go
@@ -33,11 +33,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
CONTAINER_NAME = "rubik"
|
||||
CLONE_CONTAINER_NAME = "O"
|
||||
CLONE_OVERLAY_CONTAINER_NAME = "O_o"
|
||||
CONFIG_FILE_PATH = "/var/lib/lxc"
|
||||
CONFIG_FILE_NAME = "/var/lib/lxc/rubik/config"
|
||||
ContainerName = "rubik"
|
||||
CloneContainerName = "O"
|
||||
CloneOverlayContainerName = "O_o"
|
||||
ConfigFilePath = "/var/lib/lxc"
|
||||
ConfigFileName = "/var/lib/lxc/rubik/config"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -49,20 +49,22 @@ func TestVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDefaultConfigPath(t *testing.T) {
|
||||
if DefaultConfigPath() != CONFIG_FILE_PATH {
|
||||
if DefaultConfigPath() != ConfigFilePath {
|
||||
t.Errorf("DefaultConfigPath failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetConfigPath(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
current_path := z.ConfigPath()
|
||||
z.SetConfigPath("/tmp")
|
||||
new_path := z.ConfigPath()
|
||||
currentPath := z.ConfigPath()
|
||||
if err := z.SetConfigPath("/tmp"); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
newPath := z.ConfigPath()
|
||||
|
||||
if current_path == new_path {
|
||||
if currentPath == newPath {
|
||||
t.Errorf("SetConfigPath failed...")
|
||||
}
|
||||
}
|
||||
@@ -89,7 +91,7 @@ func TestConcurrentDefined_Negative(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDefined_Negative(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if z.Defined() {
|
||||
@@ -98,24 +100,24 @@ func TestDefined_Negative(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.Create("ubuntu", "amd64", "quantal") {
|
||||
t.Errorf("Creating the container failed...")
|
||||
if err := z.Create("ubuntu", "amd64", "quantal"); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.Clone(CLONE_CONTAINER_NAME, DIRECTORY) {
|
||||
t.Errorf("Cloning the DIRECTORY backed container failed...")
|
||||
if err := z.CloneToDirectory(CloneContainerName); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
if !z.Clone(CLONE_OVERLAY_CONTAINER_NAME, OVERLAYFS) {
|
||||
t.Errorf("Cloning the OVERLAYFS backed container failed...")
|
||||
if err := z.CloneToOverlayFS(CloneOverlayContainerName); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +133,8 @@ func TestConcurrentCreate(t *testing.T) {
|
||||
// sleep for a while to simulate some dummy work
|
||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(250)))
|
||||
|
||||
if !z.Create("ubuntu", "amd64", "quantal") {
|
||||
t.Errorf("Creating the container (%d) failed...", i)
|
||||
if err := z.Create("ubuntu", "amd64", "quantal"); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
@@ -160,7 +162,9 @@ func TestConcurrentStart(t *testing.T) {
|
||||
defer PutContainer(z)
|
||||
|
||||
z.SetDaemonize()
|
||||
z.Start(false)
|
||||
if err := z.Start(false); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
z.Wait(RUNNING, 30)
|
||||
if !z.Running() {
|
||||
t.Errorf("Starting the container failed...")
|
||||
@@ -173,15 +177,15 @@ func TestConcurrentStart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigFileName(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
if z.ConfigFileName() != CONFIG_FILE_NAME {
|
||||
if z.ConfigFileName() != ConfigFileName {
|
||||
t.Errorf("ConfigFileName failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefined_Positive(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.Defined() {
|
||||
@@ -211,7 +215,7 @@ func TestConcurrentDefined_Positive(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInitPID_Negative(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if z.InitPID() != -1 {
|
||||
@@ -220,7 +224,7 @@ func TestInitPID_Negative(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.SetDaemonize()
|
||||
@@ -233,7 +237,7 @@ func TestStart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetDaemonize(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.SetDaemonize()
|
||||
@@ -243,7 +247,7 @@ func TestSetDaemonize(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInitPID_Positive(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if z.InitPID() == -1 {
|
||||
@@ -252,19 +256,21 @@ func TestInitPID_Positive(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if z.Name() != CONTAINER_NAME {
|
||||
if z.Name() != ContainerName {
|
||||
t.Errorf("Name failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFreeze(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.Freeze()
|
||||
if err := z.Freeze(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
z.Wait(FROZEN, 30)
|
||||
if z.State() != FROZEN {
|
||||
@@ -273,10 +279,12 @@ func TestFreeze(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnfreeze(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.Unfreeze()
|
||||
if err := z.Unfreeze(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
z.Wait(RUNNING, 30)
|
||||
if z.State() != RUNNING {
|
||||
@@ -285,68 +293,74 @@ func TestUnfreeze(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadConfigFile(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.LoadConfigFile(CONFIG_FILE_NAME) {
|
||||
t.Errorf("LoadConfigFile failed...")
|
||||
if err := z.LoadConfigFile(ConfigFileName); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveConfigFile(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.SaveConfigFile(CONFIG_FILE_NAME) {
|
||||
t.Errorf("LoadConfigFile failed...")
|
||||
if err := z.SaveConfigFile(ConfigFileName); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigItem(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if z.ConfigItem("lxc.utsname")[0] != CONTAINER_NAME {
|
||||
if z.ConfigItem("lxc.utsname")[0] != ContainerName {
|
||||
t.Errorf("ConfigItem failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetConfigItem(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.SetConfigItem("lxc.utsname", CONTAINER_NAME)
|
||||
if z.ConfigItem("lxc.utsname")[0] != CONTAINER_NAME {
|
||||
if err := z.SetConfigItem("lxc.utsname", ContainerName); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
if z.ConfigItem("lxc.utsname")[0] != ContainerName {
|
||||
t.Errorf("ConfigItem failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCgroupItem(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
max_mem := z.CgroupItem("memory.max_usage_in_bytes")[0]
|
||||
current_mem := z.CgroupItem("memory.limit_in_bytes")[0]
|
||||
z.SetCgroupItem("memory.limit_in_bytes", max_mem)
|
||||
new_mem := z.CgroupItem("memory.limit_in_bytes")[0]
|
||||
maxMem := z.CgroupItem("memory.max_usage_in_bytes")[0]
|
||||
currentMem := z.CgroupItem("memory.limit_in_bytes")[0]
|
||||
if err := z.SetCgroupItem("memory.limit_in_bytes", maxMem); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
newMem := z.CgroupItem("memory.limit_in_bytes")[0]
|
||||
|
||||
if new_mem == current_mem {
|
||||
if newMem == currentMem {
|
||||
t.Errorf("SetCgroupItem failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearConfigItem(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.ClearConfigItem("lxc.cap.drop")
|
||||
if err := z.ClearConfigItem("lxc.cap.drop"); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
if z.ConfigItem("lxc.cap.drop")[0] != "" {
|
||||
t.Errorf("ClearConfigItem failed...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeys(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
keys := strings.Join(z.Keys("lxc.network.0"), " ")
|
||||
@@ -356,7 +370,7 @@ func TestKeys(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNumberOfNetworkInterfaces(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if z.NumberOfNetworkInterfaces() != 1 {
|
||||
@@ -365,28 +379,28 @@ func TestNumberOfNetworkInterfaces(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMemoryUsageInBytes(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
mem_used, _ := z.MemoryUsageInBytes()
|
||||
swap_used, _ := z.SwapUsageInBytes()
|
||||
mem_limit, _ := z.MemoryLimitInBytes()
|
||||
swap_limit, _ := z.SwapLimitInBytes()
|
||||
memUsed, _ := z.MemoryUsageInBytes()
|
||||
swapUsed, _ := z.SwapUsageInBytes()
|
||||
memLimit, _ := z.MemoryLimitInBytes()
|
||||
swapLimit, _ := z.SwapLimitInBytes()
|
||||
|
||||
t.Logf("Mem usage: %0.0f\n", mem_used)
|
||||
t.Logf("Mem usage: %s\n", mem_used)
|
||||
t.Logf("Swap usage: %0.0f\n", swap_used)
|
||||
t.Logf("Swap usage: %s\n", swap_used)
|
||||
t.Logf("Mem limit: %0.0f\n", mem_limit)
|
||||
t.Logf("Mem limit: %s\n", mem_limit)
|
||||
t.Logf("Swap limit: %0.0f\n", swap_limit)
|
||||
t.Logf("Swap limit: %s\n", swap_limit)
|
||||
t.Logf("Mem usage: %0.0f\n", memUsed)
|
||||
t.Logf("Mem usage: %s\n", memUsed)
|
||||
t.Logf("Swap usage: %0.0f\n", swapUsed)
|
||||
t.Logf("Swap usage: %s\n", swapUsed)
|
||||
t.Logf("Mem limit: %0.0f\n", memLimit)
|
||||
t.Logf("Mem limit: %s\n", memLimit)
|
||||
t.Logf("Swap limit: %0.0f\n", swapLimit)
|
||||
t.Logf("Swap limit: %s\n", swapLimit)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
func TestReboot(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
t.Logf("Rebooting the container...\n")
|
||||
@@ -407,8 +421,9 @@ func TestConcurrentShutdown(t *testing.T) {
|
||||
z := NewContainer(strconv.Itoa(i))
|
||||
defer PutContainer(z)
|
||||
|
||||
z.Shutdown(30)
|
||||
|
||||
if err := z.Shutdown(30); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
if z.Running() {
|
||||
t.Errorf("Shutting down the container failed...")
|
||||
}
|
||||
@@ -420,10 +435,12 @@ func TestConcurrentShutdown(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestShutdown(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.Shutdown(30)
|
||||
if err := z.Shutdown(30); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
if z.Running() {
|
||||
t.Errorf("Shutting down the container failed...")
|
||||
@@ -431,10 +448,17 @@ func TestShutdown(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStop(t *testing.T) {
|
||||
z := NewContainer(CONTAINER_NAME)
|
||||
z := NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
z.Stop()
|
||||
z.SetDaemonize()
|
||||
if err := z.Start(false); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
if err := z.Stop(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
if z.Running() {
|
||||
t.Errorf("Stopping the container failed...")
|
||||
@@ -442,25 +466,25 @@ func TestStop(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDestroy(t *testing.T) {
|
||||
z := NewContainer(CLONE_OVERLAY_CONTAINER_NAME)
|
||||
z := NewContainer(CloneOverlayContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.Destroy() {
|
||||
t.Errorf("Destroying the container failed...")
|
||||
if err := z.Destroy(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
z = NewContainer(CLONE_CONTAINER_NAME)
|
||||
z = NewContainer(CloneContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.Destroy() {
|
||||
t.Errorf("Destroying the container failed...")
|
||||
if err := z.Destroy(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
|
||||
z = NewContainer(CONTAINER_NAME)
|
||||
z = NewContainer(ContainerName)
|
||||
defer PutContainer(z)
|
||||
|
||||
if !z.Destroy() {
|
||||
t.Errorf("Destroying the container failed...")
|
||||
if err := z.Destroy(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,8 +500,8 @@ func TestConcurrentDestroy(t *testing.T) {
|
||||
// sleep for a while to simulate some dummy work
|
||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(250)))
|
||||
|
||||
if !z.Destroy() {
|
||||
t.Errorf("Destroying the container failed...")
|
||||
if err := z.Destroy(); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
75
state.go
75
state.go
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* state.go: Go bindings for lxc
|
||||
*
|
||||
* Copyright © 2013, S.Çağlar Onur
|
||||
*
|
||||
* Authors:
|
||||
* S.Çağlar Onur <caglar@10ur.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package lxc
|
||||
|
||||
// #include <lxc/lxc.h>
|
||||
// #include <lxc/lxccontainer.h>
|
||||
import "C"
|
||||
|
||||
type State int
|
||||
|
||||
const (
|
||||
STOPPED State = C.STOPPED
|
||||
STARTING State = C.STARTING
|
||||
RUNNING State = C.RUNNING
|
||||
STOPPING State = C.STOPPING
|
||||
ABORTING State = C.ABORTING
|
||||
FREEZING State = C.FREEZING
|
||||
FROZEN State = C.FROZEN
|
||||
THAWED State = C.THAWED
|
||||
)
|
||||
|
||||
var stateMap = map[string]State{
|
||||
"STOPPED": STOPPED,
|
||||
"STARTING": STARTING,
|
||||
"RUNNING": RUNNING,
|
||||
"STOPPING": STOPPING,
|
||||
"ABORTING": ABORTING,
|
||||
"FREEZING": FREEZING,
|
||||
"FROZEN": FROZEN,
|
||||
"THAWED": THAWED,
|
||||
}
|
||||
|
||||
// State as string
|
||||
func (t State) String() string {
|
||||
switch t {
|
||||
case STOPPED:
|
||||
return "STOPPED"
|
||||
case STARTING:
|
||||
return "STARTING"
|
||||
case RUNNING:
|
||||
return "RUNNING"
|
||||
case STOPPING:
|
||||
return "STOPPING"
|
||||
case ABORTING:
|
||||
return "ABORTING"
|
||||
case FREEZING:
|
||||
return "FREEZING"
|
||||
case FROZEN:
|
||||
return "FROZEN"
|
||||
case THAWED:
|
||||
return "THAWED"
|
||||
}
|
||||
return "<INVALID>"
|
||||
}
|
||||
182
type.go
Normal file
182
type.go
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* type.go: Go bindings for lxc
|
||||
*
|
||||
* Copyright © 2013, S.Çağlar Onur
|
||||
*
|
||||
* Authors:
|
||||
* S.Çağlar Onur <caglar@10ur.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package lxc
|
||||
|
||||
// #include <lxc/lxc.h>
|
||||
// #include <lxc/lxccontainer.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Verbosity type
|
||||
type Verbosity int
|
||||
|
||||
const (
|
||||
// Quiet makes some API calls not to write anything to stdout
|
||||
Quiet Verbosity = 1 << iota
|
||||
// Verbose makes some API calls write to stdout
|
||||
Verbose
|
||||
)
|
||||
|
||||
// BackendStore type
|
||||
type BackendStore int
|
||||
|
||||
const (
|
||||
// BtrFS backendstore type
|
||||
BtrFS BackendStore = iota
|
||||
// Directory backendstore type
|
||||
Directory
|
||||
// LVM backendstore type
|
||||
LVM
|
||||
// ZFS backendstore type
|
||||
ZFS
|
||||
// OverlayFS backendstore type
|
||||
OverlayFS
|
||||
// Loopback backendstore type
|
||||
Loopback
|
||||
)
|
||||
|
||||
// BackendStore as string
|
||||
func (t BackendStore) String() string {
|
||||
switch t {
|
||||
case Directory:
|
||||
return "dir"
|
||||
case ZFS:
|
||||
return "zfs"
|
||||
case BtrFS:
|
||||
return "btrfs"
|
||||
case LVM:
|
||||
return "lvm"
|
||||
case OverlayFS:
|
||||
return "overlayfs"
|
||||
case Loopback:
|
||||
return "loopback"
|
||||
}
|
||||
return "<INVALID>"
|
||||
}
|
||||
|
||||
// State type
|
||||
type State int
|
||||
|
||||
const (
|
||||
// STOPPED means container is not running
|
||||
STOPPED State = C.STOPPED
|
||||
// STARTING means container is starting
|
||||
STARTING State = C.STARTING
|
||||
// RUNNING means container is running
|
||||
RUNNING State = C.RUNNING
|
||||
// STOPPING means container is stopping
|
||||
STOPPING State = C.STOPPING
|
||||
// ABORTING means container is aborting
|
||||
ABORTING State = C.ABORTING
|
||||
// FREEZING means container is freezing
|
||||
FREEZING State = C.FREEZING
|
||||
// FROZEN means containe is frozen
|
||||
FROZEN State = C.FROZEN
|
||||
// THAWED means container is thawed
|
||||
THAWED State = C.THAWED
|
||||
)
|
||||
|
||||
var stateMap = map[string]State{
|
||||
"STOPPED": STOPPED,
|
||||
"STARTING": STARTING,
|
||||
"RUNNING": RUNNING,
|
||||
"STOPPING": STOPPING,
|
||||
"ABORTING": ABORTING,
|
||||
"FREEZING": FREEZING,
|
||||
"FROZEN": FROZEN,
|
||||
"THAWED": THAWED,
|
||||
}
|
||||
|
||||
// State as string
|
||||
func (t State) String() string {
|
||||
switch t {
|
||||
case STOPPED:
|
||||
return "STOPPED"
|
||||
case STARTING:
|
||||
return "STARTING"
|
||||
case RUNNING:
|
||||
return "RUNNING"
|
||||
case STOPPING:
|
||||
return "STOPPING"
|
||||
case ABORTING:
|
||||
return "ABORTING"
|
||||
case FREEZING:
|
||||
return "FREEZING"
|
||||
case FROZEN:
|
||||
return "FROZEN"
|
||||
case THAWED:
|
||||
return "THAWED"
|
||||
}
|
||||
return "<INVALID>"
|
||||
}
|
||||
|
||||
// Taken from http://golang.org/doc/effective_go.html#constants
|
||||
|
||||
// ByteSize type
|
||||
type ByteSize float64
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
// KB - kilobyte
|
||||
KB ByteSize = 1 << (10 * iota)
|
||||
// MB - megabyte
|
||||
MB
|
||||
// GB - gigabyte
|
||||
GB
|
||||
// TB - terabyte
|
||||
TB
|
||||
// PB - petabyte
|
||||
PB
|
||||
// EB - exabyte
|
||||
EB
|
||||
// ZB - zettabyte
|
||||
ZB
|
||||
// YB - yottabyte
|
||||
YB
|
||||
)
|
||||
|
||||
func (b ByteSize) String() string {
|
||||
switch {
|
||||
case b >= YB:
|
||||
return fmt.Sprintf("%.2fYB", b/YB)
|
||||
case b >= ZB:
|
||||
return fmt.Sprintf("%.2fZB", b/ZB)
|
||||
case b >= EB:
|
||||
return fmt.Sprintf("%.2fEB", b/EB)
|
||||
case b >= PB:
|
||||
return fmt.Sprintf("%.2fPB", b/PB)
|
||||
case b >= TB:
|
||||
return fmt.Sprintf("%.2fTB", b/TB)
|
||||
case b >= GB:
|
||||
return fmt.Sprintf("%.2fGB", b/GB)
|
||||
case b >= MB:
|
||||
return fmt.Sprintf("%.2fMB", b/MB)
|
||||
case b >= KB:
|
||||
return fmt.Sprintf("%.2fKB", b/KB)
|
||||
}
|
||||
return fmt.Sprintf("%.2fB", b)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* utils.go: Go bindings for lxc
|
||||
* util.go: Go bindings for lxc
|
||||
*
|
||||
* Copyright © 2013, S.Çağlar Onur
|
||||
*
|
||||
Reference in New Issue
Block a user