Refactor command line arguments and the executor

In this refactor I:

1. Created KanikoOptions to make it easier to pass around arguments
passed in through the command line
2. Reorganized executor.go by putting the logic for pushing the image in
a new file push.go
3. Made some error messages clearer
4. Fixed a mistake in the README for pushing to AWS
5. Marked the --bucket flag as hidden since we want people to use
--context instead, and marked an aws flag as hidden which is set in a
vendored directorya
This commit is contained in:
Priya Wadhwa
2018-08-23 13:30:36 -07:00
parent 8f71b7fb26
commit cfa822f178
7 changed files with 214 additions and 177 deletions
@@ -18,21 +18,16 @@ package executor
import (
"bytes"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strconv"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/authn/k8schain"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/sirupsen/logrus"
@@ -40,37 +35,26 @@ import (
"github.com/GoogleContainerTools/kaniko/pkg/commands"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/pkg/options"
"github.com/GoogleContainerTools/kaniko/pkg/snapshot"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/GoogleContainerTools/kaniko/pkg/version"
)
// KanikoBuildArgs contains all the args required to build the image
type KanikoBuildArgs struct {
DockerfilePath string
SrcContext string
SnapshotMode string
Args []string
SingleSnapshot bool
Reproducible bool
Target string
}
func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
func DoBuild(opts *options.KanikoOptions) (v1.Image, error) {
// Parse dockerfile and unpack base image to root
stages, err := dockerfile.Stages(k.DockerfilePath, k.Target)
stages, err := dockerfile.Stages(opts.DockerfilePath, opts.Target)
if err != nil {
return nil, err
}
hasher, err := getHasher(k.SnapshotMode)
hasher, err := getHasher(opts.SnapshotMode)
if err != nil {
return nil, err
}
for index, stage := range stages {
finalStage := finalStage(index, k.Target, stages)
finalStage := finalStage(index, opts.Target, stages)
// Unpack file system to root
sourceImage, err := util.RetrieveSourceImage(index, k.Args, stages)
sourceImage, err := util.RetrieveSourceImage(index, opts.BuildArgs, stages)
if err != nil {
return nil, err
}
@@ -90,10 +74,10 @@ func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
if err := resolveOnBuild(&stage, &imageConfig.Config); err != nil {
return nil, err
}
buildArgs := dockerfile.NewBuildArgs(k.Args)
buildArgs := dockerfile.NewBuildArgs(opts.BuildArgs)
for index, cmd := range stage.Commands {
finalCmd := index == len(stage.Commands)-1
dockerCommand, err := commands.GetCommand(cmd, k.SrcContext)
dockerCommand, err := commands.GetCommand(cmd, opts.SrcContext)
if err != nil {
return nil, err
}
@@ -105,7 +89,7 @@ func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
}
// Don't snapshot if it's not the final stage and not the final command
// Also don't snapshot if it's the final stage, not the final command, and single snapshot is set
if (!finalStage && !finalCmd) || (finalStage && !finalCmd && k.SingleSnapshot) {
if (!finalStage && !finalCmd) || (finalStage && !finalCmd && opts.SingleSnapshot) {
continue
}
// Now, we get the files to snapshot from this command and take the snapshot
@@ -148,7 +132,7 @@ func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
return nil, err
}
if finalStage {
if k.Reproducible {
if opts.Reproducible {
sourceImage, err = mutate.Canonical(sourceImage)
if err != nil {
return nil, err
@@ -172,64 +156,6 @@ func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
return nil, err
}
type withUserAgent struct {
t http.RoundTripper
}
func (w *withUserAgent) RoundTrip(r *http.Request) (*http.Response, error) {
r.Header.Set("User-Agent", fmt.Sprintf("kaniko/%s", version.Version()))
return w.t.RoundTrip(r)
}
func DoPush(image v1.Image, destinations []string, tarPath string, dockerInsecureSkipTLSVerify bool) error {
// continue pushing unless an error occurs
for _, destination := range destinations {
// Push the image
destRef, err := name.NewTag(destination, name.WeakValidation)
if err != nil {
return err
}
if dockerInsecureSkipTLSVerify {
newReg, err := name.NewInsecureRegistry(destRef.Repository.Registry.Name(), name.WeakValidation)
if err != nil {
return err
}
destRef.Repository.Registry = newReg
}
if tarPath != "" {
return tarball.WriteToFile(tarPath, destRef, image, nil)
}
k8sc, err := k8schain.NewNoClient()
if err != nil {
return err
}
kc := authn.NewMultiKeychain(authn.DefaultKeychain, k8sc)
pushAuth, err := kc.Resolve(destRef.Context().Registry)
if err != nil {
return err
}
// Create a transport to set our user-agent.
tr := http.DefaultTransport
if dockerInsecureSkipTLSVerify {
tr.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
rt := &withUserAgent{t: tr}
if err := remote.Write(destRef, image, pushAuth, rt, remote.WriteOptions{}); err != nil {
logrus.Error(fmt.Errorf("Failed to push to destination %s", destination))
return err
}
}
return nil
}
func finalStage(index int, target string, stages []instructions.Stage) bool {
if index == len(stages)-1 {
return true
+95
View File
@@ -0,0 +1,95 @@
/*
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 executor
import (
"crypto/tls"
"fmt"
"net/http"
"github.com/GoogleContainerTools/kaniko/pkg/options"
"github.com/GoogleContainerTools/kaniko/pkg/version"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/authn/k8schain"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/sirupsen/logrus"
)
type withUserAgent struct {
t http.RoundTripper
}
func (w *withUserAgent) RoundTrip(r *http.Request) (*http.Response, error) {
r.Header.Set("User-Agent", fmt.Sprintf("kaniko/%s", version.Version()))
return w.t.RoundTrip(r)
}
// DoPush is responsible for pushing image to the destinations specified in opts
func DoPush(image v1.Image, opts *options.KanikoOptions) error {
if opts.NoPush {
logrus.Info("Skipping push to container registry due to --no-push flag")
return nil
}
// continue pushing unless an error occurs
for _, destination := range opts.Destinations {
// Push the image
destRef, err := name.NewTag(destination, name.WeakValidation)
if err != nil {
return err
}
if opts.DockerInsecureSkipTLSVerify {
newReg, err := name.NewInsecureRegistry(destRef.Repository.Registry.Name(), name.WeakValidation)
if err != nil {
return err
}
destRef.Repository.Registry = newReg
}
if opts.TarPath != "" {
return tarball.WriteToFile(opts.TarPath, destRef, image, nil)
}
k8sc, err := k8schain.NewNoClient()
if err != nil {
return err
}
kc := authn.NewMultiKeychain(authn.DefaultKeychain, k8sc)
pushAuth, err := kc.Resolve(destRef.Context().Registry)
if err != nil {
return err
}
// Create a transport to set our user-agent.
tr := http.DefaultTransport
if opts.DockerInsecureSkipTLSVerify {
tr.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
rt := &withUserAgent{t: tr}
if err := remote.Write(destRef, image, pushAuth, rt, remote.WriteOptions{}); err != nil {
logrus.Error(fmt.Errorf("Failed to push to destination %s", destination))
return err
}
}
return nil
}