summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/commands.go2
-rw-r--r--cmd/podman/container.go1
-rw-r--r--cmd/podman/create.go2
-rw-r--r--cmd/podman/export.go51
-rw-r--r--cmd/podman/image.go1
-rw-r--r--cmd/podman/import.go77
-rw-r--r--cmd/podman/main.go2
-rw-r--r--cmd/podman/play_kube.go2
-rw-r--r--cmd/podman/pull.go2
-rw-r--r--cmd/podman/runlabel.go2
-rw-r--r--cmd/podman/shared/container.go2
-rw-r--r--cmd/podman/sign.go2
-rw-r--r--cmd/podman/varlink/io.podman.varlink5
-rw-r--r--contrib/perftest/main.go2
-rw-r--r--docs/podman-container-runlabel.1.md3
-rw-r--r--libpod/adapter/client.go11
-rw-r--r--libpod/adapter/runtime.go55
-rw-r--r--libpod/adapter/runtime_remote.go86
-rw-r--r--libpod/image/image.go4
-rw-r--r--libpod/image/image_test.go8
-rw-r--r--libpod/image/pull.go44
-rw-r--r--libpod/runtime_ctr.go43
-rw-r--r--libpod/runtime_img.go79
-rw-r--r--libpod/runtime_pod_infra_linux.go2
-rw-r--r--pkg/varlinkapi/containers.go17
-rw-r--r--pkg/varlinkapi/containers_create.go2
-rw-r--r--pkg/varlinkapi/images.go16
-rw-r--r--pkg/varlinkapi/transfers.go75
-rw-r--r--test/e2e/export_test.go3
-rw-r--r--test/e2e/runlabel_test.go11
-rw-r--r--vendor.conf2
-rw-r--r--vendor/github.com/containers/buildah/imagebuildah/build.go17
-rw-r--r--vendor/github.com/varlink/go/varlink/bridge.go21
-rw-r--r--vendor/github.com/varlink/go/varlink/bridge_windows.go17
-rw-r--r--vendor/github.com/varlink/go/varlink/call.go21
-rw-r--r--vendor/github.com/varlink/go/varlink/connection.go84
-rw-r--r--vendor/github.com/varlink/go/varlink/orgvarlinkservice.go53
-rw-r--r--vendor/github.com/varlink/go/varlink/service.go14
38 files changed, 637 insertions, 204 deletions
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index 718717009..d8fdd556f 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -12,8 +12,6 @@ func getAppCommands() []cli.Command {
createCommand,
diffCommand,
execCommand,
- exportCommand,
- importCommand,
killCommand,
kubeCommand,
loadCommand,
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index acbcbb644..29300a6a4 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -8,6 +8,7 @@ import (
var (
containerSubCommands = []cli.Command{
+ exportCommand,
inspectCommand,
}
containerDescription = "Manage containers"
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index c56efa153..2d85abd35 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -134,7 +134,7 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container
writer = os.Stderr
}
- newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false)
+ newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil)
if err != nil {
return nil, nil, err
}
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index c0e63bd2a..eaa4e38a2 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -1,12 +1,9 @@
package main
import (
- "io/ioutil"
"os"
- "strconv"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -43,7 +40,7 @@ func exportCmd(c *cli.Context) error {
rootless.SetSkipStorageSetup(true)
}
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
@@ -58,52 +55,18 @@ func exportCmd(c *cli.Context) error {
}
output := c.String("output")
+ if runtime.Remote && (output == "/dev/stdout" || len(output) == 0) {
+ return errors.New("remote client usage must specify an output file (-o)")
+ }
if output == "/dev/stdout" {
file := os.Stdout
if logrus.IsTerminal(file) {
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
}
}
+
if err := validateFileName(output); err != nil {
return err
}
-
- ctr, err := runtime.LookupContainer(args[0])
- if err != nil {
- return errors.Wrapf(err, "error looking up container %q", args[0])
- }
-
- if os.Geteuid() != 0 {
- state, err := ctr.State()
- if err != nil {
- return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
- }
- if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
- data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
- if err != nil {
- return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
- }
- conmonPid, err := strconv.Atoi(string(data))
- if err != nil {
- return errors.Wrapf(err, "cannot parse PID %q", data)
- }
- became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- } else {
- became, ret, err := rootless.BecomeRootInUserNS()
- if err != nil {
- return err
- }
- if became {
- os.Exit(ret)
- }
- }
- }
-
- return ctr.Export(output)
+ return runtime.Export(args[0], c.String("output"))
}
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index a51a90b0e..6b451a1ca 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -8,6 +8,7 @@ import (
var (
imageSubCommands = []cli.Command{
+ importCommand,
historyCommand,
imageExistsCommand,
inspectCommand,
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index 144354fa6..661bd5a65 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -2,16 +2,8 @@ package main
import (
"fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/util"
- "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
@@ -51,7 +43,7 @@ func importCmd(c *cli.Context) error {
return err
}
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
@@ -60,7 +52,6 @@ func importCmd(c *cli.Context) error {
var (
source string
reference string
- writer io.Writer
)
args := c.Args()
@@ -80,67 +71,13 @@ func importCmd(c *cli.Context) error {
return err
}
- changes := v1.ImageConfig{}
- if c.IsSet("change") || c.IsSet("c") {
- changes, err = util.GetImageConfig(c.StringSlice("change"))
- if err != nil {
- return errors.Wrapf(err, "error adding config changes to image %q", source)
- }
+ quiet := c.Bool("quiet")
+ if runtime.Remote {
+ quiet = false
}
-
- history := []v1.History{
- {Comment: c.String("message")},
- }
-
- config := v1.Image{
- Config: changes,
- History: history,
- }
-
- writer = nil
- if !c.Bool("quiet") {
- writer = os.Stderr
- }
-
- // if source is a url, download it and save to a temp file
- u, err := url.ParseRequestURI(source)
- if err == nil && u.Scheme != "" {
- file, err := downloadFromURL(source)
- if err != nil {
- return err
- }
- defer os.Remove(file)
- source = file
- }
-
- newImage, err := runtime.ImageRuntime().Import(getContext(), source, reference, writer, image.SigningOptions{}, config)
+ iid, err := runtime.Import(getContext(), source, reference, c.StringSlice("change"), c.String("message"), quiet)
if err == nil {
- fmt.Println(newImage.ID())
+ fmt.Println(iid)
}
return err
}
-
-// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
-// and temporarily saves in it /var/tmp/importxyz, which is deleted after the image is imported
-func downloadFromURL(source string) (string, error) {
- fmt.Printf("Downloading from %q\n", source)
-
- outFile, err := ioutil.TempFile("/var/tmp", "import")
- if err != nil {
- return "", errors.Wrap(err, "error creating file")
- }
- defer outFile.Close()
-
- response, err := http.Get(source)
- if err != nil {
- return "", errors.Wrapf(err, "error downloading %q", source)
- }
- defer response.Body.Close()
-
- _, err = io.Copy(outFile, response.Body)
- if err != nil {
- return "", errors.Wrapf(err, "error saving %s to %s", source, outFile.Name())
- }
-
- return outFile.Name(), nil
-}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index c10590006..1ca8882eb 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -88,9 +88,11 @@ func main() {
app.Commands = []cli.Command{
containerCommand,
+ exportCommand,
historyCommand,
imageCommand,
imagesCommand,
+ importCommand,
infoCommand,
inspectCommand,
pullCommand,
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 2ce2e21bb..4753dd0a6 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -146,7 +146,7 @@ func playKubeYAMLCmd(c *cli.Context) error {
}
for _, container := range podYAML.Spec.Containers {
- newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false)
+ newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil)
if err != nil {
return err
}
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 2a78d0c54..f70e5cded 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -123,7 +123,7 @@ func pullCmd(c *cli.Context) error {
imgID = newImage[0].ID()
} else {
authfile := getAuthFile(c.String("authfile"))
- newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true)
+ newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true, nil)
if err != nil {
return errors.Wrapf(err, "error pulling image %q", image)
}
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index 48a296260..b16a93fd9 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -166,7 +166,7 @@ func runlabelCmd(c *cli.Context) error {
return err
}
if runLabel == "" {
- return nil
+ return errors.Errorf("%s does not have a label of %s", runlabelImage, label)
}
cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, c.String("name"), opts, extraArgs)
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 9040c4a5c..f84fb8261 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -609,7 +609,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim
registryCreds = creds
}
dockerRegistryOptions.DockerRegistryCreds = registryCreds
- newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false)
+ newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false, &label)
} else {
newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage)
}
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index 1d9aecdc9..22aa07230 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -104,7 +104,7 @@ func signCmd(c *cli.Context) error {
}
// create the signstore file
- newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false)
+ newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false, nil)
if err != nil {
return errors.Wrapf(err, "error pulling image %s", signimage)
}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 8b02057a1..101232b0c 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -688,7 +688,7 @@ method Commit(name: string, image_name: string, changes: []string, author: strin
# ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
# descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
-method ImportImage(source: string, reference: string, message: string, changes: []string) -> (image: string)
+method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string)
# ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also
# a booleon option to force compression. It also takes in a string array of tags to be able to save multiple
@@ -1050,6 +1050,9 @@ method ContainerInspectData(name: string) -> (config: string)
# development of Podman only and generally should not be used.
method ContainerStateData(name: string) -> (config: string)
+method SendFile(type: string, length: int) -> (file_handle: string)
+method ReceiveFile(path: string, delete: bool) -> (len: int)
+
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
error ImageNotFound (name: string)
diff --git a/contrib/perftest/main.go b/contrib/perftest/main.go
index 0d0947890..6a6725ab9 100644
--- a/contrib/perftest/main.go
+++ b/contrib/perftest/main.go
@@ -103,7 +103,7 @@ func main() {
}
fmt.Printf("image %s not found locally, fetching from remote registry..\n", *testImageName)
- testImage, err = client.ImageRuntime().New(ctx, *testImageName, "", "", writer, &dockerRegistryOptions, image2.SigningOptions{}, false)
+ testImage, err = client.ImageRuntime().New(ctx, *testImageName, "", "", writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil)
if err != nil {
logrus.Fatal(err)
}
diff --git a/docs/podman-container-runlabel.1.md b/docs/podman-container-runlabel.1.md
index 6f7b4dae8..c5d7a278f 100644
--- a/docs/podman-container-runlabel.1.md
+++ b/docs/podman-container-runlabel.1.md
@@ -26,6 +26,9 @@ If the container image has a LABEL INSTALL instruction like the following:
`podman container runlabel` will set the following environment variables for use in the command:
+If the container image does not have the desired label, an error message will be displayed along with a non-zero
+return code.
+
Note: Podman will always ensure that `podman` is the first argument of the command being executed.
**LABEL**
diff --git a/libpod/adapter/client.go b/libpod/adapter/client.go
index b3bb9acae..6512a5952 100644
--- a/libpod/adapter/client.go
+++ b/libpod/adapter/client.go
@@ -34,3 +34,14 @@ func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
}
return connection, nil
}
+
+// RefreshConnection is used to replace the current r.Conn after things like
+// using an upgraded varlink connection
+func (r RemoteRuntime) RefreshConnection() error {
+ newConn, err := r.Connect()
+ if err != nil {
+ return err
+ }
+ r.Conn = newConn
+ return nil
+}
diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go
index f4961437e..2c408dd2f 100644
--- a/libpod/adapter/runtime.go
+++ b/libpod/adapter/runtime.go
@@ -4,12 +4,17 @@ package adapter
import (
"context"
+ "github.com/pkg/errors"
"io"
+ "io/ioutil"
+ "os"
+ "strconv"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/urfave/cli"
)
@@ -78,8 +83,8 @@ func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef type
}
// New calls into local storage to look for an image in local storage or to pull it
-func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) {
- img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull)
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) {
+ img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull, label)
if err != nil {
return nil, err
}
@@ -104,3 +109,49 @@ func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
return r.ImageRuntime().PruneImages(all)
}
+
+// Export is a wrapper to container export to a tarfile
+func (r *LocalRuntime) Export(name string, path string) error {
+ ctr, err := r.Runtime.LookupContainer(name)
+ if err != nil {
+ return errors.Wrapf(err, "error looking up container %q", name)
+ }
+ if os.Geteuid() != 0 {
+ state, err := ctr.State()
+ if err != nil {
+ return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
+ }
+ if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ } else {
+ became, ret, err := rootless.BecomeRootInUserNS()
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ }
+ }
+
+ return ctr.Export(path)
+}
+
+// Import is a wrapper to import a container image
+func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
+ return r.Runtime.Import(ctx, source, reference, changes, history, quiet)
+}
diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go
index f184ce0a9..07c786184 100644
--- a/libpod/adapter/runtime_remote.go
+++ b/libpod/adapter/runtime_remote.go
@@ -3,10 +3,13 @@
package adapter
import (
+ "bufio"
"context"
"encoding/json"
"fmt"
+ "github.com/pkg/errors"
"io"
+ "os"
"strings"
"time"
@@ -156,7 +159,10 @@ func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef type
}
// New calls into local storage to look for an image in local storage or to pull it
-func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) {
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) {
+ if label != nil {
+ return nil, errors.New("the remote client function does not support checking a remote image for a label")
+ }
// TODO Creds needs to be figured out here too, like above
tlsBool := dockeroptions.DockerInsecureSkipTLSVerify
// Remember SkipTlsVerify is the opposite of tlsverify
@@ -320,6 +326,84 @@ func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
return &data
}
+
+// PruneImages is the wrapper call for a remote-client to prune images
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
return iopodman.ImagesPrune().Call(r.Conn, all)
}
+
+// Export is a wrapper to container export to a tarfile
+func (r *LocalRuntime) Export(name string, path string) error {
+ tempPath, err := iopodman.ExportContainer().Call(r.Conn, name, "")
+ if err != nil {
+ return err
+ }
+
+ outputFile, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer outputFile.Close()
+
+ writer := bufio.NewWriter(outputFile)
+ defer writer.Flush()
+
+ reply, err := iopodman.ReceiveFile().Send(r.Conn, varlink.Upgrade, tempPath, true)
+ if err != nil {
+ return err
+ }
+
+ length, _, err := reply()
+ if err != nil {
+ return errors.Wrap(err, "unable to get file length for transfer")
+ }
+
+ reader := r.Conn.Reader
+ if _, err := io.CopyN(writer, reader, length); err != nil {
+ return errors.Wrap(err, "file transer failed")
+ }
+
+ return nil
+}
+
+// Import implements the remote calls required to import a container image to the store
+func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
+ // First we send the file to the host
+ fs, err := os.Open(source)
+ if err != nil {
+ return "", err
+ }
+
+ fileInfo, err := fs.Stat()
+ if err != nil {
+ return "", err
+ }
+ reply, err := iopodman.SendFile().Send(r.Conn, varlink.Upgrade, "", int64(fileInfo.Size()))
+ if err != nil {
+ return "", err
+ }
+ _, _, err = reply()
+ if err != nil {
+ return "", err
+ }
+
+ reader := bufio.NewReader(fs)
+ _, err = reader.WriteTo(r.Conn.Writer)
+ if err != nil {
+ return "", err
+ }
+ r.Conn.Writer.Flush()
+
+ // All was sent, wait for the ACK from the server
+ tempFile, err := r.Conn.Reader.ReadString(':')
+ if err != nil {
+ return "", err
+ }
+
+ // r.Conn is kaput at this point due to the upgrade
+ if err := r.RemoteRuntime.RefreshConnection(); err != nil {
+ return "", err
+
+ }
+ return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true)
+}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index a32336f49..739372e77 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -125,7 +125,7 @@ func (ir *Runtime) NewFromLocal(name string) (*Image, error) {
// New creates a new image object where the image could be local
// or remote
-func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull bool) (*Image, error) {
+func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull bool, label *string) (*Image, error) {
// We don't know if the image is local or not ... check local first
newImage := Image{
InputName: name,
@@ -145,7 +145,7 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
if signaturePolicyPath == "" {
signaturePolicyPath = ir.SignaturePolicyPath
}
- imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions)
+ imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions, label)
if err != nil {
return nil, errors.Wrapf(err, "unable to pull %s", name)
}
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index 077ae460e..075ba119d 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -87,9 +87,9 @@ func TestImage_NewFromLocal(t *testing.T) {
// Need images to be present for this test
ir, err := NewImageRuntimeFromOptions(so)
assert.NoError(t, err)
- bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false)
+ bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false, nil)
assert.NoError(t, err)
- bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false)
+ bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false, nil)
assert.NoError(t, err)
tm, err := makeLocalMatrix(bb, bbglibc)
@@ -136,7 +136,7 @@ func TestImage_New(t *testing.T) {
// Iterate over the names and delete the image
// after the pull
for _, img := range names {
- newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false)
+ newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false, nil)
assert.NoError(t, err)
assert.NotEqual(t, newImage.ID(), "")
err = newImage.Remove(false)
@@ -164,7 +164,7 @@ func TestImage_MatchRepoTag(t *testing.T) {
}
ir, err := NewImageRuntimeFromOptions(so)
assert.NoError(t, err)
- newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false)
+ newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false, nil)
assert.NoError(t, err)
err = newImage.TagImage("foo:latest")
assert.NoError(t, err)
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index 434b83520..6fef96e37 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ "strings"
cp "github.com/containers/image/copy"
"github.com/containers/image/directory"
@@ -192,7 +193,7 @@ func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types.
// pullImageFromHeuristicSource pulls an image based on inputName, which is heuristically parsed and may involve configured registries.
// Use pullImageFromReference if the source is known precisely.
-func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) {
+func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, label *string) ([]string, error) {
var goal *pullGoal
sc := GetSystemContext(signaturePolicyPath, authfile, false)
srcRef, err := alltransports.ParseImageName(inputName)
@@ -208,7 +209,7 @@ func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName s
return nil, errors.Wrapf(err, "error determining pull goal for image %q", inputName)
}
}
- return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions)
+ return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, label)
}
// pullImageFromReference pulls an image from a types.imageReference.
@@ -218,11 +219,11 @@ func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.Imag
if err != nil {
return nil, errors.Wrapf(err, "error determining pull goal for image %q", transports.ImageName(srcRef))
}
- return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions)
+ return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, nil)
}
// doPullImage is an internal helper interpreting pullGoal. Almost everyone should call one of the callers of doPullImage instead.
-func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) {
+func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, label *string) ([]string, error) {
policyContext, err := getPolicyContext(sc)
if err != nil {
return nil, err
@@ -230,8 +231,12 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
defer policyContext.Destroy()
systemRegistriesConfPath := registries.SystemRegistriesConfPath()
- var images []string
- var pullErrors *multierror.Error
+
+ var (
+ images []string
+ pullErrors *multierror.Error
+ )
+
for _, imageInfo := range goal.refPairs {
copyOptions := getCopyOptions(sc, writer, dockerOptions, nil, signingOptions, "", nil)
copyOptions.SourceCtx.SystemRegistriesConfPath = systemRegistriesConfPath // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
@@ -239,6 +244,13 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) {
io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image))
}
+ // If the label is not nil, check if the label exists and if not, return err
+ if label != nil {
+ if err := checkRemoteImageForLabel(ctx, *label, imageInfo, sc); err != nil {
+ return nil, err
+ }
+ }
+
_, err = cp.Image(ctx, policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions)
if err != nil {
pullErrors = multierror.Append(pullErrors, err)
@@ -314,3 +326,23 @@ func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (*pullG
searchedRegistries: searchRegistries,
}, nil
}
+
+// checkRemoteImageForLabel checks if the remote image has a specific label. if the label exists, we
+// return nil, else we return an error
+func checkRemoteImageForLabel(ctx context.Context, label string, imageInfo pullRefPair, sc *types.SystemContext) error {
+ labelImage, err := imageInfo.srcRef.NewImage(ctx, sc)
+ if err != nil {
+ return err
+ }
+ remoteInspect, err := labelImage.Inspect(ctx)
+ if err != nil {
+ return err
+ }
+ // Labels are case insensitive; so we iterate instead of simple lookup
+ for k := range remoteInspect.Labels {
+ if strings.ToLower(label) == strings.ToLower(k) {
+ return nil
+ }
+ }
+ return errors.Errorf("%s has no label %s", imageInfo.image, label)
+}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 6d5ce5a7e..9afdef7b6 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -2,9 +2,11 @@ package libpod
import (
"context"
+ "io/ioutil"
"os"
"path"
"path/filepath"
+ "strconv"
"strings"
"time"
@@ -521,3 +523,44 @@ func isNamedVolume(volName string) bool {
}
return false
}
+
+// Export is the libpod portion of exporting a container to a tar file
+func (r *Runtime) Export(name string, path string) error {
+ ctr, err := r.LookupContainer(name)
+ if err != nil {
+ return err
+ }
+ if os.Geteuid() != 0 {
+ state, err := ctr.State()
+ if err != nil {
+ return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
+ }
+ if state == ContainerStateRunning || state == ContainerStatePaused {
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ } else {
+ became, ret, err := rootless.BecomeRootInUserNS()
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ }
+ }
+ return ctr.Export(path)
+
+}
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index 66844bb31..c20aa77a3 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -3,9 +3,16 @@ package libpod
import (
"context"
"fmt"
+ "github.com/opencontainers/image-spec/specs-go/v1"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
"github.com/containers/buildah/imagebuildah"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
)
@@ -132,3 +139,75 @@ func (r *Runtime) Build(ctx context.Context, options imagebuildah.BuildOptions,
_, _, err := imagebuildah.BuildDockerfiles(ctx, r.store, options, dockerfiles...)
return err
}
+
+// Import is called as an intermediary to the image library Import
+func (r *Runtime) Import(ctx context.Context, source string, reference string, changes []string, history string, quiet bool) (string, error) {
+ var (
+ writer io.Writer
+ err error
+ )
+
+ ic := v1.ImageConfig{}
+ if len(changes) > 0 {
+ ic, err = util.GetImageConfig(changes)
+ if err != nil {
+ return "", errors.Wrapf(err, "error adding config changes to image %q", source)
+ }
+ }
+
+ hist := []v1.History{
+ {Comment: history},
+ }
+
+ config := v1.Image{
+ Config: ic,
+ History: hist,
+ }
+
+ writer = nil
+ if !quiet {
+ writer = os.Stderr
+ }
+
+ // if source is a url, download it and save to a temp file
+ u, err := url.ParseRequestURI(source)
+ if err == nil && u.Scheme != "" {
+ file, err := downloadFromURL(source)
+ if err != nil {
+ return "", err
+ }
+ defer os.Remove(file)
+ source = file
+ }
+
+ newImage, err := r.imageRuntime.Import(ctx, source, reference, writer, image.SigningOptions{}, config)
+ if err != nil {
+ return "", err
+ }
+ return newImage.ID(), nil
+}
+
+// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
+// and temporarily saves in it /var/tmp/importxyz, which is deleted after the image is imported
+func downloadFromURL(source string) (string, error) {
+ fmt.Printf("Downloading from %q\n", source)
+
+ outFile, err := ioutil.TempFile("/var/tmp", "import")
+ if err != nil {
+ return "", errors.Wrap(err, "error creating file")
+ }
+ defer outFile.Close()
+
+ response, err := http.Get(source)
+ if err != nil {
+ return "", errors.Wrapf(err, "error downloading %q", source)
+ }
+ defer response.Body.Close()
+
+ _, err = io.Copy(outFile, response.Body)
+ if err != nil {
+ return "", errors.Wrapf(err, "error saving %s to %s", source, outFile.Name())
+ }
+
+ return outFile.Name(), nil
+}
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 5e1051150..4f221764a 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -67,7 +67,7 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container,
return nil, ErrRuntimeStopped
}
- newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false)
+ newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index a01e3cc2b..737e2dd96 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"os"
"syscall"
"time"
@@ -194,15 +195,25 @@ func (i *LibpodAPI) ListContainerChanges(call iopodman.VarlinkCall, name string)
}
// ExportContainer ...
-func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, path string) error {
+func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
return call.ReplyContainerNotFound(name)
}
- if err := ctr.Export(path); err != nil {
+ outputFile, err := ioutil.TempFile("", "varlink_recv")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ defer outputFile.Close()
+ if outPath == "" {
+ outPath = outputFile.Name()
+ }
+ if err := ctr.Export(outPath); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
- return call.ReplyExportContainer(path)
+ return call.ReplyExportContainer(outPath)
+
}
// GetContainerStats ...
diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go
index d72eaeb18..cc707b11f 100644
--- a/pkg/varlinkapi/containers_create.go
+++ b/pkg/varlinkapi/containers_create.go
@@ -25,7 +25,7 @@ func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.C
rtc := i.Runtime.GetConfig()
ctx := getContext()
- newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false)
+ newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index d6a9b7301..5e0889645 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -500,7 +500,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
}
// ImportImage imports an image from a tarball to the image store
-func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string) error {
+func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string, delete bool) error {
configChanges, err := util.GetImageConfig(changes)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -516,6 +516,12 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
+ if delete {
+ if err := os.Remove(source); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ }
+
return call.ReplyImportImage(newImage.ID())
}
@@ -573,7 +579,7 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, c
}
imageID = newImage[0].ID()
} else {
- newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false)
+ newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false, nil)
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error()))
}
@@ -610,15 +616,15 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.
runLabel, imageName, err := shared.GetRunlabel(input.Label, input.Image, ctx, i.Runtime, input.Pull, input.Creds, dockerRegistryOptions, input.Authfile, input.SignaturePolicyPath, nil)
if err != nil {
- return err
+ return call.ReplyErrorOccurred(err.Error())
}
if runLabel == "" {
- return nil
+ return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label))
}
cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs)
if err != nil {
- return err
+ return call.ReplyErrorOccurred(err.Error())
}
if err := utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...); err != nil {
return call.ReplyErrorOccurred(err.Error())
diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go
new file mode 100644
index 000000000..0cb7e5e2e
--- /dev/null
+++ b/pkg/varlinkapi/transfers.go
@@ -0,0 +1,75 @@
+package varlinkapi
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/varlink"
+)
+
+// SendFile allows a client to send a file to the varlink server
+func (i *LibpodAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int64) error {
+ if !call.WantsUpgrade() {
+ return call.ReplyErrorOccurred("client must use upgraded connection to send files")
+ }
+
+ outputFile, err := ioutil.TempFile("", "varlink_send")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ defer outputFile.Close()
+
+ if err = call.ReplySendFile(outputFile.Name()); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ writer := bufio.NewWriter(outputFile)
+ defer writer.Flush()
+
+ reader := call.Call.Reader
+ if _, err := io.CopyN(writer, reader, length); err != nil {
+ return err
+ }
+
+ // Send an ACK to the client
+ call.Call.Writer.WriteString(fmt.Sprintf("%s:", outputFile.Name()))
+ call.Call.Writer.Flush()
+ return nil
+
+}
+
+// ReceiveFile allows the varlink server to send a file to a client
+func (i *LibpodAPI) ReceiveFile(call iopodman.VarlinkCall, filepath string, delete bool) error {
+ if !call.WantsUpgrade() {
+ return call.ReplyErrorOccurred("client must use upgraded connection to send files")
+ }
+ fs, err := os.Open(filepath)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ fileInfo, err := fs.Stat()
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ // Send the file length down to client
+ // Varlink connection upraded
+ if err = call.ReplyReceiveFile(fileInfo.Size()); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ reader := bufio.NewReader(fs)
+ _, err = reader.WriteTo(call.Writer)
+ if err != nil {
+ return err
+ }
+ if delete {
+ if err := os.Remove(filepath); err != nil {
+ return err
+ }
+ }
+ return call.Writer.Flush()
+}
diff --git a/test/e2e/export_test.go b/test/e2e/export_test.go
index de3f23667..dba0a2255 100644
--- a/test/e2e/export_test.go
+++ b/test/e2e/export_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
@@ -37,6 +35,7 @@ var _ = Describe("Podman export", func() {
})
It("podman export output flag", func() {
+ SkipIfRemote()
_, ec, cid := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go
index 9b4f584b0..49b9e13d8 100644
--- a/test/e2e/runlabel_test.go
+++ b/test/e2e/runlabel_test.go
@@ -68,4 +68,15 @@ var _ = Describe("podman container runlabel", func() {
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
+ It("podman container runlabel bogus label should result in non-zero exit code", func() {
+ result := podmanTest.Podman([]string{"container", "runlabel", "RUN", ALPINE})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).ToNot(Equal(0))
+ })
+ It("podman container runlabel bogus label in remote image should result in non-zero exit", func() {
+ result := podmanTest.Podman([]string{"container", "runlabel", "RUN", "docker.io/library/ubuntu:latest"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).ToNot(Equal(0))
+
+ })
})
diff --git a/vendor.conf b/vendor.conf
index 4a62c6be7..ce3ca9d44 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -91,7 +91,7 @@ k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apim
k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
github.com/varlink/go 92687ab4eb68d99e43b1f5b93477ad76bb54f811
-github.com/containers/buildah e7ca330f923701dba8859f5c014d0a9a3f7f0a49
+github.com/containers/buildah 2406e4acaa00938b8324a0ef3caadbe5668ec896
# TODO: Gotty has not been updated since 2012. Can we find replacement?
github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512
# do not go beyond the below commit as the next one requires a more recent
diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go
index 217bcfc79..56ab7aa57 100644
--- a/vendor/github.com/containers/buildah/imagebuildah/build.go
+++ b/vendor/github.com/containers/buildah/imagebuildah/build.go
@@ -1311,13 +1311,17 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (strin
// Check if we have a one line Dockerfile making layers irrelevant
// or the user told us to ignore layers.
- ignoreLayers := (len(stages) < 2 && len(stages[0].Node.Children) < 2) || (!b.layers && !b.noCache)
+ singleLineDockerfile := (len(stages) < 2 && len(stages[0].Node.Children) < 1)
+ ignoreLayers := singleLineDockerfile || !b.layers && !b.noCache
if ignoreLayers {
imgID, ref, err := stageExecutor.Commit(ctx, stages[len(stages)-1].Builder, "")
if err != nil {
return "", nil, err
}
+ if singleLineDockerfile {
+ b.log("COMMIT %s", ref)
+ }
imageID = imgID
imageRef = ref
}
@@ -1527,6 +1531,17 @@ func (b *Executor) deleteSuccessfulIntermediateCtrs() error {
return lastErr
}
+func (b *Executor) EnsureContainerPath(path string) error {
+ _, err := os.Stat(filepath.Join(b.mountPoint, path))
+ if err != nil && os.IsNotExist(err) {
+ err = os.MkdirAll(filepath.Join(b.mountPoint, path), 0755)
+ }
+ if err != nil {
+ return errors.Wrapf(err, "error ensuring container path %q", path)
+ }
+ return nil
+}
+
// preprocessDockerfileContents runs CPP(1) in preprocess-only mode on the input
// dockerfile content and will use ctxDir as the base include path.
//
diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go
index b20c0925a..0ea5de682 100644
--- a/vendor/github.com/varlink/go/varlink/bridge.go
+++ b/vendor/github.com/varlink/go/varlink/bridge.go
@@ -5,13 +5,13 @@ package varlink
import (
"bufio"
"io"
- "log"
"net"
"os/exec"
)
type PipeCon struct {
net.Conn
+ cmd *exec.Cmd
reader *io.ReadCloser
writer *io.WriteCloser
}
@@ -25,6 +25,8 @@ func (p PipeCon) Close() error {
if err2 != nil {
return err2
}
+ p.cmd.Wait()
+
return nil
}
@@ -42,18 +44,15 @@ func NewBridge(bridge string) (*Connection, error) {
if err != nil {
return nil, err
}
- c.conn = PipeCon{nil, &r, &w}
+ c.conn = PipeCon{nil, cmd, &r, &w}
c.address = ""
- c.reader = bufio.NewReader(r)
- c.writer = bufio.NewWriter(w)
+ c.Reader = bufio.NewReader(r)
+ c.Writer = bufio.NewWriter(w)
- go func() {
- err := cmd.Run()
- if err != nil {
- log.Fatal(err)
- }
- }()
+ err = cmd.Start()
+ if err != nil {
+ return nil, err
+ }
return &c, nil
}
-
diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go
index 692367a1a..220ae3156 100644
--- a/vendor/github.com/varlink/go/varlink/bridge_windows.go
+++ b/vendor/github.com/varlink/go/varlink/bridge_windows.go
@@ -3,13 +3,13 @@ package varlink
import (
"bufio"
"io"
- "log"
"net"
"os/exec"
)
type PipeCon struct {
net.Conn
+ cmd *exec.Cmd
reader *io.ReadCloser
writer *io.WriteCloser
}
@@ -23,6 +23,8 @@ func (p PipeCon) Close() error {
if err2 != nil {
return err2
}
+ p.cmd.Wait()
+
return nil
}
@@ -40,18 +42,15 @@ func NewBridge(bridge string) (*Connection, error) {
if err != nil {
return nil, err
}
- c.conn = PipeCon{nil, &r, &w}
+ c.conn = PipeCon{nil, cmd, &r, &w}
c.address = ""
c.reader = bufio.NewReader(r)
c.writer = bufio.NewWriter(w)
- go func() {
- err := cmd.Run()
- if err != nil {
- log.Fatal(err)
- }
- }()
+ err = cmd.Start()
+ if err != nil {
+ return nil, err
+ }
return &c, nil
}
-
diff --git a/vendor/github.com/varlink/go/varlink/call.go b/vendor/github.com/varlink/go/varlink/call.go
index 5e9249c0e..d6e046f1d 100644
--- a/vendor/github.com/varlink/go/varlink/call.go
+++ b/vendor/github.com/varlink/go/varlink/call.go
@@ -4,6 +4,7 @@ import (
"bufio"
"encoding/json"
"fmt"
+ "io"
"strings"
)
@@ -11,9 +12,11 @@ import (
// client can be terminated by returning an error from the call instead
// of sending a reply or error reply.
type Call struct {
- writer *bufio.Writer
+ *bufio.Reader
+ *bufio.Writer
in *serviceCall
Continues bool
+ Upgrade bool
}
// WantsMore indicates if the calling client accepts more than one reply to this method call.
@@ -21,6 +24,11 @@ func (c *Call) WantsMore() bool {
return c.in.More
}
+// WantsUpgrade indicates that the calling client wants the connection to be upgraded.
+func (c *Call) WantsUpgrade() bool {
+ return c.in.Upgrade
+}
+
// IsOneway indicate that the calling client does not expect a reply.
func (c *Call) IsOneway() bool {
return c.in.Oneway
@@ -45,11 +53,18 @@ func (c *Call) sendMessage(r *serviceReply) error {
}
b = append(b, 0)
- _, e = c.writer.Write(b)
+ _, e = c.Writer.Write(b)
if e != nil {
+ if e == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
return e
}
- return c.writer.Flush()
+ e = c.Writer.Flush()
+ if e == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return e
}
// Reply sends a reply to this method call.
diff --git a/vendor/github.com/varlink/go/varlink/connection.go b/vendor/github.com/varlink/go/varlink/connection.go
index ac9542408..596caa825 100644
--- a/vendor/github.com/varlink/go/varlink/connection.go
+++ b/vendor/github.com/varlink/go/varlink/connection.go
@@ -4,6 +4,7 @@ import (
"bufio"
"encoding/json"
"fmt"
+ "io"
"net"
"strings"
)
@@ -15,15 +16,59 @@ const (
More = 1 << iota
Oneway = 1 << iota
Continues = 1 << iota
+ Upgrade = 1 << iota
)
// Error is a varlink error returned from a method call.
type Error struct {
- error
Name string
Parameters interface{}
}
+func (e *Error) DispatchError() error {
+ errorRawParameters := e.Parameters.(*json.RawMessage)
+
+ switch e.Name {
+ case "org.varlink.service.InterfaceNotFound":
+ var param InterfaceNotFound
+ if errorRawParameters != nil {
+ err := json.Unmarshal(*errorRawParameters, &param)
+ if err != nil {
+ return e
+ }
+ }
+ return &param
+ case "org.varlink.service.MethodNotFound":
+ var param MethodNotFound
+ if errorRawParameters != nil {
+ err := json.Unmarshal(*errorRawParameters, &param)
+ if err != nil {
+ return e
+ }
+ }
+ return &param
+ case "org.varlink.service.MethodNotImplemented":
+ var param MethodNotImplemented
+ if errorRawParameters != nil {
+ err := json.Unmarshal(*errorRawParameters, &param)
+ if err != nil {
+ return e
+ }
+ }
+ return &param
+ case "org.varlink.service.InvalidParameter":
+ var param InvalidParameter
+ if errorRawParameters != nil {
+ err := json.Unmarshal(*errorRawParameters, &param)
+ if err != nil {
+ return e
+ }
+ }
+ return &param
+ }
+ return e
+}
+
// Error returns the fully-qualified varlink error name.
func (e *Error) Error() string {
return e.Name
@@ -31,10 +76,11 @@ func (e *Error) Error() string {
// Connection is a connection from a client to a service.
type Connection struct {
+ io.Closer
address string
conn net.Conn
- reader *bufio.Reader
- writer *bufio.Writer
+ Reader *bufio.Reader
+ Writer *bufio.Writer
}
// Send sends a method call. It returns a receive() function which is called to retrieve the method reply.
@@ -46,6 +92,7 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
Parameters interface{} `json:"parameters,omitempty"`
More bool `json:"more,omitempty"`
Oneway bool `json:"oneway,omitempty"`
+ Upgrade bool `json:"upgrade,omitempty"`
}
if (flags&More != 0) && (flags&Oneway != 0) {
@@ -55,11 +102,19 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
}
}
+ if (flags&More != 0) && (flags&Upgrade != 0) {
+ return nil, &Error{
+ Name: "org.varlink.InvalidParameter",
+ Parameters: "more",
+ }
+ }
+
m := call{
Method: method,
Parameters: parameters,
More: flags&More != 0,
Oneway: flags&Oneway != 0,
+ Upgrade: flags&Upgrade != 0,
}
b, err := json.Marshal(m)
if err != nil {
@@ -67,13 +122,19 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
}
b = append(b, 0)
- _, err = c.writer.Write(b)
+ _, err = c.Writer.Write(b)
if err != nil {
+ if err == io.EOF {
+ return nil, io.ErrUnexpectedEOF
+ }
return nil, err
}
- err = c.writer.Flush()
+ err = c.Writer.Flush()
if err != nil {
+ if err == io.EOF {
+ return nil, io.ErrUnexpectedEOF
+ }
return nil, err
}
@@ -84,8 +145,11 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
Error string `json:"error"`
}
- out, err := c.reader.ReadBytes('\x00')
+ out, err := c.Reader.ReadBytes('\x00')
if err != nil {
+ if err == io.EOF {
+ return 0, io.ErrUnexpectedEOF
+ }
return 0, err
}
@@ -96,11 +160,11 @@ func (c *Connection) Send(method string, parameters interface{}, flags uint64) (
}
if m.Error != "" {
- err = &Error{
+ e := &Error{
Name: m.Error,
Parameters: m.Parameters,
}
- return 0, err
+ return 0, e.DispatchError()
}
if m.Parameters != nil {
@@ -220,8 +284,8 @@ func NewConnection(address string) (*Connection, error) {
}
c.address = address
- c.reader = bufio.NewReader(c.conn)
- c.writer = bufio.NewWriter(c.conn)
+ c.Reader = bufio.NewReader(c.conn)
+ c.Writer = bufio.NewWriter(c.conn)
return &c, nil
}
diff --git a/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go b/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
index 39f843c31..600c99d34 100644
--- a/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
+++ b/vendor/github.com/varlink/go/varlink/orgvarlinkservice.go
@@ -1,5 +1,42 @@
package varlink
+// The requested interface was not found.
+type InterfaceNotFound struct {
+ Interface string `json:"interface"`
+}
+
+func (e InterfaceNotFound) Error() string {
+ return "org.varlink.service.InterfaceNotFound"
+}
+
+// The requested method was not found
+type MethodNotFound struct {
+ Method string `json:"method"`
+}
+
+func (e MethodNotFound) Error() string {
+ return "org.varlink.service.MethodNotFound"
+}
+
+// The interface defines the requested method, but the service does not
+// implement it.
+type MethodNotImplemented struct {
+ Method string `json:"method"`
+}
+
+func (e MethodNotImplemented) Error() string {
+ return "org.varlink.service.MethodNotImplemented"
+}
+
+// One of the passed parameters is invalid.
+type InvalidParameter struct {
+ Parameter string `json:"parameter"`
+}
+
+func (e InvalidParameter) Error() string {
+ return "org.varlink.service.InvalidParameter"
+}
+
func doReplyError(c *Call, name string, parameters interface{}) error {
return c.sendMessage(&serviceReply{
Error: name,
@@ -9,36 +46,28 @@ func doReplyError(c *Call, name string, parameters interface{}) error {
// ReplyInterfaceNotFound sends a org.varlink.service errror reply to this method call
func (c *Call) ReplyInterfaceNotFound(interfaceA string) error {
- var out struct {
- Interface string `json:"interface,omitempty"`
- }
+ var out InterfaceNotFound
out.Interface = interfaceA
return doReplyError(c, "org.varlink.service.InterfaceNotFound", &out)
}
// ReplyMethodNotFound sends a org.varlink.service errror reply to this method call
func (c *Call) ReplyMethodNotFound(method string) error {
- var out struct {
- Method string `json:"method,omitempty"`
- }
+ var out MethodNotFound
out.Method = method
return doReplyError(c, "org.varlink.service.MethodNotFound", &out)
}
// ReplyMethodNotImplemented sends a org.varlink.service errror reply to this method call
func (c *Call) ReplyMethodNotImplemented(method string) error {
- var out struct {
- Method string `json:"method,omitempty"`
- }
+ var out MethodNotImplemented
out.Method = method
return doReplyError(c, "org.varlink.service.MethodNotImplemented", &out)
}
// ReplyInvalidParameter sends a org.varlink.service errror reply to this method call
func (c *Call) ReplyInvalidParameter(parameter string) error {
- var out struct {
- Parameter string `json:"parameter,omitempty"`
- }
+ var out InvalidParameter
out.Parameter = parameter
return doReplyError(c, "org.varlink.service.InvalidParameter", &out)
}
diff --git a/vendor/github.com/varlink/go/varlink/service.go b/vendor/github.com/varlink/go/varlink/service.go
index cb461f917..abccffe6a 100644
--- a/vendor/github.com/varlink/go/varlink/service.go
+++ b/vendor/github.com/varlink/go/varlink/service.go
@@ -22,6 +22,7 @@ type serviceCall struct {
Parameters *json.RawMessage `json:"parameters,omitempty"`
More bool `json:"more,omitempty"`
Oneway bool `json:"oneway,omitempty"`
+ Upgrade bool `json:"upgrade,omitempty"`
}
type serviceReply struct {
@@ -50,7 +51,7 @@ type Service struct {
}
// ServiceTimoutError helps API users to special-case timeouts.
-type ServiceTimeoutError struct {}
+type ServiceTimeoutError struct{}
func (ServiceTimeoutError) Error() string {
return "service timeout"
@@ -73,7 +74,7 @@ func (s *Service) getInterfaceDescription(c Call, name string) error {
return c.replyGetInterfaceDescription(description)
}
-func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error {
+func (s *Service) handleMessage(reader *bufio.Reader, writer *bufio.Writer, request []byte) error {
var in serviceCall
err := json.Unmarshal(request, &in)
@@ -83,7 +84,8 @@ func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error {
}
c := Call{
- writer: writer,
+ Reader: reader,
+ Writer: writer,
in: &in,
}
@@ -129,7 +131,7 @@ func (s *Service) handleConnection(conn net.Conn, wg *sync.WaitGroup) {
break
}
- err = s.handleMessage(writer, request[:len(request)-1])
+ err = s.handleMessage(reader, writer, request[:len(request)-1])
if err != nil {
// FIXME: report error
//fmt.Fprintf(os.Stderr, "handleMessage: %v", err)
@@ -201,11 +203,11 @@ func getListener(protocol string, address string) (net.Listener, error) {
func (s *Service) refreshTimeout(timeout time.Duration) error {
switch l := s.listener.(type) {
case *net.UnixListener:
- if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil {
+ if err := l.SetDeadline(time.Now().Add(timeout)); err != nil {
return err
}
case *net.TCPListener:
- if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil {
+ if err := l.SetDeadline(time.Now().Add(timeout)); err != nil {
return err
}