From 0cf18cef32cb79dcc25410a21f406c370d4d7396 Mon Sep 17 00:00:00 2001 From: dherges Date: Sat, 21 Dec 2024 13:58:39 +0100 Subject: [PATCH 1/7] feat: add config option kaniko.imagePullSecret --- pkg/skaffold/schema/latest/config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go index 860efb7f673..0ab52a742ca 100644 --- a/pkg/skaffold/schema/latest/config.go +++ b/pkg/skaffold/schema/latest/config.go @@ -1465,6 +1465,9 @@ type KanikoArtifact struct { // Defaults to the latest released version of `gcr.io/kaniko-project/executor`. Image string `yaml:"image,omitempty"` + // ImagePullSecret is the name of the Kubernetes secret for pulling kaniko image and kaniko init image from a private registry + ImagePullSecret string `yaml:"imagePullSecret,omitempty"` + // Destination is additional tags to push. Destination []string `yaml:"destination,omitempty"` From 6f5fe9ea9572b5570b1ddab1b8d08cb1308f9aaa Mon Sep 17 00:00:00 2001 From: dherges Date: Sat, 21 Dec 2024 13:58:39 +0100 Subject: [PATCH 2/7] feat: pull kaniko images from private registry w/ pull secret --- pkg/skaffold/build/cluster/pod.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/skaffold/build/cluster/pod.go b/pkg/skaffold/build/cluster/pod.go index 1932d7e890c..75d329dd2f3 100644 --- a/pkg/skaffold/build/cluster/pod.go +++ b/pkg/skaffold/build/cluster/pod.go @@ -95,6 +95,13 @@ func (b *Builder) kanikoPodSpec(artifact *latest.KanikoArtifact, tag string, pla addSecretVolume(pod, kaniko.DefaultSecretName, b.ClusterDetails.PullSecretMountPath, b.ClusterDetails.PullSecretName) } + // Add secret for pulling kaniko images from a private registry + if artifact.ImagePullSecret != "" { + pod.Spec.ImagePullSecrets = []v1.LocalObjectReference{{ + Name: artifact.ImagePullSecret, + }} + } + // Add host path volume for cache if artifact.Cache != nil && artifact.Cache.HostPath != "" { addHostPathVolume(pod, kaniko.DefaultCacheDirName, kaniko.DefaultCacheDirMountPath, artifact.Cache.HostPath) From ad284346098a9c997f94420ddf2ff50a8b020dc0 Mon Sep 17 00:00:00 2001 From: dherges Date: Sat, 21 Dec 2024 13:58:40 +0100 Subject: [PATCH 3/7] test: verify pod spec for kaniko.imagePullSecret --- pkg/skaffold/build/cluster/pod_test.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/skaffold/build/cluster/pod_test.go b/pkg/skaffold/build/cluster/pod_test.go index 70d16d410f0..9539614324d 100644 --- a/pkg/skaffold/build/cluster/pod_test.go +++ b/pkg/skaffold/build/cluster/pod_test.go @@ -181,9 +181,10 @@ func TestKanikoArgs(t *testing.T) { func TestKanikoPodSpec(t *testing.T) { artifact := &latest.KanikoArtifact{ - Image: "image", - DockerfilePath: "Dockerfile", - InitImage: "init/image", + Image: "image", + DockerfilePath: "Dockerfile", + InitImage: "init/image", + ImagePullSecret: "image-pull-secret", Destination: []string{ "gcr.io/foo/bar:test-1", "gcr.io/foo/bar:test-2", @@ -353,6 +354,9 @@ func TestKanikoPodSpec(t *testing.T) { }, }, }}, + ImagePullSecrets: []v1.LocalObjectReference{{ + Name: "image-pull-secret", + }}, ServiceAccountName: "aVerySpecialSA", SecurityContext: &v1.PodSecurityContext{ RunAsUser: &runAsUser, From da5ec48e382ff723427cb497c5dd43ac4ca8fd32 Mon Sep 17 00:00:00 2001 From: Angel Montero Date: Tue, 14 Jan 2025 22:55:45 +0000 Subject: [PATCH 4/7] format test --- pkg/skaffold/build/cluster/pod_test.go | 860 ++++++++++++------------- 1 file changed, 430 insertions(+), 430 deletions(-) diff --git a/pkg/skaffold/build/cluster/pod_test.go b/pkg/skaffold/build/cluster/pod_test.go index 9539614324d..f764d850eb0 100644 --- a/pkg/skaffold/build/cluster/pod_test.go +++ b/pkg/skaffold/build/cluster/pod_test.go @@ -17,451 +17,451 @@ limitations under the License. package cluster import ( - "testing" + "testing" - specs "github.com/opencontainers/image-spec/specs-go/v1" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + specs "github.com/opencontainers/image-spec/specs-go/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/build/kaniko" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/platform" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util" - "github.com/GoogleContainerTools/skaffold/v2/testutil" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/build/kaniko" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/platform" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util" + "github.com/GoogleContainerTools/skaffold/v2/testutil" ) func TestKanikoArgs(t *testing.T) { - tests := []struct { - description string - artifact *latest.KanikoArtifact - insecureRegistries map[string]bool - tag string - shouldErr bool - expectedArgs []string - }{ - { - description: "simple build", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - }, - expectedArgs: []string{}, - }, - { - description: "with Destination", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Destination: []string{ - "gcr.io/foo/bar:test-1", - "gcr.io/foo/bar:test-2", - }, - }, - expectedArgs: []string{ - kaniko.DestinationFlag, "gcr.io/foo/bar:test-1", - kaniko.DestinationFlag, "gcr.io/foo/bar:test-2", - }, - }, - { - description: "cache layers", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Cache: &latest.KanikoCache{}, - }, - expectedArgs: []string{kaniko.CacheFlag}, - }, - { - description: "cache layers to specific repo", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Cache: &latest.KanikoCache{ - Repo: "repo", - }, - }, - expectedArgs: []string{"--cache", kaniko.CacheRepoFlag, "repo"}, - }, - { - description: "cache path", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Cache: &latest.KanikoCache{ - HostPath: "/cache", - }, - }, - expectedArgs: []string{ - kaniko.CacheFlag, - kaniko.CacheDirFlag, "/cache"}, - }, - { - description: "target", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Target: "target", - }, - expectedArgs: []string{kaniko.TargetFlag, "target"}, - }, - { - description: "reproducible", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Reproducible: true, - }, - expectedArgs: []string{kaniko.ReproducibleFlag}, - }, - { - description: "build args", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - BuildArgs: map[string]*string{ - "nil_key": nil, - "empty_key": util.Ptr(""), - "value_key": util.Ptr("value"), - }, - }, - expectedArgs: []string{ - kaniko.BuildArgsFlag, "empty_key=", - kaniko.BuildArgsFlag, "nil_key", - kaniko.BuildArgsFlag, "value_key=value"}, - }, - { - description: "invalid build args", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - BuildArgs: map[string]*string{ - "invalid": util.Ptr("{{Invalid"), - }, - }, - shouldErr: true, - }, - { - description: "insecure registries", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - }, - insecureRegistries: map[string]bool{"localhost:4000": true}, - expectedArgs: []string{kaniko.InsecureRegistryFlag, "localhost:4000"}, - }, - { - description: "skip tls", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - SkipTLS: true, - }, - expectedArgs: []string{ - kaniko.SkipTLSFlag, - kaniko.SkipTLSVerifyRegistryFlag, "gcr.io", - }, - }, - { - description: "invalid registry", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - SkipTLS: true, - }, - tag: "!!!!", - shouldErr: true, - }, - } - for _, test := range tests { - testutil.Run(t, test.description, func(t *testutil.T) { - commonArgs := []string{"--destination", "gcr.io/tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext"} + tests := []struct { + description string + artifact *latest.KanikoArtifact + insecureRegistries map[string]bool + tag string + shouldErr bool + expectedArgs []string + }{ + { + description: "simple build", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + }, + expectedArgs: []string{}, + }, + { + description: "with Destination", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Destination: []string{ + "gcr.io/foo/bar:test-1", + "gcr.io/foo/bar:test-2", + }, + }, + expectedArgs: []string{ + kaniko.DestinationFlag, "gcr.io/foo/bar:test-1", + kaniko.DestinationFlag, "gcr.io/foo/bar:test-2", + }, + }, + { + description: "cache layers", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Cache: &latest.KanikoCache{}, + }, + expectedArgs: []string{kaniko.CacheFlag}, + }, + { + description: "cache layers to specific repo", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Cache: &latest.KanikoCache{ + Repo: "repo", + }, + }, + expectedArgs: []string{"--cache", kaniko.CacheRepoFlag, "repo"}, + }, + { + description: "cache path", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Cache: &latest.KanikoCache{ + HostPath: "/cache", + }, + }, + expectedArgs: []string{ + kaniko.CacheFlag, + kaniko.CacheDirFlag, "/cache"}, + }, + { + description: "target", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Target: "target", + }, + expectedArgs: []string{kaniko.TargetFlag, "target"}, + }, + { + description: "reproducible", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Reproducible: true, + }, + expectedArgs: []string{kaniko.ReproducibleFlag}, + }, + { + description: "build args", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + BuildArgs: map[string]*string{ + "nil_key": nil, + "empty_key": util.Ptr(""), + "value_key": util.Ptr("value"), + }, + }, + expectedArgs: []string{ + kaniko.BuildArgsFlag, "empty_key=", + kaniko.BuildArgsFlag, "nil_key", + kaniko.BuildArgsFlag, "value_key=value"}, + }, + { + description: "invalid build args", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + BuildArgs: map[string]*string{ + "invalid": util.Ptr("{{Invalid"), + }, + }, + shouldErr: true, + }, + { + description: "insecure registries", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + }, + insecureRegistries: map[string]bool{"localhost:4000": true}, + expectedArgs: []string{kaniko.InsecureRegistryFlag, "localhost:4000"}, + }, + { + description: "skip tls", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + SkipTLS: true, + }, + expectedArgs: []string{ + kaniko.SkipTLSFlag, + kaniko.SkipTLSVerifyRegistryFlag, "gcr.io", + }, + }, + { + description: "invalid registry", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + SkipTLS: true, + }, + tag: "!!!!", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + commonArgs := []string{"--destination", "gcr.io/tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext"} - tag := "gcr.io/tag" - if test.tag != "" { - tag = test.tag - } - args, err := kanikoArgs(test.artifact, tag, test.insecureRegistries) + tag := "gcr.io/tag" + if test.tag != "" { + tag = test.tag + } + args, err := kanikoArgs(test.artifact, tag, test.insecureRegistries) - t.CheckError(test.shouldErr, err) - if !test.shouldErr { - t.CheckDeepEqual(append(commonArgs, test.expectedArgs...), args) - } - }) - } + t.CheckError(test.shouldErr, err) + if !test.shouldErr { + t.CheckDeepEqual(append(commonArgs, test.expectedArgs...), args) + } + }) + } } func TestKanikoPodSpec(t *testing.T) { - artifact := &latest.KanikoArtifact{ - Image: "image", - DockerfilePath: "Dockerfile", - InitImage: "init/image", - ImagePullSecret: "image-pull-secret", - Destination: []string{ - "gcr.io/foo/bar:test-1", - "gcr.io/foo/bar:test-2", - }, - Env: []v1.EnvVar{{ - Name: "KEY", - Value: "VALUE", - }}, - VolumeMounts: []v1.VolumeMount{ - { - Name: "cm-volume-1", - ReadOnly: true, - MountPath: "/cm-test-mount-path", - SubPath: "/subpath", - }, - { - Name: "secret-volume-1", - ReadOnly: true, - MountPath: "/secret-test-mount-path", - SubPath: "/subpath", - }, - }, - } + artifact := &latest.KanikoArtifact{ + Image: "image", + DockerfilePath: "Dockerfile", + InitImage: "init/image", + ImagePullSecret: "image-pull-secret", + Destination: []string{ + "gcr.io/foo/bar:test-1", + "gcr.io/foo/bar:test-2", + }, + Env: []v1.EnvVar{{ + Name: "KEY", + Value: "VALUE", + }}, + VolumeMounts: []v1.VolumeMount{ + { + Name: "cm-volume-1", + ReadOnly: true, + MountPath: "/cm-test-mount-path", + SubPath: "/subpath", + }, + { + Name: "secret-volume-1", + ReadOnly: true, + MountPath: "/secret-test-mount-path", + SubPath: "/subpath", + }, + }, + } - var runAsUser int64 = 0 + var runAsUser int64 = 0 - builder := &Builder{ - cfg: &mockBuilderContext{}, - ClusterDetails: &latest.ClusterDetails{ - Namespace: "ns", - PullSecretName: "secret", - PullSecretPath: "kaniko-secret.json", - PullSecretMountPath: "/secret", - HTTPProxy: "http://proxy", - HTTPSProxy: "https://proxy", - ServiceAccountName: "aVerySpecialSA", - Annotations: map[string]string{"test": "test"}, - Labels: map[string]string{"test-key": "test-value"}, - RunAsUser: &runAsUser, - Resources: &latest.ResourceRequirements{ - Requests: &latest.ResourceRequirement{ - CPU: "0.1", - }, - Limits: &latest.ResourceRequirement{ - CPU: "0.5", - }, - }, - Volumes: []v1.Volume{ - { - Name: "cm-volume-1", - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "cm-1", - }, - }, - }, - }, - { - Name: "secret-volume-1", - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: "secret-1", - }, - }, - }, - }, - Tolerations: []v1.Toleration{ - { - Key: "app", - Operator: "Equal", - Value: "skaffold", - Effect: "NoSchedule", - TolerationSeconds: nil, - }, - }, - NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, - }, - } - matcher := platform.Matcher{Platforms: []specs.Platform{{OS: "linux", Architecture: "arm64"}}} - pod, _ := builder.kanikoPodSpec(artifact, "tag", matcher) + builder := &Builder{ + cfg: &mockBuilderContext{}, + ClusterDetails: &latest.ClusterDetails{ + Namespace: "ns", + PullSecretName: "secret", + PullSecretPath: "kaniko-secret.json", + PullSecretMountPath: "/secret", + HTTPProxy: "http://proxy", + HTTPSProxy: "https://proxy", + ServiceAccountName: "aVerySpecialSA", + Annotations: map[string]string{"test": "test"}, + Labels: map[string]string{"test-key": "test-value"}, + RunAsUser: &runAsUser, + Resources: &latest.ResourceRequirements{ + Requests: &latest.ResourceRequirement{ + CPU: "0.1", + }, + Limits: &latest.ResourceRequirement{ + CPU: "0.5", + }, + }, + Volumes: []v1.Volume{ + { + Name: "cm-volume-1", + VolumeSource: v1.VolumeSource{ + ConfigMap: &v1.ConfigMapVolumeSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "cm-1", + }, + }, + }, + }, + { + Name: "secret-volume-1", + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: "secret-1", + }, + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "app", + Operator: "Equal", + Value: "skaffold", + Effect: "NoSchedule", + TolerationSeconds: nil, + }, + }, + NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, + }, + } + matcher := platform.Matcher{Platforms: []specs.Platform{{OS: "linux", Architecture: "arm64"}}} + pod, _ := builder.kanikoPodSpec(artifact, "tag", matcher) - expectedPod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{"test": "test"}, - GenerateName: "kaniko-", - Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko", "test-key": "test-value"}, - Namespace: "ns", - }, - Spec: v1.PodSpec{ - InitContainers: []v1.Container{{ - Name: initContainer, - Image: "init/image", - Command: []string{"sh", "-c", "while [ ! -f /tmp/complete ]; do sleep 1; done"}, - VolumeMounts: []v1.VolumeMount{{ - Name: kaniko.DefaultEmptyDirName, - MountPath: kaniko.DefaultEmptyDirMountPath, - }, { - Name: "cm-volume-1", - ReadOnly: true, - MountPath: "/cm-secret-mount-path", - SubPath: "/subpath", - }, { - Name: "secret-volume-1", - ReadOnly: true, - MountPath: "/secret-secret-mount-path", - SubPath: "/subpath", - }}, - Resources: v1.ResourceRequirements{ - Requests: map[v1.ResourceName]resource.Quantity{ - v1.ResourceCPU: resource.MustParse("0.1"), - }, - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("0.5"), - }, - }, - }}, - Containers: []v1.Container{{ - Name: kaniko.DefaultContainerName, - Image: "image", - Args: []string{"--destination", "tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext", "--destination", "gcr.io/foo/bar:test-1", "--destination", "gcr.io/foo/bar:test-2"}, - ImagePullPolicy: v1.PullIfNotPresent, - Env: []v1.EnvVar{{ - Name: "UPSTREAM_CLIENT_TYPE", - Value: "UpstreamClient(skaffold-)", - }, { - Name: "KEY", - Value: "VALUE", - }, { - Name: "HTTP_PROXY", - Value: "http://proxy", - }, { - Name: "HTTPS_PROXY", - Value: "https://proxy", - }, { - Name: "GOOGLE_APPLICATION_CREDENTIALS", - Value: "/secret/kaniko-secret.json", - }}, - VolumeMounts: []v1.VolumeMount{ - { - Name: kaniko.DefaultEmptyDirName, - MountPath: kaniko.DefaultEmptyDirMountPath, - }, - { - Name: kaniko.DefaultSecretName, - MountPath: "/secret", - }, - { - Name: "cm-volume-1", - ReadOnly: true, - MountPath: "/cm-secret-mount-path", - SubPath: "/subpath", - }, - { - Name: "secret-volume-1", - ReadOnly: true, - MountPath: "/secret-secret-mount-path", - SubPath: "/subpath", - }, - }, - Resources: v1.ResourceRequirements{ - Requests: map[v1.ResourceName]resource.Quantity{ - v1.ResourceCPU: resource.MustParse("0.1"), - }, - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("0.5"), - }, - }, - }}, - ImagePullSecrets: []v1.LocalObjectReference{{ - Name: "image-pull-secret", - }}, - ServiceAccountName: "aVerySpecialSA", - SecurityContext: &v1.PodSecurityContext{ - RunAsUser: &runAsUser, - }, - RestartPolicy: v1.RestartPolicyNever, - Volumes: []v1.Volume{ - { - Name: kaniko.DefaultEmptyDirName, - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, - }, - }, - { - Name: kaniko.DefaultSecretName, - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: "secret", - }, - }, - }, - { - Name: "cm-volume-1", - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "cm-1", - }, - }, - }, - }, - { - Name: "secret-volume-1", - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: "secret-1", - }, - }, - }, - }, - Tolerations: []v1.Toleration{ - { - Key: "app", - Operator: "Equal", - Value: "skaffold", - Effect: "NoSchedule", - TolerationSeconds: nil, - }, - }, - NodeSelector: map[string]string{"kubernetes.io/os": "linux", "kubernetes.io/arch": "arm64"}, - }, - } + expectedPod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"test": "test"}, + GenerateName: "kaniko-", + Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko", "test-key": "test-value"}, + Namespace: "ns", + }, + Spec: v1.PodSpec{ + InitContainers: []v1.Container{{ + Name: initContainer, + Image: "init/image", + Command: []string{"sh", "-c", "while [ ! -f /tmp/complete ]; do sleep 1; done"}, + VolumeMounts: []v1.VolumeMount{{ + Name: kaniko.DefaultEmptyDirName, + MountPath: kaniko.DefaultEmptyDirMountPath, + }, { + Name: "cm-volume-1", + ReadOnly: true, + MountPath: "/cm-secret-mount-path", + SubPath: "/subpath", + }, { + Name: "secret-volume-1", + ReadOnly: true, + MountPath: "/secret-secret-mount-path", + SubPath: "/subpath", + }}, + Resources: v1.ResourceRequirements{ + Requests: map[v1.ResourceName]resource.Quantity{ + v1.ResourceCPU: resource.MustParse("0.1"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("0.5"), + }, + }, + }}, + Containers: []v1.Container{{ + Name: kaniko.DefaultContainerName, + Image: "image", + Args: []string{"--destination", "tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext", "--destination", "gcr.io/foo/bar:test-1", "--destination", "gcr.io/foo/bar:test-2"}, + ImagePullPolicy: v1.PullIfNotPresent, + Env: []v1.EnvVar{{ + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-)", + }, { + Name: "KEY", + Value: "VALUE", + }, { + Name: "HTTP_PROXY", + Value: "http://proxy", + }, { + Name: "HTTPS_PROXY", + Value: "https://proxy", + }, { + Name: "GOOGLE_APPLICATION_CREDENTIALS", + Value: "/secret/kaniko-secret.json", + }}, + VolumeMounts: []v1.VolumeMount{ + { + Name: kaniko.DefaultEmptyDirName, + MountPath: kaniko.DefaultEmptyDirMountPath, + }, + { + Name: kaniko.DefaultSecretName, + MountPath: "/secret", + }, + { + Name: "cm-volume-1", + ReadOnly: true, + MountPath: "/cm-secret-mount-path", + SubPath: "/subpath", + }, + { + Name: "secret-volume-1", + ReadOnly: true, + MountPath: "/secret-secret-mount-path", + SubPath: "/subpath", + }, + }, + Resources: v1.ResourceRequirements{ + Requests: map[v1.ResourceName]resource.Quantity{ + v1.ResourceCPU: resource.MustParse("0.1"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("0.5"), + }, + }, + }}, + ImagePullSecrets: []v1.LocalObjectReference{{ + Name: "image-pull-secret", + }}, + ServiceAccountName: "aVerySpecialSA", + SecurityContext: &v1.PodSecurityContext{ + RunAsUser: &runAsUser, + }, + RestartPolicy: v1.RestartPolicyNever, + Volumes: []v1.Volume{ + { + Name: kaniko.DefaultEmptyDirName, + VolumeSource: v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + }, + }, + { + Name: kaniko.DefaultSecretName, + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: "secret", + }, + }, + }, + { + Name: "cm-volume-1", + VolumeSource: v1.VolumeSource{ + ConfigMap: &v1.ConfigMapVolumeSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "cm-1", + }, + }, + }, + }, + { + Name: "secret-volume-1", + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: "secret-1", + }, + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "app", + Operator: "Equal", + Value: "skaffold", + Effect: "NoSchedule", + TolerationSeconds: nil, + }, + }, + NodeSelector: map[string]string{"kubernetes.io/os": "linux", "kubernetes.io/arch": "arm64"}, + }, + } - testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Env, pod.Spec.Containers[0].Env) - testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Args, pod.Spec.Containers[0].Args) - testutil.CheckDeepEqual(t, expectedPod.ObjectMeta, pod.ObjectMeta) + testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Env, pod.Spec.Containers[0].Env) + testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Args, pod.Spec.Containers[0].Args) + testutil.CheckDeepEqual(t, expectedPod.ObjectMeta, pod.ObjectMeta) } func TestResourceRequirements(t *testing.T) { - tests := []struct { - description string - initial *latest.ResourceRequirements - expected v1.ResourceRequirements - }{ - { - description: "no resource specified", - initial: &latest.ResourceRequirements{}, - expected: v1.ResourceRequirements{}, - }, - { - description: "with resource specified", - initial: &latest.ResourceRequirements{ - Requests: &latest.ResourceRequirement{ - CPU: "0.5", - Memory: "1000", - ResourceStorage: "1000", - EphemeralStorage: "1000", - }, - Limits: &latest.ResourceRequirement{ - CPU: "1.0", - Memory: "2000", - ResourceStorage: "1000", - EphemeralStorage: "1000", - }, - }, - expected: v1.ResourceRequirements{ - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("0.5"), - v1.ResourceMemory: resource.MustParse("1000"), - v1.ResourceStorage: resource.MustParse("1000"), - v1.ResourceEphemeralStorage: resource.MustParse("1000"), - }, - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("1.0"), - v1.ResourceMemory: resource.MustParse("2000"), - v1.ResourceStorage: resource.MustParse("1000"), - v1.ResourceEphemeralStorage: resource.MustParse("1000"), - }, - }, - }, - } + tests := []struct { + description string + initial *latest.ResourceRequirements + expected v1.ResourceRequirements + }{ + { + description: "no resource specified", + initial: &latest.ResourceRequirements{}, + expected: v1.ResourceRequirements{}, + }, + { + description: "with resource specified", + initial: &latest.ResourceRequirements{ + Requests: &latest.ResourceRequirement{ + CPU: "0.5", + Memory: "1000", + ResourceStorage: "1000", + EphemeralStorage: "1000", + }, + Limits: &latest.ResourceRequirement{ + CPU: "1.0", + Memory: "2000", + ResourceStorage: "1000", + EphemeralStorage: "1000", + }, + }, + expected: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("0.5"), + v1.ResourceMemory: resource.MustParse("1000"), + v1.ResourceStorage: resource.MustParse("1000"), + v1.ResourceEphemeralStorage: resource.MustParse("1000"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("1.0"), + v1.ResourceMemory: resource.MustParse("2000"), + v1.ResourceStorage: resource.MustParse("1000"), + v1.ResourceEphemeralStorage: resource.MustParse("1000"), + }, + }, + }, + } - for _, test := range tests { - testutil.Run(t, test.description, func(t *testutil.T) { - actual := resourceRequirements(test.initial) - t.CheckDeepEqual(test.expected, actual) - }) - } -} + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + actual := resourceRequirements(test.initial) + t.CheckDeepEqual(test.expected, actual) + }) + } +} \ No newline at end of file From 3ab685da5990f6f75dfdaf22d6adca08f0478828 Mon Sep 17 00:00:00 2001 From: Angel Montero Date: Wed, 15 Jan 2025 17:49:02 +0000 Subject: [PATCH 5/7] add period to end of ImagePullSecret description --- pkg/skaffold/schema/latest/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go index ada7578c8a5..90865a21b04 100644 --- a/pkg/skaffold/schema/latest/config.go +++ b/pkg/skaffold/schema/latest/config.go @@ -1471,7 +1471,7 @@ type KanikoArtifact struct { // Defaults to the latest released version of `gcr.io/kaniko-project/executor`. Image string `yaml:"image,omitempty"` - // ImagePullSecret is the name of the Kubernetes secret for pulling kaniko image and kaniko init image from a private registry + // ImagePullSecret is the name of the Kubernetes secret for pulling kaniko image and kaniko init image from a private registry. ImagePullSecret string `yaml:"imagePullSecret,omitempty"` // Destination is additional tags to push. From a29eb3baf0707c91f8c50931f493cc7386299cd5 Mon Sep 17 00:00:00 2001 From: Angel Montero Date: Wed, 15 Jan 2025 17:50:17 +0000 Subject: [PATCH 6/7] regenerate v4beta12 schema --- docs-v2/content/en/schemas/v4beta12.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs-v2/content/en/schemas/v4beta12.json b/docs-v2/content/en/schemas/v4beta12.json index 5377523fa5c..24cd4c39e4d 100755 --- a/docs-v2/content/en/schemas/v4beta12.json +++ b/docs-v2/content/en/schemas/v4beta12.json @@ -2763,6 +2763,11 @@ "description": "specify a file to save the image name with digest of the built image to.", "x-intellij-html-description": "specify a file to save the image name with digest of the built image to." }, + "imagePullSecret": { + "type": "string", + "description": "name of the Kubernetes secret for pulling kaniko image and kaniko init image from a private registry.", + "x-intellij-html-description": "name of the Kubernetes secret for pulling kaniko image and kaniko init image from a private registry." + }, "initImage": { "type": "string", "description": "image used to run init container which mounts kaniko context.", @@ -2929,6 +2934,7 @@ "target", "initImage", "image", + "imagePullSecret", "destination", "digestFile", "imageFSExtractRetry", From 12833d72d792d700a7ac27c7154d129ff5b7d399 Mon Sep 17 00:00:00 2001 From: Angel Montero Date: Wed, 15 Jan 2025 18:00:42 +0000 Subject: [PATCH 7/7] fix indentation with gofmt --- pkg/skaffold/build/cluster/pod_test.go | 860 ++++++++++++------------- 1 file changed, 430 insertions(+), 430 deletions(-) diff --git a/pkg/skaffold/build/cluster/pod_test.go b/pkg/skaffold/build/cluster/pod_test.go index f764d850eb0..3a218ee5f0a 100644 --- a/pkg/skaffold/build/cluster/pod_test.go +++ b/pkg/skaffold/build/cluster/pod_test.go @@ -17,451 +17,451 @@ limitations under the License. package cluster import ( - "testing" + "testing" - specs "github.com/opencontainers/image-spec/specs-go/v1" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + specs "github.com/opencontainers/image-spec/specs-go/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/build/kaniko" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/platform" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest" - "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util" - "github.com/GoogleContainerTools/skaffold/v2/testutil" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/build/kaniko" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/platform" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util" + "github.com/GoogleContainerTools/skaffold/v2/testutil" ) func TestKanikoArgs(t *testing.T) { - tests := []struct { - description string - artifact *latest.KanikoArtifact - insecureRegistries map[string]bool - tag string - shouldErr bool - expectedArgs []string - }{ - { - description: "simple build", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - }, - expectedArgs: []string{}, - }, - { - description: "with Destination", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Destination: []string{ - "gcr.io/foo/bar:test-1", - "gcr.io/foo/bar:test-2", - }, - }, - expectedArgs: []string{ - kaniko.DestinationFlag, "gcr.io/foo/bar:test-1", - kaniko.DestinationFlag, "gcr.io/foo/bar:test-2", - }, - }, - { - description: "cache layers", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Cache: &latest.KanikoCache{}, - }, - expectedArgs: []string{kaniko.CacheFlag}, - }, - { - description: "cache layers to specific repo", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Cache: &latest.KanikoCache{ - Repo: "repo", - }, - }, - expectedArgs: []string{"--cache", kaniko.CacheRepoFlag, "repo"}, - }, - { - description: "cache path", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Cache: &latest.KanikoCache{ - HostPath: "/cache", - }, - }, - expectedArgs: []string{ - kaniko.CacheFlag, - kaniko.CacheDirFlag, "/cache"}, - }, - { - description: "target", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Target: "target", - }, - expectedArgs: []string{kaniko.TargetFlag, "target"}, - }, - { - description: "reproducible", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - Reproducible: true, - }, - expectedArgs: []string{kaniko.ReproducibleFlag}, - }, - { - description: "build args", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - BuildArgs: map[string]*string{ - "nil_key": nil, - "empty_key": util.Ptr(""), - "value_key": util.Ptr("value"), - }, - }, - expectedArgs: []string{ - kaniko.BuildArgsFlag, "empty_key=", - kaniko.BuildArgsFlag, "nil_key", - kaniko.BuildArgsFlag, "value_key=value"}, - }, - { - description: "invalid build args", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - BuildArgs: map[string]*string{ - "invalid": util.Ptr("{{Invalid"), - }, - }, - shouldErr: true, - }, - { - description: "insecure registries", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - }, - insecureRegistries: map[string]bool{"localhost:4000": true}, - expectedArgs: []string{kaniko.InsecureRegistryFlag, "localhost:4000"}, - }, - { - description: "skip tls", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - SkipTLS: true, - }, - expectedArgs: []string{ - kaniko.SkipTLSFlag, - kaniko.SkipTLSVerifyRegistryFlag, "gcr.io", - }, - }, - { - description: "invalid registry", - artifact: &latest.KanikoArtifact{ - DockerfilePath: "Dockerfile", - SkipTLS: true, - }, - tag: "!!!!", - shouldErr: true, - }, - } - for _, test := range tests { - testutil.Run(t, test.description, func(t *testutil.T) { - commonArgs := []string{"--destination", "gcr.io/tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext"} + tests := []struct { + description string + artifact *latest.KanikoArtifact + insecureRegistries map[string]bool + tag string + shouldErr bool + expectedArgs []string + }{ + { + description: "simple build", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + }, + expectedArgs: []string{}, + }, + { + description: "with Destination", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Destination: []string{ + "gcr.io/foo/bar:test-1", + "gcr.io/foo/bar:test-2", + }, + }, + expectedArgs: []string{ + kaniko.DestinationFlag, "gcr.io/foo/bar:test-1", + kaniko.DestinationFlag, "gcr.io/foo/bar:test-2", + }, + }, + { + description: "cache layers", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Cache: &latest.KanikoCache{}, + }, + expectedArgs: []string{kaniko.CacheFlag}, + }, + { + description: "cache layers to specific repo", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Cache: &latest.KanikoCache{ + Repo: "repo", + }, + }, + expectedArgs: []string{"--cache", kaniko.CacheRepoFlag, "repo"}, + }, + { + description: "cache path", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Cache: &latest.KanikoCache{ + HostPath: "/cache", + }, + }, + expectedArgs: []string{ + kaniko.CacheFlag, + kaniko.CacheDirFlag, "/cache"}, + }, + { + description: "target", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Target: "target", + }, + expectedArgs: []string{kaniko.TargetFlag, "target"}, + }, + { + description: "reproducible", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + Reproducible: true, + }, + expectedArgs: []string{kaniko.ReproducibleFlag}, + }, + { + description: "build args", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + BuildArgs: map[string]*string{ + "nil_key": nil, + "empty_key": util.Ptr(""), + "value_key": util.Ptr("value"), + }, + }, + expectedArgs: []string{ + kaniko.BuildArgsFlag, "empty_key=", + kaniko.BuildArgsFlag, "nil_key", + kaniko.BuildArgsFlag, "value_key=value"}, + }, + { + description: "invalid build args", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + BuildArgs: map[string]*string{ + "invalid": util.Ptr("{{Invalid"), + }, + }, + shouldErr: true, + }, + { + description: "insecure registries", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + }, + insecureRegistries: map[string]bool{"localhost:4000": true}, + expectedArgs: []string{kaniko.InsecureRegistryFlag, "localhost:4000"}, + }, + { + description: "skip tls", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + SkipTLS: true, + }, + expectedArgs: []string{ + kaniko.SkipTLSFlag, + kaniko.SkipTLSVerifyRegistryFlag, "gcr.io", + }, + }, + { + description: "invalid registry", + artifact: &latest.KanikoArtifact{ + DockerfilePath: "Dockerfile", + SkipTLS: true, + }, + tag: "!!!!", + shouldErr: true, + }, + } + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + commonArgs := []string{"--destination", "gcr.io/tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext"} - tag := "gcr.io/tag" - if test.tag != "" { - tag = test.tag - } - args, err := kanikoArgs(test.artifact, tag, test.insecureRegistries) + tag := "gcr.io/tag" + if test.tag != "" { + tag = test.tag + } + args, err := kanikoArgs(test.artifact, tag, test.insecureRegistries) - t.CheckError(test.shouldErr, err) - if !test.shouldErr { - t.CheckDeepEqual(append(commonArgs, test.expectedArgs...), args) - } - }) - } + t.CheckError(test.shouldErr, err) + if !test.shouldErr { + t.CheckDeepEqual(append(commonArgs, test.expectedArgs...), args) + } + }) + } } func TestKanikoPodSpec(t *testing.T) { - artifact := &latest.KanikoArtifact{ - Image: "image", - DockerfilePath: "Dockerfile", - InitImage: "init/image", - ImagePullSecret: "image-pull-secret", - Destination: []string{ - "gcr.io/foo/bar:test-1", - "gcr.io/foo/bar:test-2", - }, - Env: []v1.EnvVar{{ - Name: "KEY", - Value: "VALUE", - }}, - VolumeMounts: []v1.VolumeMount{ - { - Name: "cm-volume-1", - ReadOnly: true, - MountPath: "/cm-test-mount-path", - SubPath: "/subpath", - }, - { - Name: "secret-volume-1", - ReadOnly: true, - MountPath: "/secret-test-mount-path", - SubPath: "/subpath", - }, - }, - } + artifact := &latest.KanikoArtifact{ + Image: "image", + DockerfilePath: "Dockerfile", + InitImage: "init/image", + ImagePullSecret: "image-pull-secret", + Destination: []string{ + "gcr.io/foo/bar:test-1", + "gcr.io/foo/bar:test-2", + }, + Env: []v1.EnvVar{{ + Name: "KEY", + Value: "VALUE", + }}, + VolumeMounts: []v1.VolumeMount{ + { + Name: "cm-volume-1", + ReadOnly: true, + MountPath: "/cm-test-mount-path", + SubPath: "/subpath", + }, + { + Name: "secret-volume-1", + ReadOnly: true, + MountPath: "/secret-test-mount-path", + SubPath: "/subpath", + }, + }, + } - var runAsUser int64 = 0 + var runAsUser int64 = 0 - builder := &Builder{ - cfg: &mockBuilderContext{}, - ClusterDetails: &latest.ClusterDetails{ - Namespace: "ns", - PullSecretName: "secret", - PullSecretPath: "kaniko-secret.json", - PullSecretMountPath: "/secret", - HTTPProxy: "http://proxy", - HTTPSProxy: "https://proxy", - ServiceAccountName: "aVerySpecialSA", - Annotations: map[string]string{"test": "test"}, - Labels: map[string]string{"test-key": "test-value"}, - RunAsUser: &runAsUser, - Resources: &latest.ResourceRequirements{ - Requests: &latest.ResourceRequirement{ - CPU: "0.1", - }, - Limits: &latest.ResourceRequirement{ - CPU: "0.5", - }, - }, - Volumes: []v1.Volume{ - { - Name: "cm-volume-1", - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "cm-1", - }, - }, - }, - }, - { - Name: "secret-volume-1", - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: "secret-1", - }, - }, - }, - }, - Tolerations: []v1.Toleration{ - { - Key: "app", - Operator: "Equal", - Value: "skaffold", - Effect: "NoSchedule", - TolerationSeconds: nil, - }, - }, - NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, - }, - } - matcher := platform.Matcher{Platforms: []specs.Platform{{OS: "linux", Architecture: "arm64"}}} - pod, _ := builder.kanikoPodSpec(artifact, "tag", matcher) + builder := &Builder{ + cfg: &mockBuilderContext{}, + ClusterDetails: &latest.ClusterDetails{ + Namespace: "ns", + PullSecretName: "secret", + PullSecretPath: "kaniko-secret.json", + PullSecretMountPath: "/secret", + HTTPProxy: "http://proxy", + HTTPSProxy: "https://proxy", + ServiceAccountName: "aVerySpecialSA", + Annotations: map[string]string{"test": "test"}, + Labels: map[string]string{"test-key": "test-value"}, + RunAsUser: &runAsUser, + Resources: &latest.ResourceRequirements{ + Requests: &latest.ResourceRequirement{ + CPU: "0.1", + }, + Limits: &latest.ResourceRequirement{ + CPU: "0.5", + }, + }, + Volumes: []v1.Volume{ + { + Name: "cm-volume-1", + VolumeSource: v1.VolumeSource{ + ConfigMap: &v1.ConfigMapVolumeSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "cm-1", + }, + }, + }, + }, + { + Name: "secret-volume-1", + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: "secret-1", + }, + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "app", + Operator: "Equal", + Value: "skaffold", + Effect: "NoSchedule", + TolerationSeconds: nil, + }, + }, + NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, + }, + } + matcher := platform.Matcher{Platforms: []specs.Platform{{OS: "linux", Architecture: "arm64"}}} + pod, _ := builder.kanikoPodSpec(artifact, "tag", matcher) - expectedPod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{"test": "test"}, - GenerateName: "kaniko-", - Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko", "test-key": "test-value"}, - Namespace: "ns", - }, - Spec: v1.PodSpec{ - InitContainers: []v1.Container{{ - Name: initContainer, - Image: "init/image", - Command: []string{"sh", "-c", "while [ ! -f /tmp/complete ]; do sleep 1; done"}, - VolumeMounts: []v1.VolumeMount{{ - Name: kaniko.DefaultEmptyDirName, - MountPath: kaniko.DefaultEmptyDirMountPath, - }, { - Name: "cm-volume-1", - ReadOnly: true, - MountPath: "/cm-secret-mount-path", - SubPath: "/subpath", - }, { - Name: "secret-volume-1", - ReadOnly: true, - MountPath: "/secret-secret-mount-path", - SubPath: "/subpath", - }}, - Resources: v1.ResourceRequirements{ - Requests: map[v1.ResourceName]resource.Quantity{ - v1.ResourceCPU: resource.MustParse("0.1"), - }, - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("0.5"), - }, - }, - }}, - Containers: []v1.Container{{ - Name: kaniko.DefaultContainerName, - Image: "image", - Args: []string{"--destination", "tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext", "--destination", "gcr.io/foo/bar:test-1", "--destination", "gcr.io/foo/bar:test-2"}, - ImagePullPolicy: v1.PullIfNotPresent, - Env: []v1.EnvVar{{ - Name: "UPSTREAM_CLIENT_TYPE", - Value: "UpstreamClient(skaffold-)", - }, { - Name: "KEY", - Value: "VALUE", - }, { - Name: "HTTP_PROXY", - Value: "http://proxy", - }, { - Name: "HTTPS_PROXY", - Value: "https://proxy", - }, { - Name: "GOOGLE_APPLICATION_CREDENTIALS", - Value: "/secret/kaniko-secret.json", - }}, - VolumeMounts: []v1.VolumeMount{ - { - Name: kaniko.DefaultEmptyDirName, - MountPath: kaniko.DefaultEmptyDirMountPath, - }, - { - Name: kaniko.DefaultSecretName, - MountPath: "/secret", - }, - { - Name: "cm-volume-1", - ReadOnly: true, - MountPath: "/cm-secret-mount-path", - SubPath: "/subpath", - }, - { - Name: "secret-volume-1", - ReadOnly: true, - MountPath: "/secret-secret-mount-path", - SubPath: "/subpath", - }, - }, - Resources: v1.ResourceRequirements{ - Requests: map[v1.ResourceName]resource.Quantity{ - v1.ResourceCPU: resource.MustParse("0.1"), - }, - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("0.5"), - }, - }, - }}, - ImagePullSecrets: []v1.LocalObjectReference{{ - Name: "image-pull-secret", - }}, - ServiceAccountName: "aVerySpecialSA", - SecurityContext: &v1.PodSecurityContext{ - RunAsUser: &runAsUser, - }, - RestartPolicy: v1.RestartPolicyNever, - Volumes: []v1.Volume{ - { - Name: kaniko.DefaultEmptyDirName, - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, - }, - }, - { - Name: kaniko.DefaultSecretName, - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: "secret", - }, - }, - }, - { - Name: "cm-volume-1", - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: "cm-1", - }, - }, - }, - }, - { - Name: "secret-volume-1", - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: "secret-1", - }, - }, - }, - }, - Tolerations: []v1.Toleration{ - { - Key: "app", - Operator: "Equal", - Value: "skaffold", - Effect: "NoSchedule", - TolerationSeconds: nil, - }, - }, - NodeSelector: map[string]string{"kubernetes.io/os": "linux", "kubernetes.io/arch": "arm64"}, - }, - } + expectedPod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"test": "test"}, + GenerateName: "kaniko-", + Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko", "test-key": "test-value"}, + Namespace: "ns", + }, + Spec: v1.PodSpec{ + InitContainers: []v1.Container{{ + Name: initContainer, + Image: "init/image", + Command: []string{"sh", "-c", "while [ ! -f /tmp/complete ]; do sleep 1; done"}, + VolumeMounts: []v1.VolumeMount{{ + Name: kaniko.DefaultEmptyDirName, + MountPath: kaniko.DefaultEmptyDirMountPath, + }, { + Name: "cm-volume-1", + ReadOnly: true, + MountPath: "/cm-secret-mount-path", + SubPath: "/subpath", + }, { + Name: "secret-volume-1", + ReadOnly: true, + MountPath: "/secret-secret-mount-path", + SubPath: "/subpath", + }}, + Resources: v1.ResourceRequirements{ + Requests: map[v1.ResourceName]resource.Quantity{ + v1.ResourceCPU: resource.MustParse("0.1"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("0.5"), + }, + }, + }}, + Containers: []v1.Container{{ + Name: kaniko.DefaultContainerName, + Image: "image", + Args: []string{"--destination", "tag", "--dockerfile", "Dockerfile", "--context", "dir:///kaniko/buildcontext", "--destination", "gcr.io/foo/bar:test-1", "--destination", "gcr.io/foo/bar:test-2"}, + ImagePullPolicy: v1.PullIfNotPresent, + Env: []v1.EnvVar{{ + Name: "UPSTREAM_CLIENT_TYPE", + Value: "UpstreamClient(skaffold-)", + }, { + Name: "KEY", + Value: "VALUE", + }, { + Name: "HTTP_PROXY", + Value: "http://proxy", + }, { + Name: "HTTPS_PROXY", + Value: "https://proxy", + }, { + Name: "GOOGLE_APPLICATION_CREDENTIALS", + Value: "/secret/kaniko-secret.json", + }}, + VolumeMounts: []v1.VolumeMount{ + { + Name: kaniko.DefaultEmptyDirName, + MountPath: kaniko.DefaultEmptyDirMountPath, + }, + { + Name: kaniko.DefaultSecretName, + MountPath: "/secret", + }, + { + Name: "cm-volume-1", + ReadOnly: true, + MountPath: "/cm-secret-mount-path", + SubPath: "/subpath", + }, + { + Name: "secret-volume-1", + ReadOnly: true, + MountPath: "/secret-secret-mount-path", + SubPath: "/subpath", + }, + }, + Resources: v1.ResourceRequirements{ + Requests: map[v1.ResourceName]resource.Quantity{ + v1.ResourceCPU: resource.MustParse("0.1"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("0.5"), + }, + }, + }}, + ImagePullSecrets: []v1.LocalObjectReference{{ + Name: "image-pull-secret", + }}, + ServiceAccountName: "aVerySpecialSA", + SecurityContext: &v1.PodSecurityContext{ + RunAsUser: &runAsUser, + }, + RestartPolicy: v1.RestartPolicyNever, + Volumes: []v1.Volume{ + { + Name: kaniko.DefaultEmptyDirName, + VolumeSource: v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + }, + }, + { + Name: kaniko.DefaultSecretName, + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: "secret", + }, + }, + }, + { + Name: "cm-volume-1", + VolumeSource: v1.VolumeSource{ + ConfigMap: &v1.ConfigMapVolumeSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "cm-1", + }, + }, + }, + }, + { + Name: "secret-volume-1", + VolumeSource: v1.VolumeSource{ + Secret: &v1.SecretVolumeSource{ + SecretName: "secret-1", + }, + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "app", + Operator: "Equal", + Value: "skaffold", + Effect: "NoSchedule", + TolerationSeconds: nil, + }, + }, + NodeSelector: map[string]string{"kubernetes.io/os": "linux", "kubernetes.io/arch": "arm64"}, + }, + } - testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Env, pod.Spec.Containers[0].Env) - testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Args, pod.Spec.Containers[0].Args) - testutil.CheckDeepEqual(t, expectedPod.ObjectMeta, pod.ObjectMeta) + testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Env, pod.Spec.Containers[0].Env) + testutil.CheckDeepEqual(t, expectedPod.Spec.Containers[0].Args, pod.Spec.Containers[0].Args) + testutil.CheckDeepEqual(t, expectedPod.ObjectMeta, pod.ObjectMeta) } func TestResourceRequirements(t *testing.T) { - tests := []struct { - description string - initial *latest.ResourceRequirements - expected v1.ResourceRequirements - }{ - { - description: "no resource specified", - initial: &latest.ResourceRequirements{}, - expected: v1.ResourceRequirements{}, - }, - { - description: "with resource specified", - initial: &latest.ResourceRequirements{ - Requests: &latest.ResourceRequirement{ - CPU: "0.5", - Memory: "1000", - ResourceStorage: "1000", - EphemeralStorage: "1000", - }, - Limits: &latest.ResourceRequirement{ - CPU: "1.0", - Memory: "2000", - ResourceStorage: "1000", - EphemeralStorage: "1000", - }, - }, - expected: v1.ResourceRequirements{ - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("0.5"), - v1.ResourceMemory: resource.MustParse("1000"), - v1.ResourceStorage: resource.MustParse("1000"), - v1.ResourceEphemeralStorage: resource.MustParse("1000"), - }, - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("1.0"), - v1.ResourceMemory: resource.MustParse("2000"), - v1.ResourceStorage: resource.MustParse("1000"), - v1.ResourceEphemeralStorage: resource.MustParse("1000"), - }, - }, - }, - } + tests := []struct { + description string + initial *latest.ResourceRequirements + expected v1.ResourceRequirements + }{ + { + description: "no resource specified", + initial: &latest.ResourceRequirements{}, + expected: v1.ResourceRequirements{}, + }, + { + description: "with resource specified", + initial: &latest.ResourceRequirements{ + Requests: &latest.ResourceRequirement{ + CPU: "0.5", + Memory: "1000", + ResourceStorage: "1000", + EphemeralStorage: "1000", + }, + Limits: &latest.ResourceRequirement{ + CPU: "1.0", + Memory: "2000", + ResourceStorage: "1000", + EphemeralStorage: "1000", + }, + }, + expected: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("0.5"), + v1.ResourceMemory: resource.MustParse("1000"), + v1.ResourceStorage: resource.MustParse("1000"), + v1.ResourceEphemeralStorage: resource.MustParse("1000"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("1.0"), + v1.ResourceMemory: resource.MustParse("2000"), + v1.ResourceStorage: resource.MustParse("1000"), + v1.ResourceEphemeralStorage: resource.MustParse("1000"), + }, + }, + }, + } - for _, test := range tests { - testutil.Run(t, test.description, func(t *testutil.T) { - actual := resourceRequirements(test.initial) - t.CheckDeepEqual(test.expected, actual) - }) - } -} \ No newline at end of file + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + actual := resourceRequirements(test.initial) + t.CheckDeepEqual(test.expected, actual) + }) + } +}