[lxc-devel] [go-lxc/v2] [RFC] add c->attach() wrapper returning PID of attached process
brauner on Github
lxc-bot at linuxcontainers.org
Mon Oct 10 23:21:58 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 850 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161010/1d6f4893/attachment.bin>
-------------- next part --------------
From 1cb769b3008688981da7074656255056b0f78a29 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at canonical.com>
Date: Tue, 11 Oct 2016 01:12:40 +0200
Subject: [PATCH 1/3] lxc-binding: add binding for c->attach()
Add a wrapper to call low-level c->attach() which stores the PID of the attached
process in one of its arguments. In contrast to all the other wrappers
go_lxc_attach_no_wait() will not wait on the attached process. This will allow
more flexibility in LXD when executing commands in a container.
Signed-off-by: Christian Brauner <christian.brauner at canonical.com>
---
lxc-binding.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
lxc-binding.h | 11 +++++++++++
2 files changed, 56 insertions(+)
diff --git a/lxc-binding.c b/lxc-binding.c
index 110f952..d8841ef 100644
--- a/lxc-binding.c
+++ b/lxc-binding.c
@@ -216,6 +216,51 @@ int wait_for_pid_status(pid_t pid)
return status;
}
+int go_lxc_attach_no_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[],
+ pid_t *attached_pid) {
+ int ret;
+
+ lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+ lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
+
+ attach_options.env_policy = LXC_ATTACH_KEEP_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;
+
+ command.program = (char *)argv[0];
+ command.argv = (char **)argv;
+
+ ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, attached_pid);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
int go_lxc_attach(struct lxc_container *c,
bool clear_env,
int namespaces,
diff --git a/lxc-binding.h b/lxc-binding.h
index f7ccd84..46ad5c9 100644
--- a/lxc-binding.h
+++ b/lxc-binding.h
@@ -60,6 +60,17 @@ extern int go_lxc_attach(struct lxc_container *c,
char *initial_cwd,
char **extra_env_vars,
char **extra_keep_env);
+extern int go_lxc_attach_no_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[],
+ pid_t *attached_pid);
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);
From 136de728597615f07d86584a7fdffd552d371581 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at canonical.com>
Date: Tue, 11 Oct 2016 01:16:44 +0200
Subject: [PATCH 2/3] container: add RunCommandNoWait()
RunCommandNoWait() executes a command in a running container without waiting on
the attached process. Rather, RunCommandNoWait() returns the PID of the
executing process to the caller.
Signed-off-by: Christian Brauner <christian.brauner at canonical.com>
---
container.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/container.go b/container.go
index c8684e6..d44315a 100644
--- a/container.go
+++ b/container.go
@@ -1164,6 +1164,64 @@ func (c *Container) RunCommandStatus(args []string, options AttachOptions) (int,
return ret, nil
}
+func (c *Container) RunCommandNoWait(args []string, options AttachOptions) (int, error) {
+ if len(args) == 0 {
+ return -1, ErrInsufficientNumberOfArguments
+ }
+
+ if err := c.makeSure(isRunning); err != nil {
+ return -1, err
+ }
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ cargs := makeNullTerminatedArgs(args)
+ if cargs == nil {
+ return -1, ErrAllocationFailed
+ }
+ defer freeNullTerminatedArgs(cargs, len(args))
+
+ cenv := makeNullTerminatedArgs(options.Env)
+ if cenv == nil {
+ return -1, ErrAllocationFailed
+ }
+ defer freeNullTerminatedArgs(cenv, len(options.Env))
+
+ cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
+ if cenvToKeep == nil {
+ return -1, ErrAllocationFailed
+ }
+ defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))
+
+ cwd := C.CString(options.Cwd)
+ defer C.free(unsafe.Pointer(cwd))
+
+ var attachedPid C.pid_t
+ ret := int(C.go_lxc_attach_no_wait(
+ 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,
+ cargs,
+ &attachedPid,
+ ))
+
+ if ret < 0 {
+ return -1, ErrAttachFailed
+ }
+
+ return int(attachedPid), nil
+}
+
// RunCommand attachs a shell and runs the command within the container.
// The process will wait for the command to finish and return a success status. An error
// is returned only when invocation of the command completely fails.
From 4347d3861264e5075cbb08d5bfb66be49b514019 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at canonical.com>
Date: Tue, 11 Oct 2016 01:18:05 +0200
Subject: [PATCH 3/3] lxc_test: add test for RunCommandNoWait()
Signed-off-by: Christian Brauner <christian.brauner at canonical.com>
---
lxc_test.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/lxc_test.go b/lxc_test.go
index 94091ff..c5990ce 100644
--- a/lxc_test.go
+++ b/lxc_test.go
@@ -926,6 +926,69 @@ func TestCPUStats(t *testing.T) {
}
}
+func TestRunCommandNoWait(t *testing.T) {
+ c, err := NewContainer("TestRunCommandNoWait")
+ if err != nil {
+ t.Errorf(err.Error())
+ t.FailNow()
+ }
+
+ options := DownloadTemplateOptions
+ if !unprivileged() {
+ options = BusyboxTemplateOptions
+ }
+
+ if err := c.Create(options); err != nil {
+ t.Errorf(err.Error())
+ t.FailNow()
+ }
+ defer c.Destroy()
+
+ err = c.Start()
+ if err != nil {
+ t.Errorf(err.Error())
+ t.FailNow()
+ }
+ defer c.Stop()
+
+ argsThree := []string{"/bin/sh", "-c", "exit 0"}
+ pid, err := c.RunCommandNoWait(argsThree, DefaultAttachOptions)
+ if err != nil {
+ t.Errorf(err.Error())
+ }
+
+ proc, err := os.FindProcess(pid)
+ if err != nil {
+ t.Errorf(err.Error())
+ }
+
+ procState, err := proc.Wait()
+ if err != nil {
+ t.Errorf(err.Error())
+ }
+ if !procState.Success() {
+ t.Errorf("Expected success")
+ }
+
+ argsThree = []string{"/bin/sh", "-c", "exit 0"}
+ pid, err = c.RunCommandNoWait(argsThree, DefaultAttachOptions)
+ if err != nil {
+ t.Errorf(err.Error())
+ }
+ proc, err = os.FindProcess(pid)
+ if err != nil {
+ t.Errorf(err.Error())
+ }
+
+ procState, err = proc.Wait()
+ if err != nil {
+ t.Errorf(err.Error())
+ }
+ if procState.Success() {
+ t.Errorf("Expected failure")
+ }
+}
+
func TestRunCommand(t *testing.T) {
c, err := NewContainer(ContainerName)
if err != nil {
More information about the lxc-devel
mailing list