Skip to content

Commit e0e994e

Browse files
imjasonhtekton-robot
authored andcommitted
Support workingDir init on Windows
Previously, we used --shell-image (typically distroless/base) to invoke `mkdir -p <dirs>` to initialize any working dirs that were needed by steps in a TaskRun. This isn't portable to Windows, since distroless/base doesn't provide Windows images, and since invoking `mkdir -p` won't work on Windows. Instead, with this change, we init working dirs using a very simple Go binary that can be cross-compiled to run on both OSes.
1 parent 8c87bf9 commit e0e994e

File tree

10 files changed

+57
-15
lines changed

10 files changed

+57
-15
lines changed

cmd/controller/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func main() {
5757
flag.StringVar(&opts.Images.GsutilImage, "gsutil-image", "", "The container image containing gsutil")
5858
flag.StringVar(&opts.Images.PRImage, "pr-image", "", "The container image containing our PR binary.")
5959
flag.StringVar(&opts.Images.ImageDigestExporterImage, "imagedigest-exporter-image", "", "The container image containing our image digest exporter binary.")
60+
flag.StringVar(&opts.Images.WorkingDirInitImage, "workingdirinit-image", "", "The container image containing our working dir init binary.")
6061

6162
// This parses flags.
6263
cfg := injection.ParseAndGetRESTConfigOrDie()

cmd/workingdirinit/main.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright 2022 The Tekton Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"log"
21+
"os"
22+
"path/filepath"
23+
"strings"
24+
)
25+
26+
func main() {
27+
for _, d := range os.Args {
28+
p := filepath.Clean(d)
29+
if !filepath.IsAbs(p) || strings.HasPrefix(p, "/workspace/") {
30+
if err := os.MkdirAll(p, 0755); err != nil {
31+
log.Fatalf("Failed to mkdir %q: %v", p, err)
32+
}
33+
}
34+
}
35+
}

config/controller.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ spec:
7171
"-nop-image", "ko://github.com/tektoncd/pipeline/cmd/nop",
7272
"-imagedigest-exporter-image", "ko://github.com/tektoncd/pipeline/cmd/imagedigestexporter",
7373
"-pr-image", "ko://github.com/tektoncd/pipeline/cmd/pullrequest-init",
74+
"-workingdirinit-image", "ko://github.com/tektoncd/pipeline/cmd/workingdirinit",
7475

7576
# This is gcr.io/google.com/cloudsdktool/cloud-sdk:302.0.0-slim
7677
"-gsutil-image", "gcr.io/google.com/cloudsdktool/cloud-sdk@sha256:27b2c22bf259d9bc1a291e99c63791ba0c27a04d2db0a43241ba0f1f20f4067f",

