1
0
mirror of https://github.com/lxc/go-lxc.git synced 2026-02-05 15:47:17 +01:00

Add missing Attach options including Uid, Gid, Namespaces and Personality.

Introduce DefaultAttachOptions

fixes #12
This commit is contained in:
S.Çağlar Onur
2014-10-04 12:56:29 -04:00
parent cefcc74c25
commit b098cbcdd8
8 changed files with 227 additions and 139 deletions

View File

@@ -954,23 +954,8 @@ func (c *Container) Console(ttynum int, stdinfd, stdoutfd, stderrfd uintptr, esc
}
// AttachShell attaches a shell to the container.
func (c *Container) AttachShell() error {
if err := c.makeSure(isDefined | isRunning); err != nil {
return err
}
c.mu.Lock()
defer c.mu.Unlock()
if int(C.go_lxc_attach(c.container, false)) < 0 {
return ErrAttachFailed
}
return nil
}
// AttachShellWithClearEnvironment attaches a shell to the container.
// It clears all environment variables before attaching.
func (c *Container) AttachShellWithClearEnvironment() error {
func (c *Container) AttachShell(options *AttachOptions) error {
if err := c.makeSure(isDefined | isRunning); err != nil {
return err
}
@@ -978,7 +963,35 @@ func (c *Container) AttachShellWithClearEnvironment() error {
c.mu.Lock()
defer c.mu.Unlock()
if int(C.go_lxc_attach(c.container, true)) < 0 {
cenv := makeNullTerminatedArgs(options.Env)
if cenv == nil {
return ErrAllocationFailed
}
defer freeNullTerminatedArgs(cenv, len(options.Env))
cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
if cenvToKeep == nil {
return ErrAllocationFailed
}
defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))
cwd := C.CString(options.Cwd)
defer C.free(unsafe.Pointer(cwd))
ret := int(C.go_lxc_attach(c.container,
C.bool(options.ClearEnv),
C.int(options.Namespaces),
C.long(options.Arch),
C.uid_t(options.Uid),
C.gid_t(options.Gid),
C.int(options.StdinFd),
C.int(options.StdoutFd),
C.int(options.StderrFd),
cwd,
cenv,
cenvToKeep,
))
if ret < 0 {
return ErrAttachFailed
}
return nil
@@ -1011,17 +1024,28 @@ func (c *Container) RunCommand(args []string, options *AttachOptions) (bool, err
}
defer freeNullTerminatedArgs(cenv, len(options.Env))
cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
if cenvToKeep == nil {
return false, ErrAllocationFailed
}
defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))
cwd := C.CString(options.Cwd)
defer C.free(unsafe.Pointer(cwd))
ret := int(C.go_lxc_attach_run_wait(
c.container,
C.bool(options.ClearEnv),
C.int(options.Stdinfd),
C.int(options.Stdoutfd),
C.int(options.Stderrfd),
C.int(options.Namespaces),
C.long(options.Arch),
C.uid_t(options.Uid),
C.gid_t(options.Gid),
C.int(options.StdinFd),
C.int(options.StdoutFd),
C.int(options.StderrFd),
cwd,
cenv,
cenvToKeep,
cargs,
))

View File

@@ -7,7 +7,6 @@ package main
import (
"flag"
"log"
"os"
"gopkg.in/lxc/go-lxc.v2"
)
@@ -16,12 +15,16 @@ var (
lxcpath string
name string
clear bool
x86 bool
regular bool
)
func init() {
flag.StringVar(&lxcpath, "lxcpath", lxc.DefaultConfigPath(), "Use specified container path")
flag.StringVar(&name, "name", "rubik", "Name of the original container")
flag.BoolVar(&clear, "clear", false, "Attach with clear environment")
flag.BoolVar(&x86, "x86", false, "Attach using x86 personality")
flag.BoolVar(&regular, "regular", false, "Attach using a regular user")
flag.Parse()
}
@@ -32,38 +35,27 @@ func main() {
}
defer lxc.Release(c)
options := lxc.DefaultAttachOptions
options.ClearEnv = false
if clear {
log.Printf("AttachShellWithClearEnvironment\n")
if err := c.AttachShellWithClearEnvironment(); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
options.ClearEnv = true
}
if x86 {
options.Arch = lxc.X86
}
if regular {
options.Uid = 1000
options.Gid = 1000
}
log.Printf("AttachShell\n")
err = c.AttachShell(options)
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
log.Printf("RunCommandWithClearEnvironment\n")
_, err := c.RunCommand([]string{"uname", "-a"}, &lxc.AttachOptions{
ClearEnv: true,
Stdinfd: os.Stdin.Fd(),
Stdoutfd: os.Stdout.Fd(),
Stderrfd: os.Stderr.Fd(),
})
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
} else {
log.Printf("AttachShell\n")
if err := c.AttachShell(); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
log.Printf("RunCommand\n")
_, err := c.RunCommand([]string{"uname", "-a"}, &lxc.AttachOptions{
ClearEnv: false,
Stdinfd: os.Stdin.Fd(),
Stdoutfd: os.Stdout.Fd(),
Stderrfd: os.Stderr.Fd(),
})
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
log.Printf("RunCommand\n")
_, err = c.RunCommand([]string{"id"}, options)
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
}

