summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/containers.go56
-rw-r--r--pkg/adapter/containers_remote.go33
-rw-r--r--pkg/rootless/rootless_linux.c84
-rw-r--r--pkg/spec/storage.go2
-rw-r--r--pkg/varlinkapi/attach.go5
-rw-r--r--pkg/varlinkapi/images.go67
-rw-r--r--pkg/varlinkapi/transfers.go11
-rw-r--r--pkg/varlinkapi/virtwriter/virtwriter.go106
8 files changed, 262 insertions, 102 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index ff7b6377a..34ee70d3d 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -6,6 +6,7 @@ import (
"bufio"
"context"
"fmt"
+ "io"
"io/ioutil"
"os"
"path/filepath"
@@ -15,9 +16,12 @@ import (
"syscall"
"time"
+ "github.com/containers/buildah"
+ "github.com/containers/image/manifest"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/libpod/pkg/systemdgen"
"github.com/containers/psgo"
@@ -1030,3 +1034,55 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri
func (r *LocalRuntime) GetNamespaces(container shared.PsContainerOutput) *shared.Namespace {
return shared.GetNamespaces(container.Pid)
}
+
+// Commit creates a local image from a container
+func (r *LocalRuntime) Commit(ctx context.Context, c *cliconfig.CommitValues, container, imageName string) (string, error) {
+ var (
+ writer io.Writer
+ mimeType string
+ )
+ switch c.Format {
+ case "oci":
+ mimeType = buildah.OCIv1ImageManifest
+ if c.Flag("message").Changed {
+ return "", errors.Errorf("messages are only compatible with the docker image format (-f docker)")
+ }
+ case "docker":
+ mimeType = manifest.DockerV2Schema2MediaType
+ default:
+ return "", errors.Errorf("unrecognized image format %q", c.Format)
+ }
+ if !c.Quiet {
+ writer = os.Stderr
+ }
+ ctr, err := r.Runtime.LookupContainer(container)
+ if err != nil {
+ return "", errors.Wrapf(err, "error looking up container %q", container)
+ }
+
+ rtc, err := r.Runtime.GetConfig()
+ if err != nil {
+ return "", err
+ }
+
+ sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false)
+ coptions := buildah.CommitOptions{
+ SignaturePolicyPath: rtc.SignaturePolicyPath,
+ ReportWriter: writer,
+ SystemContext: sc,
+ PreferredManifestType: mimeType,
+ }
+ options := libpod.ContainerCommitOptions{
+ CommitOptions: coptions,
+ Pause: c.Pause,
+ IncludeVolumes: c.IncludeVolumes,
+ Message: c.Message,
+ Changes: c.Change,
+ Author: c.Author,
+ }
+ newImage, err := ctr.Commit(ctx, imageName, options)
+ if err != nil {
+ return "", err
+ }
+ return newImage.ID(), nil
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index c34495b3d..bc6a9cfcd 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -583,7 +583,15 @@ func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid s
}
// TODO add detach keys support
- _, err = iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid, detachKeys, start)
+ reply, err := iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid, detachKeys, start)
+ if err != nil {
+ restoreTerminal(oldTermState)
+ return nil, err
+ }
+
+ // See if the server accepts the upgraded connection or returns an error
+ _, err = reply()
+
if err != nil {
restoreTerminal(oldTermState)
return nil, err
@@ -986,3 +994,26 @@ func (r *LocalRuntime) GetNamespaces(container shared.PsContainerOutput) *shared
}
return &ns
}
+
+// Commit creates a local image from a container
+func (r *LocalRuntime) Commit(ctx context.Context, c *cliconfig.CommitValues, container, imageName string) (string, error) {
+ var iid string
+ reply, err := iopodman.Commit().Send(r.Conn, varlink.More, container, imageName, c.Change, c.Author, c.Message, c.Pause, c.Format)
+ if err != nil {
+ return "", err
+ }
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return "", err
+ }
+ for _, line := range responses.Logs {
+ fmt.Fprintln(os.Stderr, line)
+ }
+ iid = responses.Id
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ return iid, nil
+}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 2356882e7..eb62d55e9 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -34,6 +34,15 @@ int renameat2 (int olddirfd, const char *oldpath, int newdirfd, const char *newp
}
#endif
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(expression) \
+ (__extension__ \
+ ({ long int __result; \
+ do __result = (long int) (expression); \
+ while (__result == -1L && errno == EINTR); \
+ __result; }))
+#endif
+
static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
@@ -113,9 +122,7 @@ get_cmd_line_args (pid_t pid)
return NULL;
for (;;)
{
- do
- ret = read (fd, buffer + used, allocated - used);
- while (ret < 0 && errno == EINTR);
+ ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used));
if (ret < 0)
{
free (buffer);
@@ -180,7 +187,7 @@ can_use_shortcut ()
argv = get_cmd_line_args (0);
if (argv == NULL)
- return NULL;
+ return false;
for (argc = 0; argv[argc]; argc++)
{
@@ -269,13 +276,15 @@ static void __attribute__((constructor)) init()
return;
}
- r = read (fd, buf, sizeof (buf));
+ r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf)));
close (fd);
if (r < 0)
{
free (cwd);
return;
}
+ buf[r] = '\0';
+
pid = strtol (buf, NULL, 10);
if (pid == LONG_MAX)
{
@@ -352,10 +361,7 @@ reexec_in_user_namespace_wait (int pid, int options)
pid_t p;
int status;
- do
- p = waitpid (pid, &status, 0);
- while (p < 0 && errno == EINTR);
-
+ p = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
if (p < 0)
return -1;
@@ -384,12 +390,10 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
close (p[1]);
/* Block until we write the pid file. */
- do
- r = read (p[0], &b, 1);
- while (r < 0 && errno == EINTR);
+ r = TEMP_FAILURE_RETRY (read (p[0], &b, 1));
close (p[0]);
- reexec_in_user_namespace_wait(r, 0);
+ reexec_in_user_namespace_wait (r, 0);
return r == 1 && b == '0' ? 0 : -1;
}
@@ -426,9 +430,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
_exit (EXIT_FAILURE);
}
- do
- r = write (fd, pid_str, strlen (pid_str));
- while (r < 0 && errno == EINTR);
+ r = TEMP_FAILURE_RETRY (write (fd, pid_str, strlen (pid_str)));
if (r < 0)
{
kill (pid, SIGKILL);
@@ -445,9 +447,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
_exit (EXIT_FAILURE);
}
- do
- r = write (p[1], "0", 1);
- while (r < 0 && errno == EINTR);
+ r = TEMP_FAILURE_RETRY (write (p[1], "0", 1));
close (p[1]);
_exit (EXIT_SUCCESS);
@@ -489,6 +489,7 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path)
char **argv;
int pid;
char *cwd = getcwd (NULL, 0);
+ sigset_t sigset, oldsigset;
if (cwd == NULL)
{
@@ -522,6 +523,22 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path)
return pid;
}
+ if (sigfillset (&sigset) < 0)
+ {
+ fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+ if (sigdelset (&sigset, SIGCHLD) < 0)
+ {
+ fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+ if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0)
+ {
+ fprintf (stderr, "cannot block signals: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1);
setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1);
setenv ("_CONTAINERS_ROOTLESS_GID", gid, 1);
@@ -570,6 +587,11 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path)
/* We ignore errors here as we didn't create the namespace anyway. */
create_pause_process (pause_pid_file_path, argv);
}
+ if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0)
+ {
+ fprintf (stderr, "cannot block signals: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
execvp (argv[0], argv);
@@ -609,9 +631,7 @@ copy_file_to_fd (const char *file_to_read, int outfd)
{
ssize_t r, w, t = 0;
- do
- r = read (fd, buf, sizeof buf);
- while (r < 0 && errno == EINTR);
+ r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf));
if (r < 0)
{
close (fd);
@@ -623,9 +643,7 @@ copy_file_to_fd (const char *file_to_read, int outfd)
while (t < r)
{
- do
- w = write (outfd, &buf[t], r - t);
- while (w < 0 && errno == EINTR);
+ w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t));
if (w < 0)
{
close (fd);
@@ -734,9 +752,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1);
setenv ("_CONTAINERS_ROOTLESS_GID", gid, 1);
- do
- ret = read (ready, &b, 1) < 0;
- while (ret < 0 && errno == EINTR);
+ ret = TEMP_FAILURE_RETRY (read (ready, &b, 1));
if (ret < 0)
{
fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno));
@@ -748,21 +764,21 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
if (syscall_setresgid (0, 0, 0) < 0)
{
fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
- write (ready, "1", 1);
+ TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE);
}
if (syscall_setresuid (0, 0, 0) < 0)
{
fprintf (stderr, "cannot setresuid: %s\n", strerror (errno));
- write (ready, "1", 1);
+ TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE);
}
if (chdir (cwd) < 0)
{
fprintf (stderr, "cannot chdir: %s\n", strerror (errno));
- write (ready, "1", 1);
+ TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE);
}
free (cwd);
@@ -771,14 +787,12 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
{
if (create_pause_process (pause_pid_file_path, argv) < 0)
{
- write (ready, "2", 1);
+ TEMP_FAILURE_RETRY (write (ready, "2", 1));
_exit (EXIT_FAILURE);
}
}
- do
- ret = write (ready, "0", 1) < 0;
- while (ret < 0 && errno == EINTR);
+ ret = TEMP_FAILURE_RETRY (write (ready, "0", 1));
close (ready);
if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0)
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index dcc149b55..e221b5cb5 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -797,7 +797,7 @@ func initFSMounts(inputMounts []spec.Mount) []spec.Mount {
if m.Type == TypeBind {
m.Options = util.ProcessOptions(m.Options)
}
- if m.Type == TypeTmpfs {
+ if m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev" {
m.Options = append(m.Options, "tmpcopyup")
}
mounts = append(mounts, m)
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index 2234899a5..8051f07be 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -60,7 +60,10 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
if !start && state != libpod.ContainerStateRunning {
return call.ReplyErrorOccurred("container must be running to attach")
}
- call.Reply(nil)
+
+ // ACK the client upgrade request
+ call.ReplyAttach()
+
reader, writer, _, pw, streams := setupStreams(call)
go func() {
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index fa1a0a109..1abc4f086 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -371,7 +371,6 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compr
done = true
default:
if !call.WantsMore() {
- time.Sleep(1 * time.Second)
break
}
br := iopodman.MoreResponse{
@@ -495,6 +494,9 @@ func (i *LibpodAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error {
// Commit ...
func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error {
+ var newImage *image.Image
+
+ output := bytes.NewBuffer([]byte{})
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
return call.ReplyContainerNotFound(name, err.Error())
@@ -515,7 +517,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
}
coptions := buildah.CommitOptions{
SignaturePolicyPath: rtc.SignaturePolicyPath,
- ReportWriter: nil,
+ ReportWriter: output,
SystemContext: sc,
PreferredManifestType: mimeType,
}
@@ -527,11 +529,61 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
Author: author,
}
- newImage, err := ctr.Commit(getContext(), imageName, options)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ if call.WantsMore() {
+ call.Continues = true
}
- return call.ReplyCommit(newImage.ID())
+
+ c := make(chan error)
+
+ go func() {
+ newImage, err = ctr.Commit(getContext(), imageName, options)
+ if err != nil {
+ c <- err
+ }
+ c <- nil
+ close(c)
+ }()
+
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during commit failed for %s", name)
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyCommit(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
+ }
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: newImage.ID(),
+ }
+
+ return call.ReplyCommit(br)
}
// ImportImage imports an image from a tarball to the image store
@@ -633,7 +685,6 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
done = true
default:
if !call.WantsMore() {
- time.Sleep(1 * time.Second)
break
}
br := iopodman.MoreResponse{
@@ -764,7 +815,6 @@ func (i *LibpodAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageS
done = true
default:
if !call.WantsMore() {
- time.Sleep(1 * time.Second)
break
}
br := iopodman.MoreResponse{
@@ -844,7 +894,6 @@ func (i *LibpodAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string,
done = true
default:
if !call.WantsMore() {
- time.Sleep(1 * time.Second)
break
}
br := iopodman.MoreResponse{
diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go
index 96f76bcdc..24a91a86f 100644
--- a/pkg/varlinkapi/transfers.go
+++ b/pkg/varlinkapi/transfers.go
@@ -29,6 +29,12 @@ func (i *LibpodAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int
return call.ReplyErrorOccurred(err.Error())
}
+ // FIXME return parameter
+ if err = call.ReplySendFile("FIXME_file_handle"); err != nil {
+ // If an error occurs while sending the reply, return the error
+ return err
+ }
+
writer := bufio.NewWriter(outputFile)
defer writer.Flush()
@@ -60,9 +66,10 @@ func (i *LibpodAPI) ReceiveFile(call iopodman.VarlinkCall, filepath string, dele
}
// Send the file length down to client
- // Varlink connection upraded
+ // Varlink connection upgraded
if err = call.ReplyReceiveFile(fileInfo.Size()); err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ // If an error occurs while sending the reply, return the error
+ return err
}
reader := bufio.NewReader(fs)
diff --git a/pkg/varlinkapi/virtwriter/virtwriter.go b/pkg/varlinkapi/virtwriter/virtwriter.go
index 3adaf6e17..e747984c7 100644
--- a/pkg/varlinkapi/virtwriter/virtwriter.go
+++ b/pkg/varlinkapi/virtwriter/virtwriter.go
@@ -91,65 +91,65 @@ func (v VirtWriteCloser) Write(input []byte) (int, error) {
// Reader decodes the content that comes over the wire and directs it to the proper destination.
func Reader(r *bufio.Reader, output, errput *os.File, input *io.PipeWriter, resize chan remotecommand.TerminalSize) error {
- var saveb []byte
- var eom int
+ var messageSize int64
+ headerBytes := make([]byte, 8)
+
for {
- readb := make([]byte, 32*1024)
- n, err := r.Read(readb)
- // TODO, later may be worth checking in len of the read is 0
+ n, err := io.ReadFull(r, headerBytes)
if err != nil {
return err
}
- b := append(saveb, readb[0:n]...)
- // no sense in reading less than the header len
- for len(b) > 7 {
- eom = int(binary.BigEndian.Uint32(b[4:8])) + 8
- // The message and header are togther
- if len(b) >= eom {
- out := append([]byte{}, b[8:eom]...)
-
- switch IntToSocketDest(int(b[0])) {
- case ToStdout:
- n, err := output.Write(out)
- if err != nil {
- return err
- }
- if n < len(out) {
- return errors.New("short write error occurred on stdout")
- }
- case ToStderr:
- n, err := errput.Write(out)
- if err != nil {
- return err
- }
- if n < len(out) {
- return errors.New("short write error occurred on stderr")
- }
- case ToStdin:
- n, err := input.Write(out)
- if err != nil {
- return err
- }
- if n < len(out) {
- return errors.New("short write error occurred on stdin")
- }
- case TerminalResize:
- // Resize events come over in bytes, need to be reserialized
- resizeEvent := remotecommand.TerminalSize{}
- if err := json.Unmarshal(out, &resizeEvent); err != nil {
- return err
- }
- resize <- resizeEvent
- case Quit:
- return nil
+ if n < 8 {
+ return errors.New("short read and no full header read")
+ }
+
+ messageSize = int64(binary.BigEndian.Uint32(headerBytes[4:8]))
+
+ switch IntToSocketDest(int(headerBytes[0])) {
+ case ToStdout:
+ _, err := io.CopyN(output, r, messageSize)
+ if err != nil {
+ return err
+ }
+ case ToStderr:
+ _, err := io.CopyN(errput, r, messageSize)
+ if err != nil {
+ return err
+ }
+ case ToStdin:
+ _, err := io.CopyN(input, r, messageSize)
+ if err != nil {
+ return err
+ }
+ case TerminalResize:
+ out := make([]byte, messageSize)
+ if messageSize > 0 {
+ _, err = io.ReadFull(r, out)
+
+ if err != nil {
+ return err
}
- b = b[eom:]
- } else {
- // We do not have the header and full message, need to slurp again
- saveb = b
- break
}
+ // Resize events come over in bytes, need to be reserialized
+ resizeEvent := remotecommand.TerminalSize{}
+ if err := json.Unmarshal(out, &resizeEvent); err != nil {
+ return err
+ }
+ resize <- resizeEvent
+ case Quit:
+ out := make([]byte, messageSize)
+ if messageSize > 0 {
+ _, err = io.ReadFull(r, out)
+
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+
+ default:
+ // Something really went wrong
+ return errors.New("Unknown multiplex destination")
}
}
- return nil
}