Support BuildArgs for arg command

This commit is contained in:
Priya Wadhwa 2018-05-09 11:58:58 -07:00
parent 3aafb843e2
commit 26d8501489
No known key found for this signature in database
GPG Key ID: 0D0DAFD8F7AA73AE
38 changed files with 316 additions and 93 deletions

View File

@ -36,7 +36,6 @@ After each command, we append a layer of changed files to the base image (if the
The majority of Dockerfile commands can be executed with kaniko, but we're still working on supporting the following commands:
* HEALTHCHECK
* ARG
Multi-Stage Dockerfiles are also unsupported currently, but will be ready soon.

View File

@ -21,9 +21,9 @@ import (
"os"
"path/filepath"
"github.com/genuinetools/amicontained/container"
"github.com/GoogleContainerTools/kaniko/pkg/executor"
"github.com/genuinetools/amicontained/container"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/util"
@ -40,6 +40,7 @@ var (
dockerInsecureSkipTLSVerify bool
logLevel string
force bool
buildArgs buildArg
)
func init() {
@ -49,6 +50,7 @@ func init() {
RootCmd.PersistentFlags().StringVarP(&destination, "destination", "d", "", "Registry the final image should be pushed to (ex: gcr.io/test/example:latest)")
RootCmd.MarkPersistentFlagRequired("destination")
RootCmd.PersistentFlags().StringVarP(&snapshotMode, "snapshotMode", "", "full", "Set this flag to change the file attributes inspected during snapshotting")
RootCmd.PersistentFlags().VarP(&buildArgs, "build-arg", "", "This flag allows you to pass in ARG values at build time. Set it repeatedly for multiple values.")
RootCmd.PersistentFlags().BoolVarP(&dockerInsecureSkipTLSVerify, "insecure-skip-tls-verify", "", false, "Push to insecure registry ignoring TLS verify")
RootCmd.PersistentFlags().StringVarP(&logLevel, "verbosity", "v", constants.DefaultLogLevel, "Log level (debug, info, warn, error, fatal, panic")
RootCmd.PersistentFlags().BoolVarP(&force, "force", "", false, "Force building outside of a container")
@ -77,13 +79,33 @@ var RootCmd = &cobra.Command{
logrus.Error(err)
os.Exit(1)
}
if err := executor.DoBuild(dockerfilePath, srcContext, destination, snapshotMode, dockerInsecureSkipTLSVerify); err != nil {
if err := executor.DoBuild(dockerfilePath, srcContext, destination, snapshotMode, dockerInsecureSkipTLSVerify, buildArgs); err != nil {
logrus.Error(err)
os.Exit(1)
}
},
}
type buildArg []string
// Now, for our new type, implement the two methods of
// the flag.Value interface...
// The first method is String() string
func (b *buildArg) String() string {
return strings.Join(*b, ",")
}
// The second method is Set(value string) error
func (b *buildArg) Set(value string) error {
logrus.Infof("appending to build args %s", value)
*b = append(*b, value)
return nil
}
func (b *buildArg) Type() string {
return "Build ARG Type"
}
func checkContained() bool {
_, err := container.DetectRuntime()
return err == nil

View File

@ -14,5 +14,9 @@ ADD $contextenv/* /tmp/${contextenv}/
ADD context/tars/fil* /tars/
ADD context/tars/file.tar /tars_again
# Test with ARG
ARG file
COPY $file /arg
# Finally, test adding a remote URL, concurrently with a normal file
ADD https://github.com/GoogleCloudPlatform/docker-credential-gcr/releases/download/v1.4.3/docker-credential-gcr_linux_386-1.4.3.tar.gz context/foo /test/all/

View File

@ -1,6 +1,7 @@
FROM gcr.io/kaniko-test/onbuild-base:latest
COPY context/foo foo
ENV dir /new/workdir/
ONBUILD RUN echo "onbuild" > /tmp/onbuild
ARG file
ONBUILD RUN echo "onbuild" > $file
ONBUILD RUN echo "onbuild 2" > ${dir}
ONBUILD WORKDIR /new/workdir

View File

@ -17,3 +17,7 @@ RUN echo "hey" > /etc/foo
RUN echo "baz" > /etc/baz
RUN cp /etc/baz /etc/bar
RUN rm /etc/baz
# Test with ARG
ARG file
RUN echo "run" > $file

View File

@ -1,4 +1,14 @@
FROM scratch
ADD context/foo /foo
ENV hello hello
ADD context/foo /$hello
# First, make sure simple arg replacement works
ARG file
COPY $file /foo
# Check that setting a default value works
ARG file2=context/bar/bat
COPY $file2 /bat
# Check that overriding a default value works
ARG file3=context/bar/baz
COPY $file3 /baz
# Check that setting an ENV will override the ARG
ENV file context/bar/bam/bat
COPY $file /env

View File

@ -11,3 +11,7 @@ ENV dir /another/new/dir
WORKDIR $dir/newdir
WORKDIR $dir/$doesntexist
WORKDIR /
# Test with ARG
ARG workdir
WORKDIR $workdir

View File

@ -47,6 +47,7 @@ var fileTests = []struct {
kanikoContextBucket bool
repo string
snapshotMode string
args []string
}{
{
description: "test extract filesystem",
@ -64,6 +65,9 @@ var fileTests = []struct {
dockerContext: dockerfilesPath,
kanikoContext: dockerfilesPath,
repo: "test-run",
args: []string{
"file=/file",
},
},
{
description: "test run no files changed",
@ -99,6 +103,9 @@ var fileTests = []struct {
dockerContext: buildcontextPath,
kanikoContext: buildcontextPath,
repo: "test-workdir",
args: []string{
"workdir=/arg/workdir",
},
},
{
description: "test volume",
@ -115,6 +122,9 @@ var fileTests = []struct {
dockerContext: buildcontextPath,
kanikoContext: buildcontextPath,
repo: "test-add",
args: []string{
"file=context/foo",
},
},
{
description: "test mv add",
@ -139,6 +149,9 @@ var fileTests = []struct {
dockerContext: buildcontextPath,
kanikoContext: buildcontextPath,
repo: "test-onbuild",
args: []string{
"file=/tmp/onbuild",
},
},
{
description: "test scratch",
@ -147,6 +160,11 @@ var fileTests = []struct {
dockerContext: buildcontextPath,
kanikoContext: buildcontextPath,
repo: "test-scratch",
args: []string{
"hello=hello-value",
"file=context/foo",
"file3=context/b*",
},
},
}
@ -231,18 +249,23 @@ func main() {
Args: []string{"push", onbuildBaseImage},
}
y := testyaml{
Steps: []step{containerDiffStep, containerDiffPermissions, GCSBucketTarBuildContext, uploadTarBuildContext, buildExecutorImage,
buildOnbuildImage, pushOnbuildBase},
Steps: []step{containerDiffStep, containerDiffPermissions, GCSBucketTarBuildContext,
uploadTarBuildContext, buildExecutorImage, buildOnbuildImage, pushOnbuildBase},
Timeout: "1200s",
}
for _, test := range fileTests {
// First, build the image with docker
dockerImageTag := testRepo + dockerPrefix + test.repo
var buildArgs []string
buildArgFlag := "--build-arg"
for _, arg := range test.args {
buildArgs = append(buildArgs, buildArgFlag)
buildArgs = append(buildArgs, arg)
}
dockerBuild := step{
Name: dockerImage,
Args: []string{"build", "-t", dockerImageTag, "-f", test.dockerfilePath, test.dockerContext},
Args: append([]string{"build", "-t", dockerImageTag, "-f", test.dockerfilePath, test.dockerContext}, buildArgs...),
}
// Then, buld the image with kaniko
kanikoImage := testRepo + kanikoPrefix + test.repo
snapshotMode := ""
@ -255,7 +278,7 @@ func main() {
}
kaniko := step{
Name: executorImage,
Args: []string{"--destination", kanikoImage, "--dockerfile", test.dockerfilePath, contextFlag, test.kanikoContext, snapshotMode},
Args: append([]string{"--destination", kanikoImage, "--dockerfile", test.dockerfilePath, contextFlag, test.kanikoContext, snapshotMode}, buildArgs...),
}
// Pull the kaniko image

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"path/filepath"
"strings"
@ -41,7 +42,7 @@ type AddCommand struct {
// - If dest doesn't end with a slash, the filepath is inferred to be <dest>/<filename>
// 2. If <src> is a local tar archive:
// -If <src> is a local tar archive, it is unpacked at the dest, as 'tar -x' would
func (a *AddCommand) ExecuteCommand(config *v1.Config) error {
func (a *AddCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
srcs := a.cmd.SourcesAndDest[:len(a.cmd.SourcesAndDest)-1]
dest := a.cmd.SourcesAndDest[len(a.cmd.SourcesAndDest)-1]
@ -49,7 +50,8 @@ func (a *AddCommand) ExecuteCommand(config *v1.Config) error {
logrus.Infof("dest: %s", dest)
// First, resolve any environment replacement
resolvedEnvs, err := util.ResolveEnvironmentReplacementList(a.cmd.SourcesAndDest, config.Env, true)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
resolvedEnvs, err := util.ResolveEnvironmentReplacementList(a.cmd.SourcesAndDest, replacementEnvs, true)
if err != nil {
return err
}
@ -101,7 +103,7 @@ func (a *AddCommand) ExecuteCommand(config *v1.Config) error {
},
buildcontext: a.buildcontext,
}
if err := copyCmd.ExecuteCommand(config); err != nil {
if err := copyCmd.ExecuteCommand(config, buildArgs); err != nil {
return err
}
a.snapshotFiles = append(a.snapshotFiles, copyCmd.snapshotFiles...)

46
pkg/commands/arg.go Normal file
View File

@ -0,0 +1,46 @@
/*
Copyright 2018 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
"strings"
)
type ArgCommand struct {
cmd *instructions.ArgCommand
}
// ExecuteCommand only needs to add this ARG key/value as seen
func (r *ArgCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("ARG")
buildArgs.AddArg(r.cmd.Key, r.cmd.Value)
return nil
}
// FilesToSnapshot returns an empty array since this command only touches metadata.
func (r *ArgCommand) FilesToSnapshot() []string {
return []string{}
}
// CreatedBy returns some information about the command for the image config history
func (r *ArgCommand) CreatedBy() string {
return strings.Join([]string{r.cmd.Name(), r.cmd.Key}, " ")
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"strings"
"github.com/docker/docker/builder/dockerfile/instructions"
@ -30,7 +31,7 @@ type CmdCommand struct {
// ExecuteCommand executes the CMD command
// Argument handling is the same as RUN.
func (c *CmdCommand) ExecuteCommand(config *v1.Config) error {
func (c *CmdCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: CMD")
var newCommand []string
if c.cmd.PrependShell {

View File

@ -16,12 +16,10 @@ limitations under the License.
package commands
import (
"testing"
"github.com/google/go-containerregistry/v1"
"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"testing"
)
var cmdTests = []struct {
@ -56,7 +54,7 @@ func TestExecuteCmd(t *testing.T) {
},
},
}
err := cmd.ExecuteCommand(cfg)
err := cmd.ExecuteCommand(cfg, nil)
testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedCmd, cfg.Cmd)
}
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/pkg/errors"
@ -28,7 +29,7 @@ type DockerCommand interface {
// 1. Making required changes to the filesystem (ex. copying files for ADD/COPY or setting ENV variables)
// 2. Updating metadata fields in the config
// It should not change the config history.
ExecuteCommand(*v1.Config) error
ExecuteCommand(*v1.Config, *dockerfile.BuildArgs) error
// The config history has a "created by" field, should return information about the command
CreatedBy() string
// A list of files to snapshot, empty for metadata commands or nil if we don't know
@ -63,6 +64,8 @@ func GetCommand(cmd instructions.Command, buildcontext string) (DockerCommand, e
return &VolumeCommand{cmd: c}, nil
case *instructions.StopSignalCommand:
return &StopSignalCommand{cmd: c}, nil
case *instructions.ArgCommand:
return &ArgCommand{cmd: c}, nil
case *instructions.MaintainerCommand:
logrus.Warnf("%s is deprecated, skipping", cmd.Name())
return nil, nil

View File

@ -18,13 +18,15 @@ package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
"os"
"path/filepath"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
)
type CopyCommand struct {
@ -33,15 +35,16 @@ type CopyCommand struct {
snapshotFiles []string
}
func (c *CopyCommand) ExecuteCommand(config *v1.Config) error {
func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
srcs := c.cmd.SourcesAndDest[:len(c.cmd.SourcesAndDest)-1]
dest := c.cmd.SourcesAndDest[len(c.cmd.SourcesAndDest)-1]
logrus.Infof("cmd: copy %s", srcs)
logrus.Infof("dest: %s", dest)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
// First, resolve any environment replacement
resolvedEnvs, err := util.ResolveEnvironmentReplacementList(c.cmd.SourcesAndDest, config.Env, true)
resolvedEnvs, err := util.ResolveEnvironmentReplacementList(c.cmd.SourcesAndDest, replacementEnvs, true)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"strings"
"github.com/docker/docker/builder/dockerfile/instructions"
@ -29,7 +30,7 @@ type EntrypointCommand struct {
}
// ExecuteCommand handles command processing similar to CMD and RUN,
func (e *EntrypointCommand) ExecuteCommand(config *v1.Config) error {
func (e *EntrypointCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: ENTRYPOINT")
var newCommand []string
if e.cmd.PrependShell {

View File

@ -55,7 +55,7 @@ func TestEntrypointExecuteCmd(t *testing.T) {
},
},
}
err := cmd.ExecuteCommand(cfg)
err := cmd.ExecuteCommand(cfg, nil)
testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedCmd, cfg.Entrypoint)
}
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/util"
@ -29,15 +30,16 @@ type EnvCommand struct {
cmd *instructions.EnvCommand
}
func (e *EnvCommand) ExecuteCommand(config *v1.Config) error {
func (e *EnvCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: ENV")
newEnvs := e.cmd.Env
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
for index, pair := range newEnvs {
expandedKey, err := util.ResolveEnvironmentReplacement(pair.Key, config.Env, false)
expandedKey, err := util.ResolveEnvironmentReplacement(pair.Key, replacementEnvs, false)
if err != nil {
return err
}
expandedValue, err := util.ResolveEnvironmentReplacement(pair.Value, config.Env, false)
expandedValue, err := util.ResolveEnvironmentReplacement(pair.Value, replacementEnvs, false)
if err != nil {
return err
}

View File

@ -16,11 +16,12 @@ limitations under the License.
package commands
import (
"testing"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/testutil"
docker "github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"testing"
)
func TestUpdateEnvConfig(t *testing.T) {
@ -77,6 +78,10 @@ func Test_EnvExecute(t *testing.T) {
Key: "$path",
Value: "$home/",
},
{
Key: "$buildArg1",
Value: "$buildArg2",
},
},
},
}
@ -86,7 +91,20 @@ func Test_EnvExecute(t *testing.T) {
"home=/root",
"HOME=/root",
"/usr/=/root/",
"foo=foo2",
}
err := envCmd.ExecuteCommand(cfg)
buildArgs := setUpBuildArgs()
err := envCmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, false, err, expectedEnvs, cfg.Env)
}
func setUpBuildArgs() *docker.BuildArgs {
buildArgs := dockerfile.NewBuildArgs([]string{
"buildArg1=foo",
"buildArg2=foo2",
})
buildArgs.AddArg("buildArg1", nil)
d := "default"
buildArgs.AddArg("buildArg2", &d)
return buildArgs
}

View File

@ -18,6 +18,7 @@ package commands
import (
"fmt"
"github.com/docker/docker/builder/dockerfile"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/util"
@ -30,17 +31,18 @@ type ExposeCommand struct {
cmd *instructions.ExposeCommand
}
func (r *ExposeCommand) ExecuteCommand(config *v1.Config) error {
func (r *ExposeCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: EXPOSE")
// Grab the currently exposed ports
existingPorts := config.ExposedPorts
if existingPorts == nil {
existingPorts = make(map[string]struct{})
}
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
// Add any new ones in
for _, p := range r.cmd.Ports {
// Resolve any environment variables
p, err := util.ResolveEnvironmentReplacement(p, config.Env, false)
p, err := util.ResolveEnvironmentReplacement(p, replacementEnvs, false)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"testing"
"github.com/GoogleContainerTools/kaniko/testutil"
@ -60,8 +61,8 @@ func TestUpdateExposedPorts(t *testing.T) {
"8085/tcp": {},
"8085/udp": {},
}
err := exposeCmd.ExecuteCommand(cfg)
buildArgs := dockerfile.NewBuildArgs([]string{})
err := exposeCmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, false, err, expectedPorts, cfg.ExposedPorts)
}
@ -79,7 +80,7 @@ func TestInvalidProtocol(t *testing.T) {
Ports: ports,
},
}
err := exposeCmd.ExecuteCommand(cfg)
buildArgs := dockerfile.NewBuildArgs([]string{})
err := exposeCmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, true, err, nil, nil)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/util"
@ -29,24 +30,29 @@ type LabelCommand struct {
cmd *instructions.LabelCommand
}
func (r *LabelCommand) ExecuteCommand(config *v1.Config) error {
func (r *LabelCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: LABEL")
return updateLabels(r.cmd.Labels, config)
return updateLabels(r.cmd.Labels, config, buildArgs)
}
func updateLabels(labels []instructions.KeyValuePair, config *v1.Config) error {
func updateLabels(labels []instructions.KeyValuePair, config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
existingLabels := config.Labels
if existingLabels == nil {
existingLabels = make(map[string]string)
}
// Let's unescape values before setting the label
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
for index, kvp := range labels {
unescaped, err := util.ResolveEnvironmentReplacement(kvp.Value, []string{}, false)
key, err := util.ResolveEnvironmentReplacement(kvp.Key, replacementEnvs, false)
if err != nil {
return err
}
unescaped, err := util.ResolveEnvironmentReplacement(kvp.Value, replacementEnvs, false)
if err != nil {
return err
}
labels[index] = instructions.KeyValuePair{
Key: kvp.Key,
Key: key,
Value: unescaped,
}
}

View File

@ -17,11 +17,11 @@ limitations under the License.
package commands
import (
"testing"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"testing"
)
func TestUpdateLabels(t *testing.T) {
@ -48,14 +48,25 @@ func TestUpdateLabels(t *testing.T) {
Key: "backslashes",
Value: "lots\\\\ of\\\\ words",
},
{
Key: "$label",
Value: "foo",
},
}
expectedLabels := map[string]string{
"foo": "override",
"bar": "baz",
"multiword": "lots of words",
"backslashes": "lots\\ of\\ words",
arguments := []string{
"label=build_arg_label",
}
updateLabels(labels, cfg)
buildArgs := dockerfile.NewBuildArgs(arguments)
buildArgs.AddArg("label", nil)
expectedLabels := map[string]string{
"foo": "override",
"bar": "baz",
"multiword": "lots of words",
"backslashes": "lots\\ of\\ words",
"build_arg_label": "foo",
}
updateLabels(labels, cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, false, nil, expectedLabels, cfg.Labels)
}

View File

@ -18,6 +18,7 @@ package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
@ -28,10 +29,11 @@ type OnBuildCommand struct {
}
//ExecuteCommand adds the specified expression in Onbuild to the config
func (o *OnBuildCommand) ExecuteCommand(config *v1.Config) error {
func (o *OnBuildCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: ONBUILD")
logrus.Infof("args: %s", o.cmd.Expression)
resolvedExpression, err := util.ResolveEnvironmentReplacement(o.cmd.Expression, config.Env, false)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
resolvedExpression, err := util.ResolveEnvironmentReplacement(o.cmd.Expression, replacementEnvs, false)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"testing"
"github.com/GoogleContainerTools/kaniko/testutil"
@ -62,8 +63,8 @@ func TestExecuteOnbuild(t *testing.T) {
Expression: test.expression,
},
}
err := onbuildCmd.ExecuteCommand(cfg)
buildArgs := dockerfile.NewBuildArgs([]string{})
err := onbuildCmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedArray, cfg.OnBuild)
}

View File

@ -17,22 +17,23 @@ limitations under the License.
package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
)
type RunCommand struct {
cmd *instructions.RunCommand
}
func (r *RunCommand) ExecuteCommand(config *v1.Config) error {
func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
var newCommand []string
if r.cmd.PrependShell {
// This is the default shell on Linux
@ -54,7 +55,8 @@ func (r *RunCommand) ExecuteCommand(config *v1.Config) error {
cmd := exec.Command(newCommand[0], newCommand[1:]...)
cmd.Dir = config.WorkingDir
cmd.Stdout = os.Stdout
cmd.Env = config.Env
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
cmd.Env = replacementEnvs
// If specified, run the command as a specific user
if config.User != "" {

View File

@ -17,11 +17,11 @@ limitations under the License.
package commands
import (
"strings"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
"strings"
)
type ShellCommand struct {
@ -29,7 +29,7 @@ type ShellCommand struct {
}
// ExecuteCommand handles command processing similar to CMD and RUN,
func (s *ShellCommand) ExecuteCommand(config *v1.Config) error {
func (s *ShellCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: SHELL")
var newShell []string

View File

@ -49,7 +49,7 @@ func TestShellExecuteCmd(t *testing.T) {
Shell: test.cmdLine,
},
}
err := cmd.ExecuteCommand(cfg)
err := cmd.ExecuteCommand(cfg, nil)
testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedShell, cfg.Shell)
}
}

View File

@ -17,13 +17,13 @@ limitations under the License.
package commands
import (
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/docker/docker/pkg/signal"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
"strings"
)
type StopSignalCommand struct {
@ -31,11 +31,12 @@ type StopSignalCommand struct {
}
// ExecuteCommand handles command processing similar to CMD and RUN,
func (s *StopSignalCommand) ExecuteCommand(config *v1.Config) error {
func (s *StopSignalCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: STOPSIGNAL")
// resolve possible environment variables
resolvedEnvs, err := util.ResolveEnvironmentReplacementList([]string{s.cmd.Signal}, config.Env, false)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
resolvedEnvs, err := util.ResolveEnvironmentReplacementList([]string{s.cmd.Signal}, replacementEnvs, false)
if err != nil {
return err
}

View File

@ -16,11 +16,11 @@ limitations under the License.
package commands
import (
"testing"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"testing"
)
var stopsignalTests = []struct {
@ -54,7 +54,8 @@ func TestStopsignalExecuteCmd(t *testing.T) {
Signal: test.signal,
},
}
err := cmd.ExecuteCommand(cfg)
b := dockerfile.NewBuildArgs([]string{})
err := cmd.ExecuteCommand(cfg, b)
testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedSignal, cfg.StopSignal)
}
}

View File

@ -17,30 +17,31 @@ limitations under the License.
package commands
import (
"os/user"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
"os/user"
"strings"
)
type UserCommand struct {
cmd *instructions.UserCommand
}
func (r *UserCommand) ExecuteCommand(config *v1.Config) error {
func (r *UserCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: USER")
u := r.cmd.User
userAndGroup := strings.Split(u, ":")
userStr, err := util.ResolveEnvironmentReplacement(userAndGroup[0], config.Env, false)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
userStr, err := util.ResolveEnvironmentReplacement(userAndGroup[0], replacementEnvs, false)
if err != nil {
return err
}
var groupStr string
if len(userAndGroup) > 1 {
groupStr, err = util.ResolveEnvironmentReplacement(userAndGroup[1], config.Env, false)
groupStr, err = util.ResolveEnvironmentReplacement(userAndGroup[1], replacementEnvs, false)
if err != nil {
return err
}

View File

@ -16,6 +16,7 @@ limitations under the License.
package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"testing"
"github.com/GoogleContainerTools/kaniko/testutil"
@ -93,7 +94,8 @@ func TestUpdateUser(t *testing.T) {
User: test.user,
},
}
err := cmd.ExecuteCommand(cfg)
buildArgs := dockerfile.NewBuildArgs([]string{})
err := cmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, test.shouldError, err, test.expectedUid, cfg.User)
}
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"os"
"strings"
@ -31,10 +32,11 @@ type VolumeCommand struct {
snapshotFiles []string
}
func (v *VolumeCommand) ExecuteCommand(config *v1.Config) error {
func (v *VolumeCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: VOLUME")
volumes := v.cmd.Volumes
resolvedVolumes, err := util.ResolveEnvironmentReplacementList(volumes, config.Env, true)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
resolvedVolumes, err := util.ResolveEnvironmentReplacementList(volumes, replacementEnvs, true)
if err != nil {
return err
}

View File

@ -16,6 +16,7 @@ limitations under the License.
package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"testing"
"github.com/GoogleContainerTools/kaniko/testutil"
@ -49,7 +50,7 @@ func TestUpdateVolume(t *testing.T) {
"/var/lib": {},
"/etc": {},
}
err := volumeCmd.ExecuteCommand(cfg)
buildArgs := dockerfile.NewBuildArgs([]string{})
err := volumeCmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, false, err, expectedVolumes, cfg.Volumes)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package commands
import (
"github.com/docker/docker/builder/dockerfile"
"os"
"path/filepath"
@ -31,10 +32,11 @@ type WorkdirCommand struct {
snapshotFiles []string
}
func (w *WorkdirCommand) ExecuteCommand(config *v1.Config) error {
func (w *WorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: workdir")
workdirPath := w.cmd.Path
resolvedWorkingDir, err := util.ResolveEnvironmentReplacement(workdirPath, config.Env, true)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
resolvedWorkingDir, err := util.ResolveEnvironmentReplacement(workdirPath, replacementEnvs, true)
if err != nil {
return err
}

View File

@ -16,6 +16,7 @@ limitations under the License.
package commands
import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"testing"
"github.com/GoogleContainerTools/kaniko/testutil"
@ -78,7 +79,8 @@ func TestWorkdirCommand(t *testing.T) {
},
snapshotFiles: []string{},
}
cmd.ExecuteCommand(cfg)
buildArgs := dockerfile.NewBuildArgs([]string{})
cmd.ExecuteCommand(cfg, buildArgs)
testutil.CheckErrorAndDeepEqual(t, false, nil, test.expectedPath, cfg.WorkingDir)
}
}

View File

@ -0,0 +1,35 @@
/*
Copyright 2018 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dockerfile
import (
d "github.com/docker/docker/builder/dockerfile"
"strings"
)
func NewBuildArgs(args []string) *d.BuildArgs {
argsFromOptions := make(map[string]*string)
for _, a := range args {
s := strings.Split(a, "=")
if len(s) == 1 {
argsFromOptions[s[0]] = nil
} else {
argsFromOptions[s[0]] = &s[1]
}
}
return d.NewBuildArgs(argsFromOptions)
}

View File

@ -44,7 +44,7 @@ import (
"github.com/sirupsen/logrus"
)
func DoBuild(dockerfilePath, srcContext, destination, snapshotMode string, dockerInsecureSkipTLSVerify bool) error {
func DoBuild(dockerfilePath, srcContext, destination, snapshotMode string, dockerInsecureSkipTLSVerify bool, args []string) error {
// Parse dockerfile and unpack base image to root
d, err := ioutil.ReadFile(dockerfilePath)
if err != nil {
@ -108,6 +108,7 @@ func DoBuild(dockerfilePath, srcContext, destination, snapshotMode string, docke
if err != nil {
return err
}
buildArgs := dockerfile.NewBuildArgs(args)
// Currently only supports single stage builds
for _, stage := range stages {
if err := resolveOnBuild(&stage, &imageConfig.Config); err != nil {
@ -121,7 +122,7 @@ func DoBuild(dockerfilePath, srcContext, destination, snapshotMode string, docke
if dockerCommand == nil {
continue
}
if err := dockerCommand.ExecuteCommand(&imageConfig.Config); err != nil {
if err := dockerCommand.ExecuteCommand(&imageConfig.Config, buildArgs); err != nil {
return err
}
// Now, we get the files to snapshot from this command and take the snapshot

View File

@ -17,9 +17,11 @@ limitations under the License.
package util
import (
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/docker/docker/builder/dockerfile/parser"
"github.com/docker/docker/builder/dockerfile/shell"
"github.com/google/go-containerregistry/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"net/http"
@ -222,3 +224,10 @@ func IsSrcRemoteFileURL(rawurl string) bool {
}
return true
}
// ReplacementEnvs returns a list of all variables that can be used for
// environment replacement
func ReplacementEnvs(config *v1.Config, buildArgs *dockerfile.BuildArgs) []string {
filtered := buildArgs.FilterAllowed(config.Env)
return append(config.Env, filtered...)
}