Skip to content

Commit

Permalink
Ensure kaniko e2e test pushes image to registry
Browse files Browse the repository at this point in the history
Adds `github.com/google/go-containerregistry` as a dependency for
accessing container registries

Adds `KANIKO_SECRET_CONFIG_FILE` for adding a service account to the
kaniko task when running e2e test locally.

Fixes tektoncd#150
  • Loading branch information
Tanner Bruce committed Oct 16, 2018
1 parent fd9fb0e commit bfe69f0
Show file tree
Hide file tree
Showing 53 changed files with 4,564 additions and 26 deletions.
20 changes: 20 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

158 changes: 132 additions & 26 deletions test/kaniko_task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@ limitations under the License.
package test

import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strings"
"testing"
"time"

"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
buildv1alpha1 "github.com/knative/build/pkg/apis/build/v1alpha1"
duckv1alpha1 "github.com/knative/pkg/apis/duck/v1alpha1"
knativetest "github.com/knative/pkg/test"
"github.com/knative/pkg/test/logging"
"io/ioutil"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"os"
"regexp"
"strings"
"testing"
"time"

"github.com/knative/build-pipeline/pkg/apis/pipeline/v1alpha1"
)
Expand All @@ -51,7 +52,7 @@ func getGitResource(namespace string) *v1alpha1.PipelineResource {
Spec: v1alpha1.PipelineResourceSpec{
Type: v1alpha1.PipelineResourceTypeGit,
Params: []v1alpha1.Param{
v1alpha1.Param{
{
Name: "Url",
Value: "https://github.com/pivotal-nader-ziada/gohelloworld",
},
Expand All @@ -60,24 +61,50 @@ func getGitResource(namespace string) *v1alpha1.PipelineResource {
}
}

func getTask(namespace string, t *testing.T) *v1alpha1.Task {
func getDockerRepo() (string, error) {
// according to knative/test-infra readme (https://github.com/knative/test-infra/blob/13055d769cc5e1756e605fcb3bcc1c25376699f1/scripts/README.md)
// the KO_DOCKER_REPO will be set with according to the porject where the cluster is created
// it is used here to dunamically get the docker registery to push the image to
// the KO_DOCKER_REPO will be set with according to the project where the cluster is created
// it is used here to dynamically get the docker registry to push the image to
dockerRepo := os.Getenv("KO_DOCKER_REPO")
if dockerRepo == "" {
t.Fatalf("KO_DOCKER_REPO env variable is required")
return "", fmt.Errorf("KO_DOCKER_REPO env variable is required")
}
return fmt.Sprintf("%s/kanikotasktest", dockerRepo), nil
}

func createSecret(c *knativetest.KubeClient, namespace string) (bool, error) {
// when running e2e in cluster, this will not be set so just hop out early
file := os.Getenv("KANIKO_SECRET_CONFIG_FILE")
if file == "" {
return false, nil
}

sec := &corev1.Secret{}
sec.Name = "kaniko-secret"
sec.Namespace = namespace

return &v1alpha1.Task{
bs, err := ioutil.ReadFile(file)
if err != nil {
return false, fmt.Errorf("couldn't read kaniko secret json: %v", err)
}

sec.Data = map[string][]byte{
"config.json": bs,
}
_, err = c.Kube.CoreV1().Secrets(namespace).Create(sec)
return true, err
}

func getTask(repo, namespace string, withSecretConfig bool) *v1alpha1.Task {
task := &v1alpha1.Task{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: kanikoTaskName,
},
Spec: v1alpha1.TaskSpec{
Inputs: &v1alpha1.Inputs{
Resources: []v1alpha1.TaskResource{
v1alpha1.TaskResource{
{
Name: kanikoResourceName,
Type: v1alpha1.PipelineResourceTypeGit,
},
Expand All @@ -89,12 +116,40 @@ func getTask(namespace string, t *testing.T) *v1alpha1.Task {
Name: "kaniko",
Image: "gcr.io/kaniko-project/executor",
Args: []string{"--dockerfile=/workspace/Dockerfile",
fmt.Sprintf("--destination=%s/kanikotasktest", dockerRepo),
fmt.Sprintf("--destination=%s", repo),
},
}},
},
},
}
if withSecretConfig {
step := task.Spec.BuildSpec.Steps[0]
step.VolumeMounts = []corev1.VolumeMount{
{
Name: "kaniko-secret",
MountPath: "/secrets",
},
}
step.Env = []corev1.EnvVar{
{
Name: "GOOGLE_APPLICATION_CREDENTIALS",
Value: "/secrets/config.json",
},
}
task.Spec.BuildSpec.Volumes = []corev1.Volume{
{
Name: "kaniko-secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "kaniko-secret",
},
},
},
}
task.Spec.BuildSpec.Steps[0] = step
}

return task
}

func getTaskRun(namespace string) *v1alpha1.TaskRun {
Expand All @@ -114,7 +169,7 @@ func getTaskRun(namespace string) *v1alpha1.TaskRun {
},
Inputs: v1alpha1.TaskRunInputs{
Resources: []v1alpha1.PipelineResourceVersion{
v1alpha1.PipelineResourceVersion{
{
ResourceRef: v1alpha1.PipelineResourceRef{
Name: kanikoResourceName,
},
Expand All @@ -131,16 +186,30 @@ func TestKanikoTaskRun(t *testing.T) {
logger := logging.GetContextLogger(t.Name())
c, namespace := setup(t, logger)

repo, err := getDockerRepo()
if err != nil {
t.Errorf("Expected to get docker repo")
}
ref, err := name.ParseReference(repo, name.WeakValidation)
if err != nil {
t.Errorf("Expected to be able to parse image reference %q: %v", r, err)
}

knativetest.CleanupOnInterrupt(func() { tearDown(logger, c.KubeClient, namespace) }, logger)
defer tearDown(logger, c.KubeClient, namespace)

hasSecretConfig, err := createSecret(c.KubeClient, namespace)
if err != nil {
t.Fatalf("Expected to create kaniko creds: %v", err)
}

logger.Infof("Creating Git PipelineResource %s", kanikoResourceName)
if _, err := c.PipelineResourceClient.Create(getGitResource(namespace)); err != nil {
t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoResourceName, err)
}

logger.Infof("Creating Task %s", kanikoTaskName)
if _, err := c.TaskClient.Create(getTask(namespace, t)); err != nil {
if _, err := c.TaskClient.Create(getTask(repo, namespace, hasSecretConfig)); err != nil {
t.Fatalf("Failed to create Task `%s`: %s", kanikoTaskName, err)
}

Expand All @@ -164,6 +233,7 @@ func TestKanikoTaskRun(t *testing.T) {
t.Errorf("Error waiting for TaskRun %s to finish: %s", kanikoTaskRunName, err)
}


// The Build created by the TaskRun will have the same name
b, err := c.BuildClient.Get(kanikoTaskRunName, metav1.GetOptions{})
if err != nil {
Expand All @@ -175,19 +245,55 @@ func TestKanikoTaskRun(t *testing.T) {
}
podName := cluster.PodName
pods := c.KubeClient.Kube.CoreV1().Pods(namespace)
t.Logf("Retrieved pods for podname %s: %s\n", podName, pods)
logger.Infof("Retrieved pods for podname %s: %s\n", podName, pods)

req := pods.GetLogs(podName, &corev1.PodLogOptions{})
// get the logs for the kaniko step
req := pods.GetLogs(podName, &corev1.PodLogOptions{Container: "build-step-kaniko"})
readCloser, err := req.Stream()
if err != nil {
t.Fatalf("Failed to open stream to read: %v", err)
}
defer readCloser.Close()
var buf bytes.Buffer
out := bufio.NewWriter(&buf)
_, err = io.Copy(out, readCloser)
if !strings.Contains(buf.String(), kanikoBuildOutput) {
t.Fatalf("Expected output %s from pod %s but got %s", kanikoBuildOutput, podName, buf.String())
bs, err := ioutil.ReadAll(readCloser)
if err != nil {
t.Fatalf("Failed to read pod log stream: %v", err)
}
initLogs := string(bs)
readCloser.Close()

// get the pods' logs
req = pods.GetLogs(podName, &corev1.PodLogOptions{})
readCloser, err = req.Stream()
if err != nil {
t.Fatalf("Failed to open stream to read: %v", err)
}
readCloser.Close()
bs, err = ioutil.ReadAll(readCloser)
if err != nil {
t.Fatalf("Failed to read pod log stream: %v", err)
}
podLogs := string(bs)

// check the logs match what we expect
if !strings.Contains(podLogs, kanikoBuildOutput) {
t.Fatalf("Expected output %s from pod %s but got %s", kanikoBuildOutput, podName, string(bs))
}
// make sure the pushed digest matches the one we pushed
re := regexp.MustCompile("digest: (sha256:\\w+)")
ms := re.FindAllStringSubmatch(initLogs, -1)
if len(ms) != 1 && len(ms[0]) < 2 {
t.Fatalf("Expected to find one image digest in the build output")
}
localDigest := ms[0][1]
// pull digest from pushed image
img, err := remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
t.Errorf("Expected to be able to pull remote ref %s: %v", ref, err)
}
digest, err := img.Digest()
if err != nil {
t.Errorf("Expected to get digest for image %s: %v", img, err)
}
if digest.String() != localDigest {
t.Errorf("Expected built digest %s to match remote digest %s", localDigest, digest)
}
}
Loading

0 comments on commit bfe69f0

Please sign in to comment.