aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/import.go5
-rw-r--r--docs/podman-import.1.md20
-rw-r--r--go.mod2
-rw-r--r--go.sum2
-rw-r--r--pkg/util/utils.go85
-rw-r--r--pkg/util/utils_test.go71
-rw-r--r--test/e2e/import_test.go42
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go1
-rw-r--r--vendor/github.com/containers/storage/store.go13
-rw-r--r--vendor/modules.txt2
12 files changed, 216 insertions, 31 deletions
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index d49792f27..027fa7299 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -39,7 +39,7 @@ func init() {
importCommand.SetHelpTemplate(HelpTemplate())
importCommand.SetUsageTemplate(UsageTemplate())
flags := importCommand.Flags()
- flags.StringSliceVarP(&importCommand.Change, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
+ flags.StringArrayVarP(&importCommand.Change, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
flags.StringVarP(&importCommand.Message, "message", "m", "", "Set commit message for imported image")
flags.BoolVarP(&importCommand.Quiet, "quiet", "q", false, "Suppress output")
@@ -56,7 +56,6 @@ func importCmd(c *cliconfig.ImportValues) error {
source string
reference string
)
-
args := c.InputArgs
switch len(args) {
case 0:
@@ -81,7 +80,7 @@ func importCmd(c *cliconfig.ImportValues) error {
if runtime.Remote {
quiet = false
}
- iid, err := runtime.Import(getContext(), source, reference, c.StringSlice("change"), c.String("message"), quiet)
+ iid, err := runtime.Import(getContext(), source, reference, importCommand.Change, c.String("message"), quiet)
if err == nil {
fmt.Println(iid)
}
diff --git a/docs/podman-import.1.md b/docs/podman-import.1.md
index 5e57c1bcb..946b680dd 100644
--- a/docs/podman-import.1.md
+++ b/docs/podman-import.1.md
@@ -55,6 +55,26 @@ db65d991f3bbf7f31ed1064db9a6ced7652e3f8166c4736aa9133dadd3c7acb3
```
```
+$ podman import --change "ENTRYPOINT ["/bin/sh","-c","test-image"]" --change LABEL=blue=image test-image.tar image-imported
+Getting image source signatures
+Copying blob e3b0c44298fc skipped: already exists
+Copying config 1105523502 done
+Writing manifest to image destination
+Storing signatures
+110552350206337183ceadc0bdd646dc356e06514c548b69a8917b4182414b
+```
+```
+$ podman import --change "CMD /bin/sh" --change LABEL=blue=image test-image.tar image-imported
+Getting image source signatures
+Copying blob e3b0c44298fc skipped: already exists
+Copying config ae9a27e249 done
+Writing manifest to image destination
+Storing signatures
+ae9a27e249f801aff11a4ba54a81751ea9fbc9db45a6df3f1bfd63fc2437bb9c
+```
+
+
+```
$ cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported
db65d991f3bbf7f31ed1064db9a6ced7652e3f8166c4736aa9133dadd3c7acb3
```
diff --git a/go.mod b/go.mod
index 786df0567..07ae53f9d 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
github.com/containers/conmon v0.3.0 // indirect
github.com/containers/image v3.0.2+incompatible
github.com/containers/psgo v1.3.1
- github.com/containers/storage v1.13.3
+ github.com/containers/storage v1.13.4
github.com/coreos/bbolt v1.3.3 // indirect
github.com/coreos/etcd v3.3.13+incompatible // indirect
github.com/coreos/go-iptables v0.4.2 // indirect
diff --git a/go.sum b/go.sum
index 92011a6ba..460626d25 100644
--- a/go.sum
+++ b/go.sum
@@ -110,6 +110,8 @@ github.com/containers/storage v1.13.2 h1:UXZ0Ckmk6+6+4vj2M2ywruVtH97pnRoAhTG8ctd
github.com/containers/storage v1.13.2/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/containers/storage v1.13.3 h1:9EzTXZXG/8SGD9MnkSCe/jLq3QldcE1QlgW7vePEsjw=
github.com/containers/storage v1.13.3/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
+github.com/containers/storage v1.13.4 h1:j0bBaJDKbUHtAW1MXPFnwXJtqcH+foWeuXK1YaBV5GA=
+github.com/containers/storage v1.13.4/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 583bf5d18..edcad1d1b 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "regexp"
"strings"
"sync"
"time"
@@ -16,7 +17,7 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
- "github.com/opencontainers/image-spec/specs-go/v1"
+ v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
@@ -69,6 +70,50 @@ func StringInSlice(s string, sl []string) bool {
return false
}
+// ParseChanges returns key, value(s) pair for given option.
+func ParseChanges(option string) (key string, vals []string, err error) {
+ // Supported format as below
+ // 1. key=value
+ // 2. key value
+ // 3. key ["value","value1"]
+ if strings.Contains(option, " ") {
+ // This handles 2 & 3 conditions.
+ var val string
+ tokens := strings.SplitAfterN(option, " ", 2)
+ if len(tokens) < 2 {
+ return "", []string{}, fmt.Errorf("invalid key value %s", option)
+ }
+ key = strings.Trim(tokens[0], " ") // Need to trim whitespace part of delimeter.
+ val = tokens[1]
+ if strings.Contains(tokens[1], "[") && strings.Contains(tokens[1], "]") {
+ //Trim '[',']' if exist.
+ val = strings.TrimLeft(strings.TrimRight(tokens[1], "]"), "[")
+ }
+ vals = strings.Split(val, ",")
+ } else if strings.Contains(option, "=") {
+ // handles condition 1.
+ tokens := strings.Split(option, "=")
+ key = tokens[0]
+ vals = tokens[1:]
+ } else {
+ // either ` ` or `=` must be provided after command
+ return "", []string{}, fmt.Errorf("invalid format %s", option)
+ }
+
+ if len(vals) == 0 {
+ return "", []string{}, errors.Errorf("no value given for instruction %q", key)
+ }
+
+ for _, v := range vals {
+ //each option must not have ' '., `[`` or `]` & empty strings
+ whitespaces := regexp.MustCompile(`[\[\s\]]`)
+ if whitespaces.MatchString(v) || len(v) == 0 {
+ return "", []string{}, fmt.Errorf("invalid value %s", v)
+ }
+ }
+ return key, vals, nil
+}
+
// GetImageConfig converts the --change flag values in the format "CMD=/bin/bash USER=example"
// to a type v1.ImageConfig
func GetImageConfig(changes []string) (v1.ImageConfig, error) {
@@ -87,40 +132,42 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) {
exposedPorts := make(map[string]struct{})
volumes := make(map[string]struct{})
labels := make(map[string]string)
-
for _, ch := range changes {
- pair := strings.Split(ch, "=")
- if len(pair) == 1 {
- return v1.ImageConfig{}, errors.Errorf("no value given for instruction %q", ch)
+ key, vals, err := ParseChanges(ch)
+ if err != nil {
+ return v1.ImageConfig{}, err
}
- switch pair[0] {
+
+ switch key {
case "USER":
- user = pair[1]
+ user = vals[0]
case "EXPOSE":
var st struct{}
- exposedPorts[pair[1]] = st
+ exposedPorts[vals[0]] = st
case "ENV":
- if len(pair) < 3 {
- return v1.ImageConfig{}, errors.Errorf("no value given for environment variable %q", pair[1])
+ if len(vals) < 2 {
+ return v1.ImageConfig{}, errors.Errorf("no value given for environment variable %q", vals[0])
}
- env = append(env, strings.Join(pair[1:], "="))
+ env = append(env, strings.Join(vals[0:], "="))
case "ENTRYPOINT":
- entrypoint = append(entrypoint, pair[1])
+ // ENTRYPOINT and CMD can have array of strings
+ entrypoint = append(entrypoint, vals...)
case "CMD":
- cmd = append(cmd, pair[1])
+ // ENTRYPOINT and CMD can have array of strings
+ cmd = append(cmd, vals...)
case "VOLUME":
var st struct{}
- volumes[pair[1]] = st
+ volumes[vals[0]] = st
case "WORKDIR":
- workingDir = pair[1]
+ workingDir = vals[0]
case "LABEL":
- if len(pair) == 3 {
- labels[pair[1]] = pair[2]
+ if len(vals) == 2 {
+ labels[vals[0]] = vals[1]
} else {
- labels[pair[1]] = ""
+ labels[vals[0]] = ""
}
case "STOPSIGNAL":
- stopSignal = pair[1]
+ stopSignal = vals[0]
}
}
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index f47c0b7ad..c938dc592 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -1,8 +1,9 @@
package util
import (
- "github.com/stretchr/testify/assert"
"testing"
+
+ "github.com/stretchr/testify/assert"
)
var (
@@ -17,3 +18,71 @@ func TestStringInSlice(t *testing.T) {
// string is not in empty slice
assert.False(t, StringInSlice("one", []string{}))
}
+
+func TestParseChanges(t *testing.T) {
+ // CMD=/bin/sh
+ _, vals, err := ParseChanges("CMD=/bin/sh")
+ assert.EqualValues(t, []string{"/bin/sh"}, vals)
+ assert.NoError(t, err)
+
+ // CMD [/bin/sh]
+ _, vals, err = ParseChanges("CMD [/bin/sh]")
+ assert.EqualValues(t, []string{"/bin/sh"}, vals)
+ assert.NoError(t, err)
+
+ // CMD ["/bin/sh"]
+ _, vals, err = ParseChanges(`CMD ["/bin/sh"]`)
+ assert.EqualValues(t, []string{`"/bin/sh"`}, vals)
+ assert.NoError(t, err)
+
+ // CMD ["/bin/sh","-c","ls"]
+ _, vals, err = ParseChanges(`CMD ["/bin/sh","c","ls"]`)
+ assert.EqualValues(t, []string{`"/bin/sh"`, `"c"`, `"ls"`}, vals)
+ assert.NoError(t, err)
+
+ // CMD ["/bin/sh","arg-with,comma"]
+ _, vals, err = ParseChanges(`CMD ["/bin/sh","arg-with,comma"]`)
+ assert.EqualValues(t, []string{`"/bin/sh"`, `"arg-with`, `comma"`}, vals)
+ assert.NoError(t, err)
+
+ // CMD "/bin/sh"]
+ _, _, err = ParseChanges(`CMD "/bin/sh"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "/bin/sh"]`, err.Error())
+
+ // CMD [bin/sh
+ _, _, err = ParseChanges(`CMD "/bin/sh"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "/bin/sh"]`, err.Error())
+
+ // CMD ["/bin /sh"]
+ _, _, err = ParseChanges(`CMD ["/bin /sh"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "/bin /sh"`, err.Error())
+
+ // CMD ["/bin/sh", "-c","ls"] whitespace between values
+ _, vals, err = ParseChanges(`CMD ["/bin/sh", "c","ls"]`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value "c"`, err.Error())
+
+ // CMD?
+ _, _, err = ParseChanges(`CMD?`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid format CMD?`, err.Error())
+
+ // empty values for CMD
+ _, _, err = ParseChanges(`CMD `)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value `, err.Error())
+
+ // LABEL=blue=image
+ _, vals, err = ParseChanges(`LABEL=blue=image`)
+ assert.EqualValues(t, []string{"blue", "image"}, vals)
+ assert.NoError(t, err)
+
+ // LABEL = blue=image
+ _, vals, err = ParseChanges(`LABEL = blue=image`)
+ assert.Error(t, err)
+ assert.Equal(t, `invalid value = blue=image`, err.Error())
+
+}
diff --git a/test/e2e/import_test.go b/test/e2e/import_test.go
index 84a91a783..979440a50 100644
--- a/test/e2e/import_test.go
+++ b/test/e2e/import_test.go
@@ -88,7 +88,7 @@ var _ = Describe("Podman import", func() {
Expect(results.LineInOuputStartsWith("importing container test message")).To(BeTrue())
})
- It("podman import with change flag", func() {
+ It("podman import with change flag CMD=<path>", func() {
outfile := filepath.Join(podmanTest.TempDir, "container.tar")
_, ec, cid := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
@@ -108,4 +108,44 @@ var _ = Describe("Podman import", func() {
Expect(imageData[0].Config.Cmd[0]).To(Equal("/bin/bash"))
})
+ It("podman import with change flag CMD <path>", func() {
+ outfile := filepath.Join(podmanTest.TempDir, "container.tar")
+ _, ec, cid := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ export := podmanTest.Podman([]string{"export", "-o", outfile, cid})
+ export.WaitWithDefaultTimeout()
+ Expect(export.ExitCode()).To(Equal(0))
+
+ importImage := podmanTest.Podman([]string{"import", "--change", "CMD /bin/sh", outfile, "imported-image"})
+ importImage.WaitWithDefaultTimeout()
+ Expect(importImage.ExitCode()).To(Equal(0))
+
+ results := podmanTest.Podman([]string{"inspect", "imported-image"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ imageData := results.InspectImageJSON()
+ Expect(imageData[0].Config.Cmd[0]).To(Equal("/bin/sh"))
+ })
+
+ It("podman import with change flag CMD [\"path\",\"path'\"", func() {
+ outfile := filepath.Join(podmanTest.TempDir, "container.tar")
+ _, ec, cid := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ export := podmanTest.Podman([]string{"export", "-o", outfile, cid})
+ export.WaitWithDefaultTimeout()
+ Expect(export.ExitCode()).To(Equal(0))
+
+ importImage := podmanTest.Podman([]string{"import", "--change", "CMD [/bin/bash]", outfile, "imported-image"})
+ importImage.WaitWithDefaultTimeout()
+ Expect(importImage.ExitCode()).To(Equal(0))
+
+ results := podmanTest.Podman([]string{"inspect", "imported-image"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ imageData := results.InspectImageJSON()
+ Expect(imageData[0].Config.Cmd[0]).To(Equal("/bin/bash"))
+ })
+
})
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 01b756823..80138e714 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.13.3
+1.13.4
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index 6b40ebd59..539acfe93 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: images.go
+// source: ./images.go
package storage
diff --git a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
index 98d3ee96a..c6985d757 100644
--- a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
+++ b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
@@ -26,7 +26,6 @@ func NewLogger(logger func(*tar.Header)) (io.WriteCloser, error) {
closed: false,
}
tr := tar.NewReader(reader)
- tr.RawAccounting = true
t.closeMutex.Lock()
go func() {
hdr, err := tr.Next()
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index dd3405212..af69a4b2d 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -1502,6 +1502,7 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) {
if err != nil {
return nil, err
}
+ foundImage := false
for _, s := range append([]ROImageStore{istore}, istores...) {
store := s
store.RLock()
@@ -1515,6 +1516,12 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) {
if err == nil {
return data, nil
}
+ if store.Exists(id) {
+ foundImage = true
+ }
+ }
+ if foundImage {
+ return nil, errors.Wrapf(os.ErrNotExist, "error locating item named %q for image with ID %q", key, id)
}
return nil, errors.Wrapf(ErrImageUnknown, "error locating image with ID %q", id)
}
@@ -1587,10 +1594,12 @@ func (s *store) ImageSize(id string) (int64, error) {
return -1, errors.Wrapf(ErrImageUnknown, "error locating image with ID %q", id)
}
- // Start with a list of the image's top layers.
+ // Start with a list of the image's top layers, if it has any.
queue := make(map[string]struct{})
for _, layerID := range append([]string{image.TopLayer}, image.MappedTopLayers...) {
- queue[layerID] = struct{}{}
+ if layerID != "" {
+ queue[layerID] = struct{}{}
+ }
}
visited := make(map[string]struct{})
// Walk all of the layers.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index b5434aecc..3d0902c62 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -109,7 +109,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
github.com/containers/psgo/internal/host
-# github.com/containers/storage v1.13.3
+# github.com/containers/storage v1.13.4
github.com/containers/storage
github.com/containers/storage/pkg/archive
github.com/containers/storage/pkg/chrootarchive