View File

@@ -18,6 +18,8 @@ var (
lxcpath string
name string
clear bool
x86 bool
regular bool
wg sync.WaitGroup
)
@@ -25,6 +27,8 @@ func init() {
flag.StringVar(&lxcpath, "lxcpath", lxc.DefaultConfigPath(), "Use specified container path")
flag.StringVar(&name, "name", "rubik", "Name of the original container")
flag.BoolVar(&clear, "clear", false, "Attach with clear environment")
flag.BoolVar(&x86, "x86", false, "Attach using x86 personality")
flag.BoolVar(&regular, "regular", false, "Attach using a regular user")
flag.Parse()
}
@@ -61,44 +65,39 @@ func main() {
}
}()
options := lxc.DefaultAttachOptions
options.StdinFd = os.Stdin.Fd()
options.StdoutFd = stdoutWriter.Fd()
options.StderrFd = stderrWriter.Fd()
options.ClearEnv = false
if clear {
log.Printf("AttachShellWithClearEnvironment\n")
if err := c.AttachShellWithClearEnvironment(); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
log.Printf("RunCommandWithClearEnvironment\n")
_, err := c.RunCommand([]string{"uname", "-a"}, &lxc.AttachOptions{
ClearEnv: true,
Stdinfd: os.Stdin.Fd(),
Stdoutfd: stdoutWriter.Fd(),
Stderrfd: stderrWriter.Fd(),
})
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
} else {
log.Printf("AttachShell\n")
if err := c.AttachShell(); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
log.Printf("RunCommand\n")
_, err := c.RunCommand([]string{"uname", "-a"}, &lxc.AttachOptions{
ClearEnv: false,
Stdinfd: os.Stdin.Fd(),
Stdoutfd: stdoutWriter.Fd(),
Stderrfd: stderrWriter.Fd(),
})
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
options.ClearEnv = true
}
if err := stdoutWriter.Close(); err != nil {
if x86 {
options.Arch = lxc.X86
}
if regular {
options.Uid = 1000
options.Gid = 1000
}
log.Printf("AttachShell\n")
if err := c.AttachShell(options); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
if err := stderrWriter.Close(); err != nil {
log.Printf("RunCommand\n")
_, err = c.RunCommand([]string{"uname", "-a"}, options)
if err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
if err = stdoutWriter.Close(); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}
if err = stderrWriter.Close(); err != nil {
log.Fatalf("ERROR: %s\n", err.Error())
}

59
lxc.c
View File

@@ -177,7 +177,15 @@ char** go_lxc_get_ips(struct lxc_container *c, const char *interface, const char
return c->get_ips(c, interface, family, scope);
}
int go_lxc_attach(struct lxc_container *c, bool clear_env) {
int go_lxc_attach(struct lxc_container *c,
bool clear_env,
int namespaces,
long personality,
uid_t uid, gid_t gid,
int stdinfd, int stdoutfd, int stderrfd,
char *initial_cwd,
char **extra_env_vars,
char **extra_keep_env) {
int ret;
pid_t pid;
@@ -187,6 +195,21 @@ int go_lxc_attach(struct lxc_container *c, bool clear_env) {
if (clear_env) {
attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
}
attach_options.namespaces = namespaces;
attach_options.personality = personality;
attach_options.uid = uid;
attach_options.gid = gid;
attach_options.stdin_fd = stdinfd;
attach_options.stdout_fd = stdoutfd;
attach_options.stderr_fd = stderrfd;
attach_options.initial_cwd = initial_cwd;
attach_options.extra_env_vars = extra_env_vars;
attach_options.extra_keep_env = extra_keep_env;
/*
remount_sys_proc
When using -s and the mount namespace is not included, this flag will cause lxc-attach to remount /proc and /sys to reflect the current other namespace contexts.
@@ -195,20 +218,6 @@ int go_lxc_attach(struct lxc_container *c, bool clear_env) {
elevated_privileges
Do not drop privileges when running command inside the container. If this option is specified, the new process will not be added to the container's cgroup(s) and it will not drop its capabilities before executing.
default_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_APPARMOR);
Specify the namespaces to attach to, as a pipe-separated list, e.g. NETWORK|IPC. Allowed values are MOUNT, PID, UTSNAME, IPC, USER and NETWORK.
default_options.namespaces = namespace_flags; // lxc_fill_namespace_flags(arg, &namespace_flags);
Specify the architecture which the kernel should appear to be running as to the command executed.
default_options.personality = new_personality; // lxc_config_parse_arch(arg);
Keep the current environment for attached programs.
Clear the environment before attaching, so no undesired environment variables leak into the container.
default_options.env_policy = env_policy; // LXC_ATTACH_KEEP_ENV or LXC_ATTACH_CLEAR_ENV
default_options.extra_env_vars = extra_env;
default_options.extra_keep_env = extra_keep;
*/
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
@@ -225,7 +234,16 @@ int go_lxc_attach(struct lxc_container *c, bool clear_env) {
return -1;
}
int go_lxc_attach_run_wait(struct lxc_container *c, bool clear_env, int stdinfd, int stdoutfd, int stderrfd, char *initial_cwd, char **extra_env_vars, const char * const argv[]) {
int go_lxc_attach_run_wait(struct lxc_container *c,
bool clear_env,
int namespaces,
long personality,
uid_t uid, gid_t gid,
int stdinfd, int stdoutfd, int stderrfd,
char *initial_cwd,
char **extra_env_vars,
char **extra_keep_env,
const char * const argv[]) {
int ret;
lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
@@ -234,11 +252,20 @@ int go_lxc_attach_run_wait(struct lxc_container *c, bool clear_env, int stdinfd,
if (clear_env) {
attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
}
attach_options.namespaces = namespaces;
attach_options.personality = personality;
attach_options.uid = uid;
attach_options.gid = gid;
attach_options.stdin_fd = stdinfd;
attach_options.stdout_fd = stdoutfd;
attach_options.stderr_fd = stderrfd;
attach_options.initial_cwd = initial_cwd;
attach_options.extra_env_vars = extra_env_vars;
attach_options.extra_keep_env = extra_keep_env;
ret = c->attach_run_wait(c, &attach_options, argv[0], argv);
if (WIFEXITED(ret) && WEXITSTATUS(ret) == 255)

21
lxc.h
View File

@@ -39,8 +39,25 @@ extern char* go_lxc_get_keys(struct lxc_container *c, const char *key);
extern char* go_lxc_get_running_config_item(struct lxc_container *c, const char *key);
extern const char* go_lxc_get_config_path(struct lxc_container *c);
extern const char* go_lxc_state(struct lxc_container *c);
extern int go_lxc_attach_run_wait(struct lxc_container *c, bool clear_env, int stdinfd, int stdoutfd, int stderrfd, char *initial_cwd, char **extra_env_vars, const char * const argv[]);
extern int go_lxc_attach(struct lxc_container *c, bool clear_env);
extern int go_lxc_attach_run_wait(struct lxc_container *c,
bool clear_env,
int namespaces,
long personality,
uid_t uid, gid_t gid,
int stdinfd, int stdoutfd, int stderrfd,
char *initial_cwd,
char **extra_env_vars,
char **extra_keep_env,
const char * const argv[]);
extern int go_lxc_attach(struct lxc_container *c,
bool clear_env,
int namespaces,
long personality,
uid_t uid, gid_t gid,
int stdinfd, int stdoutfd, int stderrfd,
char *initial_cwd,
char **extra_env_vars,
char **extra_keep_env);
extern int go_lxc_console_getfd(struct lxc_container *c, int ttynum);
extern int go_lxc_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret);
extern int go_lxc_snapshot(struct lxc_container *c);

View File

@@ -930,11 +930,7 @@ func TestRunCommand(t *testing.T) {
defer Release(c)
argsThree := []string{"/bin/sh", "-c", "/bin/ls -al > /dev/null"}
ok, err := c.RunCommand(argsThree, &AttachOptions{
Stdinfd: os.Stdin.Fd(),
Stdoutfd: os.Stdout.Fd(),
Stderrfd: os.Stderr.Fd(),
})
ok, err := c.RunCommand(argsThree, DefaultAttachOptions)
if err != nil {
t.Errorf(err.Error())
}
@@ -943,11 +939,7 @@ func TestRunCommand(t *testing.T) {
}
argsThree = []string{"/bin/sh", "-c", "exit 1"}
ok, err = c.RunCommand(argsThree, &AttachOptions{
Stdinfd: os.Stdin.Fd(),
Stdoutfd: os.Stdout.Fd(),
Stderrfd: os.Stderr.Fd(),
})
ok, err = c.RunCommand(argsThree, DefaultAttachOptions)
if err != nil {
t.Errorf(err.Error())
}
@@ -963,15 +955,12 @@ func TestCommandWithEnvVars(t *testing.T) {
}
defer Release(c)
args := []string{"/bin/sh", "-c", "test $FOO = 'BAR'"}
ok, err := c.RunCommand(args, &AttachOptions{
Env: []string{"FOO=BAR"},
ClearEnv: true,
Stdinfd: os.Stdin.Fd(),
Stdoutfd: os.Stdout.Fd(),
Stderrfd: os.Stderr.Fd(),
})
options := DefaultAttachOptions
options.Env = []string{"FOO=BAR"}
options.ClearEnv = true
args := []string{"/bin/sh", "-c", "test $FOO = 'BAR'"}
ok, err := c.RunCommand(args, DefaultAttachOptions)
if err != nil {
t.Errorf(err.Error())
}
@@ -987,14 +976,11 @@ func TestCommandWithCwd(t *testing.T) {
}
defer Release(c)
args := []string{"/bin/sh", "-c", "test `pwd` = /tmp"}
ok, err := c.RunCommand(args, &AttachOptions{
Stdinfd: os.Stdin.Fd(),
Stdoutfd: os.Stdout.Fd(),
Stderrfd: os.Stderr.Fd(),
Cwd: "/tmp",
})
options := DefaultAttachOptions
options.Cwd = "/tmp"
args := []string{"/bin/sh", "-c", "test `pwd` = /tmp"}
ok, err := c.RunCommand(args, options)
if err != nil {
t.Errorf(err.Error())
}

View File

@@ -6,23 +6,58 @@
package lxc
import (
"os"
)
// AttachOptions type is used for defining various attach options
type AttachOptions struct {
// Stdinfd specifies the fd to read input from
Stdinfd uintptr
// Stdoutfd specifies the fd to write output to
Stdoutfd uintptr
// Specify the namespaces to attach to, as OR'ed list of clone flags (syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS ...)
Namespaces int
// Stderrfd specifies the fd to write error output to
Stderrfd uintptr
// Env specifies the environment of the process.
Env []string
// Specify the architecture which the kernel should appear to be running as to the command executed.
Arch Personality
// Cwd specifies the working directory of the command.
Cwd string
// If ClearEnv is true the environment is cleared before
// running the command.
// Uid specifies the user id to run as.
Uid int
// Gid specifies the group id to run as.
Gid int
// If ClearEnv is true the environment is cleared before running the command.
ClearEnv bool
// Env specifies the environment of the process.
Env []string
// EnvToKeep specifies the environment of the process when ClearEnv is true.
EnvToKeep []string
// Stdinfd specifies the fd to read input from.
StdinFd uintptr
// Stdoutfd specifies the fd to write output to.
StdoutFd uintptr
// Stderrfd specifies the fd to write error output to.
StderrFd uintptr
}
// DefaultAttachOptions is a convenient set of options to be used
var DefaultAttachOptions = &AttachOptions{
Namespaces: -1,
Arch: -1,
Cwd: "/",
Uid: -1,
Gid: -1,
ClearEnv: false,
Env: nil,
EnvToKeep: nil,
StdinFd: os.Stdin.Fd(),
StdoutFd: os.Stdout.Fd(),
StderrFd: os.Stderr.Fd(),
}

View File

@@ -7,6 +7,7 @@
package lxc
// #include <lxc/lxccontainer.h>
// #include <sys/personality.h>
import "C"
import (
@@ -246,3 +247,10 @@ const (
// CloneMaybeSnapshot means snapshot only if bdev supports it, else copy
CloneMaybeSnapshot
)
type Personality int64
const (
X86 = C.PER_LINUX32
X86_64 = C.PER_LINUX
)