pkg/apis/pipeline/images.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ type Images struct {
4242
PRImage string
4343
// ImageDigestExporterImage is the container image containing our image digest exporter binary.
4444
ImageDigestExporterImage string
45+
// WorkingDirInitImage is the container image containing our working dir init binary.
46+
WorkingDirInitImage string
4547

4648
// NOTE: Make sure to add any new images to Validate below!
4749
}
@@ -61,6 +63,7 @@ func (i Images) Validate() error {
6163
{i.GsutilImage, "gsutil-image"},
6264
{i.PRImage, "pr-image"},
6365
{i.ImageDigestExporterImage, "imagedigest-exporter-image"},
66+
{i.WorkingDirInitImage, "workingdirinit-image"},
6467
} {
6568
if f.v == "" {
6669
unset = append(unset, f.name)

pkg/apis/pipeline/images_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func TestValidate(t *testing.T) {
1717
GsutilImage: "set",
1818
PRImage: "set",
1919
ImageDigestExporterImage: "set",
20+
WorkingDirInitImage: "set",
2021
}
2122
if err := valid.Validate(); err != nil {
2223
t.Errorf("valid Images returned error: %v", err)
@@ -33,7 +34,7 @@ func TestValidate(t *testing.T) {
3334
PRImage: "", // unset!
3435
ImageDigestExporterImage: "set",
3536
}
36-
wantErr := "found unset image flags: [git-image pr-image shell-image]"
37+
wantErr := "found unset image flags: [git-image pr-image shell-image workingdirinit-image]"
3738
if err := invalid.Validate(); err == nil {
3839
t.Error("invalid Images expected error, got nil")
3940
} else if err.Error() != wantErr {

pkg/pod/pod.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1beta1.TaskRun, taskSpec
156156
}
157157

158158
// Initialize any workingDirs under /workspace.
159-
if workingDirInit := workingDirInit(b.Images.ShellImage, stepContainers); workingDirInit != nil {
159+
if workingDirInit := workingDirInit(b.Images.WorkingDirInitImage, stepContainers); workingDirInit != nil {
160160
initContainers = append(initContainers, *workingDirInit)
161161
}
162162

pkg/pod/pod_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,9 +477,9 @@ func TestPodBuild(t *testing.T) {
477477
tektonDirInit(images.EntrypointImage, []v1beta1.Step{{Container: corev1.Container{Name: "name"}}}),
478478
{
479479
Name: "working-dir-initializer",
480-
Image: images.ShellImage,
481-
Command: []string{"sh"},
482-
Args: []string{"-c", fmt.Sprintf("mkdir -p %s", filepath.Join(pipeline.WorkspaceDir, "test"))},
480+
Image: images.WorkingDirInitImage,
481+
Command: []string{"/ko-app/workingdirinit"},
482+
Args: []string{filepath.Join(pipeline.WorkspaceDir, "test")},
483483
WorkingDir: pipeline.WorkspaceDir,
484484
VolumeMounts: implicitVolumeMounts,
485485
},

pkg/pod/workingdir_init.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
//
3232
// If no such directories need to be created (i.e., no relative workingDirs
3333
// are specified), this method returns nil, as no init container is necessary.
34-
func workingDirInit(shellImage string, stepContainers []corev1.Container) *corev1.Container {
34+
func workingDirInit(workingdirinitImage string, stepContainers []corev1.Container) *corev1.Container {
3535
// Gather all unique workingDirs.
3636
workingDirs := sets.NewString()
3737
for _, step := range stepContainers {
@@ -59,9 +59,9 @@ func workingDirInit(shellImage string, stepContainers []corev1.Container) *corev
5959

6060
return &corev1.Container{
6161
Name: "working-dir-initializer",
62-
Image: shellImage,
63-
Command: []string{"sh"},
64-
Args: []string{"-c", "mkdir -p " + strings.Join(relativeDirs, " ")},
62+
Image: workingdirinitImage,
63+
Command: []string{"/ko-app/workingdirinit"},
64+
Args: relativeDirs,
6565
WorkingDir: pipeline.WorkspaceDir,
6666
VolumeMounts: implicitVolumeMounts,
6767
}

pkg/pod/workingdir_init_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ func TestWorkingDirInit(t *testing.T) {
5757
}},
5858
want: &corev1.Container{
5959
Name: "working-dir-initializer",
60-
Image: images.ShellImage,
61-
Command: []string{"sh"},
62-
Args: []string{"-c", "mkdir -p /workspace/bbb aaa zzz"},
60+
Image: images.WorkingDirInitImage,
61+
Command: []string{"/ko-app/workingdirinit"},
62+
Args: []string{"/workspace/bbb", "aaa", "zzz"},
6363
WorkingDir: pipeline.WorkspaceDir,
6464
VolumeMounts: implicitVolumeMounts,
6565
},
6666
}} {
6767
t.Run(c.desc, func(t *testing.T) {
68-
got := workingDirInit(images.ShellImage, c.stepContainers)
68+
got := workingDirInit(images.WorkingDirInitImage, c.stepContainers)
6969
if d := cmp.Diff(c.want, got); d != "" {
7070
t.Fatalf("Diff %s", diff.PrintWantGot(d))
7171
}

tekton/publish.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ spec:
1111
default: github.com/tektoncd/pipeline
1212
- name: images
1313
description: List of cmd/* paths to be published as images
14-
default: "controller webhook entrypoint nop kubeconfigwriter git-init imagedigestexporter pullrequest-init"
14+
default: "controller webhook entrypoint nop kubeconfigwriter git-init imagedigestexporter pullrequest-init workingdirinit"
1515
- name: versionTag
1616
description: The vX.Y.Z version that the artifacts should be tagged with (including `v`)
1717
- name: imageRegistry
@@ -103,9 +103,10 @@ spec:
103103
# This matches the value configured in .ko.yaml
104104
defaultBaseImage: gcr.io/distroless/static:nonroot
105105
baseImageOverrides:
106-
# Use the combined base image for entrypoint and nop images.
106+
# Use the combined base image for images that should include Windows support.
107107
$(params.package)/cmd/entrypoint: ${COMBINED_BASE_IMAGE}
108108
$(params.package)/cmd/nop: ${COMBINED_BASE_IMAGE}
109+
$(params.package)/cmd/workingdirinit: ${COMBINED_BASE_IMAGE}
109110
110111
$(params.package)/cmd/git-init: ${CONTAINER_REGISTRY}/$(params.package)/git-init-build-base:latest
111112
# These match values configured in .ko.yaml

0 commit comments

Comments
 (0)