From 001d06d7f6780797853503a2f278c49fbc6d8c5c Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Mon, 25 Nov 2019 19:00:11 -0500 Subject: Completely rework --change parsing The way we were trying to parse was very broken. I originally attempted to use Buildah's Dockerfile parser here, but dealing with it (and convincing it to accept only a limited subset, and only one instruction at a time) was challenging, so I rewrote a subset of Dockerfile parsing. This should handle most common cases well, though there are definitely unhandled edge cases for ENV and LABEL. Signed-off-by: Matthew Heon --- pkg/util/utils_test.go | 292 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 227 insertions(+), 65 deletions(-) (limited to 'pkg/util/utils_test.go') diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go index c938dc592..e60c644fd 100644 --- a/pkg/util/utils_test.go +++ b/pkg/util/utils_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var ( @@ -19,70 +20,231 @@ func TestStringInSlice(t *testing.T) { 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()) +func TestGetImageConfigUser(t *testing.T) { + validUser, err := GetImageConfig([]string{"USER valid"}) + require.Nil(t, err) + assert.Equal(t, validUser.User, "valid") + validUser2, err := GetImageConfig([]string{"USER test_user_2"}) + require.Nil(t, err) + assert.Equal(t, validUser2.User, "test_user_2") + + _, err = GetImageConfig([]string{"USER "}) + assert.NotNil(t, err) +} + +func TestGetImageConfigExpose(t *testing.T) { + validPortNoProto, err := GetImageConfig([]string{"EXPOSE 80"}) + require.Nil(t, err) + _, exists := validPortNoProto.ExposedPorts["80/tcp"] + assert.True(t, exists) + + validPortTCP, err := GetImageConfig([]string{"EXPOSE 80/tcp"}) + require.Nil(t, err) + _, exists = validPortTCP.ExposedPorts["80/tcp"] + assert.True(t, exists) + + validPortUDP, err := GetImageConfig([]string{"EXPOSE 80/udp"}) + require.Nil(t, err) + _, exists = validPortUDP.ExposedPorts["80/udp"] + assert.True(t, exists) + + _, err = GetImageConfig([]string{"EXPOSE 99999"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"EXPOSE 80/notaproto"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"EXPOSE "}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"EXPOSE thisisnotanumber"}) + assert.NotNil(t, err) +} + +func TestGetImageConfigEnv(t *testing.T) { + validEnvNoValue, err := GetImageConfig([]string{"ENV key"}) + require.Nil(t, err) + assert.True(t, StringInSlice("key=", validEnvNoValue.Env)) + + validEnvBareEquals, err := GetImageConfig([]string{"ENV key="}) + require.Nil(t, err) + assert.True(t, StringInSlice("key=", validEnvBareEquals.Env)) + + validEnvKeyValue, err := GetImageConfig([]string{"ENV key=value"}) + require.Nil(t, err) + assert.True(t, StringInSlice("key=value", validEnvKeyValue.Env)) + + validEnvKeyMultiEntryValue, err := GetImageConfig([]string{`ENV key="value1 value2"`}) + require.Nil(t, err) + assert.True(t, StringInSlice("key=value1 value2", validEnvKeyMultiEntryValue.Env)) + + _, err = GetImageConfig([]string{"ENV "}) + assert.NotNil(t, err) +} + +func TestGetImageConfigEntrypoint(t *testing.T) { + binShEntrypoint, err := GetImageConfig([]string{"ENTRYPOINT /bin/bash"}) + require.Nil(t, err) + require.Equal(t, 3, len(binShEntrypoint.Entrypoint)) + assert.Equal(t, binShEntrypoint.Entrypoint[0], "/bin/sh") + assert.Equal(t, binShEntrypoint.Entrypoint[1], "-c") + assert.Equal(t, binShEntrypoint.Entrypoint[2], "/bin/bash") + + entrypointWithSpaces, err := GetImageConfig([]string{"ENTRYPOINT ls -al"}) + require.Nil(t, err) + require.Equal(t, 3, len(entrypointWithSpaces.Entrypoint)) + assert.Equal(t, entrypointWithSpaces.Entrypoint[0], "/bin/sh") + assert.Equal(t, entrypointWithSpaces.Entrypoint[1], "-c") + assert.Equal(t, entrypointWithSpaces.Entrypoint[2], "ls -al") + + jsonArrayEntrypoint, err := GetImageConfig([]string{`ENTRYPOINT ["ls", "-al"]`}) + require.Nil(t, err) + require.Equal(t, 2, len(jsonArrayEntrypoint.Entrypoint)) + assert.Equal(t, jsonArrayEntrypoint.Entrypoint[0], "ls") + assert.Equal(t, jsonArrayEntrypoint.Entrypoint[1], "-al") + + emptyEntrypoint, err := GetImageConfig([]string{"ENTRYPOINT "}) + require.Nil(t, err) + assert.Equal(t, 0, len(emptyEntrypoint.Entrypoint)) + + emptyEntrypointArray, err := GetImageConfig([]string{"ENTRYPOINT []"}) + require.Nil(t, err) + assert.Equal(t, 0, len(emptyEntrypointArray.Entrypoint)) +} + +func TestGetImageConfigCmd(t *testing.T) { + binShCmd, err := GetImageConfig([]string{"CMD /bin/bash"}) + require.Nil(t, err) + require.Equal(t, 3, len(binShCmd.Cmd)) + assert.Equal(t, binShCmd.Cmd[0], "/bin/sh") + assert.Equal(t, binShCmd.Cmd[1], "-c") + assert.Equal(t, binShCmd.Cmd[2], "/bin/bash") + + cmdWithSpaces, err := GetImageConfig([]string{"CMD ls -al"}) + require.Nil(t, err) + require.Equal(t, 3, len(cmdWithSpaces.Cmd)) + assert.Equal(t, cmdWithSpaces.Cmd[0], "/bin/sh") + assert.Equal(t, cmdWithSpaces.Cmd[1], "-c") + assert.Equal(t, cmdWithSpaces.Cmd[2], "ls -al") + + jsonArrayCmd, err := GetImageConfig([]string{`CMD ["ls", "-al"]`}) + require.Nil(t, err) + require.Equal(t, 2, len(jsonArrayCmd.Cmd)) + assert.Equal(t, jsonArrayCmd.Cmd[0], "ls") + assert.Equal(t, jsonArrayCmd.Cmd[1], "-al") + + emptyCmd, err := GetImageConfig([]string{"CMD "}) + require.Nil(t, err) + require.Equal(t, 2, len(emptyCmd.Cmd)) + assert.Equal(t, emptyCmd.Cmd[0], "/bin/sh") + assert.Equal(t, emptyCmd.Cmd[1], "-c") + + blankCmd, err := GetImageConfig([]string{"CMD []"}) + require.Nil(t, err) + assert.Equal(t, 0, len(blankCmd.Cmd)) +} + +func TestGetImageConfigVolume(t *testing.T) { + oneLenJSONArrayVol, err := GetImageConfig([]string{`VOLUME ["/test1"]`}) + require.Nil(t, err) + _, exists := oneLenJSONArrayVol.Volumes["/test1"] + assert.True(t, exists) + assert.Equal(t, 1, len(oneLenJSONArrayVol.Volumes)) + + twoLenJSONArrayVol, err := GetImageConfig([]string{`VOLUME ["/test1", "/test2"]`}) + require.Nil(t, err) + assert.Equal(t, 2, len(twoLenJSONArrayVol.Volumes)) + _, exists = twoLenJSONArrayVol.Volumes["/test1"] + assert.True(t, exists) + _, exists = twoLenJSONArrayVol.Volumes["/test2"] + assert.True(t, exists) + + oneLenVol, err := GetImageConfig([]string{"VOLUME /test1"}) + require.Nil(t, err) + _, exists = oneLenVol.Volumes["/test1"] + assert.True(t, exists) + assert.Equal(t, 1, len(oneLenVol.Volumes)) + + twoLenVol, err := GetImageConfig([]string{"VOLUME /test1 /test2"}) + require.Nil(t, err) + assert.Equal(t, 2, len(twoLenVol.Volumes)) + _, exists = twoLenVol.Volumes["/test1"] + assert.True(t, exists) + _, exists = twoLenVol.Volumes["/test2"] + assert.True(t, exists) + + _, err = GetImageConfig([]string{"VOLUME []"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"VOLUME "}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{`VOLUME [""]`}) + assert.NotNil(t, err) +} + +func TestGetImageConfigWorkdir(t *testing.T) { + singleWorkdir, err := GetImageConfig([]string{"WORKDIR /testdir"}) + require.Nil(t, err) + assert.Equal(t, singleWorkdir.WorkingDir, "/testdir") + + twoWorkdirs, err := GetImageConfig([]string{"WORKDIR /testdir", "WORKDIR a"}) + require.Nil(t, err) + assert.Equal(t, twoWorkdirs.WorkingDir, "/testdir/a") + + _, err = GetImageConfig([]string{"WORKDIR "}) + assert.NotNil(t, err) +} + +func TestGetImageConfigLabel(t *testing.T) { + labelNoQuotes, err := GetImageConfig([]string{"LABEL key1=value1"}) + require.Nil(t, err) + assert.Equal(t, labelNoQuotes.Labels["key1"], "value1") + + labelWithQuotes, err := GetImageConfig([]string{`LABEL "key 1"="value 2"`}) + require.Nil(t, err) + assert.Equal(t, labelWithQuotes.Labels["key 1"], "value 2") + + labelNoValue, err := GetImageConfig([]string{"LABEL key="}) + require.Nil(t, err) + contents, exists := labelNoValue.Labels["key"] + assert.True(t, exists) + assert.Equal(t, contents, "") + + _, err = GetImageConfig([]string{"LABEL key"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"LABEL "}) + assert.NotNil(t, err) +} + +func TestGetImageConfigStopSignal(t *testing.T) { + stopSignalValidInt, err := GetImageConfig([]string{"STOPSIGNAL 9"}) + require.Nil(t, err) + assert.Equal(t, stopSignalValidInt.StopSignal, "9") + + stopSignalValidString, err := GetImageConfig([]string{"STOPSIGNAL SIGKILL"}) + require.Nil(t, err) + assert.Equal(t, stopSignalValidString.StopSignal, "9") + + _, err = GetImageConfig([]string{"STOPSIGNAL 0"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"STOPSIGNAL garbage"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"STOPSIGNAL "}) + assert.NotNil(t, err) +} + +func TestGetImageConfigMisc(t *testing.T) { + _, err := GetImageConfig([]string{""}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"USER"}) + assert.NotNil(t, err) + + _, err = GetImageConfig([]string{"BADINST testvalue"}) + assert.NotNil(t, err) } -- cgit v1.2.3-54-g00ecf From 60bfa305a88c686c91ebc0f8f98ac14405ae10cf Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 5 Dec 2019 15:11:40 -0500 Subject: Add ONBUILD support to --change Return types had to change a bit for this, but since we can wrap the old v1.ImageConfig, changes are overall not particularly bad. At present, I believe this only works with commit, not import. This matches how things were before we changed to the new parsing so I think this is fine. Signed-off-by: Matthew Heon --- libpod/container_commit.go | 3 +++ libpod/runtime_img.go | 3 ++- pkg/util/utils.go | 47 ++++++++++++++++++++++++++++++---------------- pkg/util/utils_test.go | 16 ++++++++++++++++ pkg/varlinkapi/images.go | 2 +- 5 files changed, 53 insertions(+), 18 deletions(-) (limited to 'pkg/util/utils_test.go') diff --git a/libpod/container_commit.go b/libpod/container_commit.go index cab204546..a0ba57f4f 100644 --- a/libpod/container_commit.go +++ b/libpod/container_commit.go @@ -183,6 +183,9 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai if newImageConfig.StopSignal != "" { importBuilder.SetStopSignal(newImageConfig.StopSignal) } + for _, onbuild := range newImageConfig.OnBuild { + importBuilder.SetOnBuild(onbuild) + } candidates, _, _, err := util.ResolveName(destImage, "", sc, c.runtime.store) if err != nil { diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index f2784c07d..abd8b581d 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -160,10 +160,11 @@ func (r *Runtime) Import(ctx context.Context, source string, reference string, c ic := v1.ImageConfig{} if len(changes) > 0 { - ic, err = util.GetImageConfig(changes) + config, err := util.GetImageConfig(changes) if err != nil { return "", errors.Wrapf(err, "error adding config changes to image %q", source) } + ic = config.ImageConfig } hist := []v1.History{ diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 5ffb05dda..5b4dfe9fa 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -73,10 +73,18 @@ func StringInSlice(s string, sl []string) bool { return false } +// ImageConfig is a wrapper around the OCIv1 Image Configuration struct exported +// by containers/image, but containing additional fields that are not supported +// by OCIv1 (but are by Docker v2) - notably OnBuild. +type ImageConfig struct { + v1.ImageConfig + OnBuild []string +} + // GetImageConfig produces a v1.ImageConfig from the --change flag that is // accepted by several Podman commands. It accepts a (limited subset) of // Dockerfile instructions. -func GetImageConfig(changes []string) (v1.ImageConfig, error) { +func GetImageConfig(changes []string) (ImageConfig, error) { // Valid changes: // USER // EXPOSE @@ -87,8 +95,9 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { // WORKDIR // LABEL // STOPSIGNAL + // ONBUILD - config := v1.ImageConfig{} + config := ImageConfig{} for _, change := range changes { // First, let's assume proper Dockerfile format - space @@ -98,7 +107,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { if len(split) != 2 { split = strings.SplitN(change, "=", 2) if len(split) != 2 { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - must be formatted as KEY VALUE", change) + return ImageConfig{}, errors.Errorf("invalid change %q - must be formatted as KEY VALUE", change) } } @@ -108,7 +117,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { case "USER": // Assume literal contents are the user. if value == "" { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - must provide a value to USER", change) + return ImageConfig{}, errors.Errorf("invalid change %q - must provide a value to USER", change) } config.User = value case "EXPOSE": @@ -117,14 +126,14 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { // Protocol must be "tcp" or "udp" splitPort := strings.Split(value, "/") if len(splitPort) > 2 { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - EXPOSE port must be formatted as PORT[/PROTO]", change) + return ImageConfig{}, errors.Errorf("invalid change %q - EXPOSE port must be formatted as PORT[/PROTO]", change) } portNum, err := strconv.Atoi(splitPort[0]) if err != nil { - return v1.ImageConfig{}, errors.Wrapf(err, "invalid change %q - EXPOSE port must be an integer", change) + return ImageConfig{}, errors.Wrapf(err, "invalid change %q - EXPOSE port must be an integer", change) } if portNum > 65535 || portNum <= 0 { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - EXPOSE port must be a valid port number", change) + return ImageConfig{}, errors.Errorf("invalid change %q - EXPOSE port must be a valid port number", change) } proto := "tcp" if len(splitPort) > 1 { @@ -133,7 +142,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { case "tcp", "udp": proto = testProto default: - return v1.ImageConfig{}, errors.Errorf("invalid change %q - EXPOSE protocol must be TCP or UDP", change) + return ImageConfig{}, errors.Errorf("invalid change %q - EXPOSE protocol must be TCP or UDP", change) } } if config.ExposedPorts == nil { @@ -157,7 +166,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { key = splitEnv[0] // We do need a key if key == "" { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - ENV must have at least one argument", change) + return ImageConfig{}, errors.Errorf("invalid change %q - ENV must have at least one argument", change) } // Perfectly valid to not have a value if len(splitEnv) == 2 { @@ -219,11 +228,11 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { testUnmarshal = strings.Split(value, " ") } if len(testUnmarshal) == 0 { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - must provide at least one argument to VOLUME", change) + return ImageConfig{}, errors.Errorf("invalid change %q - must provide at least one argument to VOLUME", change) } for _, vol := range testUnmarshal { if vol == "" { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - VOLUME paths must not be empty", change) + return ImageConfig{}, errors.Errorf("invalid change %q - VOLUME paths must not be empty", change) } if config.Volumes == nil { config.Volumes = make(map[string]struct{}) @@ -237,7 +246,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { // WORKDIR c results in /A/b/c // Just need to check it's not empty... if value == "" { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - must provide a non-empty WORKDIR", change) + return ImageConfig{}, errors.Errorf("invalid change %q - must provide a non-empty WORKDIR", change) } config.WorkingDir = filepath.Join(config.WorkingDir, value) case "LABEL": @@ -254,7 +263,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { splitLabel := strings.SplitN(value, "=", 2) // Unlike ENV, LABEL must have a value if len(splitLabel) != 2 { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - LABEL must be formatted key=value", change) + return ImageConfig{}, errors.Errorf("invalid change %q - LABEL must be formatted key=value", change) } key = splitLabel[0] val = splitLabel[1] @@ -267,7 +276,7 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { } // Check key after we strip quotations if key == "" { - return v1.ImageConfig{}, errors.Errorf("invalid change %q - LABEL must have a non-empty key", change) + return ImageConfig{}, errors.Errorf("invalid change %q - LABEL must have a non-empty key", change) } if config.Labels == nil { config.Labels = make(map[string]string) @@ -279,11 +288,17 @@ func GetImageConfig(changes []string) (v1.ImageConfig, error) { // negative numbers. killSignal, err := signal.ParseSignal(value) if err != nil { - return v1.ImageConfig{}, errors.Wrapf(err, "invalid change %q - KILLSIGNAL must be given a valid signal", change) + return ImageConfig{}, errors.Wrapf(err, "invalid change %q - KILLSIGNAL must be given a valid signal", change) } config.StopSignal = fmt.Sprintf("%d", killSignal) + case "ONBUILD": + // Onbuild always appends. + if value == "" { + return ImageConfig{}, errors.Errorf("invalid change %q - ONBUILD must be given an argument", change) + } + config.OnBuild = append(config.OnBuild, value) default: - return v1.ImageConfig{}, errors.Errorf("invalid change %q - invalid instruction %s", change, outerKey) + return ImageConfig{}, errors.Errorf("invalid change %q - invalid instruction %s", change, outerKey) } } diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go index e60c644fd..f4b03599d 100644 --- a/pkg/util/utils_test.go +++ b/pkg/util/utils_test.go @@ -238,6 +238,22 @@ func TestGetImageConfigStopSignal(t *testing.T) { assert.NotNil(t, err) } +func TestGetImageConfigOnBuild(t *testing.T) { + onBuildOne, err := GetImageConfig([]string{"ONBUILD ADD /testdir1"}) + require.Nil(t, err) + require.Equal(t, 1, len(onBuildOne.OnBuild)) + assert.Equal(t, onBuildOne.OnBuild[0], "ADD /testdir1") + + onBuildTwo, err := GetImageConfig([]string{"ONBUILD ADD /testdir1", "ONBUILD ADD /testdir2"}) + require.Nil(t, err) + require.Equal(t, 2, len(onBuildTwo.OnBuild)) + assert.Equal(t, onBuildTwo.OnBuild[0], "ADD /testdir1") + assert.Equal(t, onBuildTwo.OnBuild[1], "ADD /testdir2") + + _, err = GetImageConfig([]string{"ONBUILD "}) + assert.NotNil(t, err) +} + func TestGetImageConfigMisc(t *testing.T) { _, err := GetImageConfig([]string{""}) assert.NotNil(t, err) diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 7abffa42a..604a455a5 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -602,7 +602,7 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me {Comment: message}, } config := v1.Image{ - Config: configChanges, + Config: configChanges.ImageConfig, History: history, } newImage, err := i.Runtime.ImageRuntime().Import(getContext(), source, reference, nil, image.SigningOptions{}, config) -- cgit v1.2.3-54-g00ecf