Skip to content

Commit e3e3ee1

Browse files
committed
updates to pr tektoncd#721
- run the image digest exporter after each step - move the index path to the task definition instead of the resource since the user needs to know this at the time of creating the task so it can be used as part of the steps scripting if needed - rename indexpath to outputimagepath - add example yaml
1 parent 80888fa commit e3e3ee1

File tree

11 files changed

+325
-56
lines changed

11 files changed

+325
-56
lines changed

cmd/imagedigestexporter/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func main() {
4242

4343
output := []v1alpha1.PipelineResourceResult{}
4444
for _, imageResource := range imageResources {
45-
ii, err := layout.ImageIndexFromPath(imageResource.IndexPath)
45+
ii, err := layout.ImageIndexFromPath(imageResource.OutputImagePath)
4646
if err != nil {
4747
// if this image doesn't have a builder that supports index.josn file,
4848
// then it will be skipped
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
apiVersion: tekton.dev/v1alpha1
2+
kind: PipelineResource
3+
metadata:
4+
name: skaffold-image-leeroy-web
5+
spec:
6+
type: image
7+
params:
8+
- name: url
9+
value: gcr.io/christiewilson-catfactory/leeroy-web # Replace this URL with ${KO_DOCKER_REPO}
10+
---
11+
# This demo modifies the cluster (deploys to it) you must use a service
12+
# account with permission to admin the cluster (or make your default user an admin
13+
# of the `default` namespace with default-cluster-admin.
14+
apiVersion: rbac.authorization.k8s.io/v1
15+
kind: ClusterRoleBinding
16+
metadata:
17+
name: default-cluster-admin
18+
subjects:
19+
- kind: ServiceAccount
20+
name: default
21+
namespace: default
22+
roleRef:
23+
kind: ClusterRole
24+
name: cluster-admin
25+
apiGroup: rbac.authorization.k8s.io
26+
---
27+
apiVersion: tekton.dev/v1alpha1
28+
kind: PipelineResource
29+
metadata:
30+
name: skaffold-git
31+
spec:
32+
type: git
33+
params:
34+
- name: revision
35+
value: master
36+
- name: url
37+
value: https://github.com/GoogleContainerTools/skaffold
38+
---
39+
#Builds an image via kaniko and pushes it to registry.
40+
apiVersion: tekton.dev/v1alpha1
41+
kind: Task
42+
metadata:
43+
name: build-push-kaniko
44+
spec:
45+
inputs:
46+
resources:
47+
- name: workspace
48+
type: git
49+
outputs:
50+
resources:
51+
- name: builtImage
52+
type: image
53+
outputImagePath: /workspace/workspace
54+
steps:
55+
- name: build-and-push
56+
image: busybox
57+
command:
58+
- /bin/sh
59+
args:
60+
- -ce
61+
- |
62+
set -e
63+
cat <<EOF > /workspace/workspace/index.json
64+
{
65+
"schemaVersion": 2,
66+
"manifests": [
67+
{
68+
"mediaType": "application/vnd.oci.image.index.v1+json",
69+
"size": 314,
70+
"digest": "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5"
71+
}
72+
]
73+
}
74+
EOF
75+
- name: echo
76+
image: busybox
77+
command:
78+
- /bin/sh
79+
args:
80+
- -ce
81+
- |
82+
set -e
83+
cat /workspace/workspace/index.json
84+
---
85+
apiVersion: tekton.dev/v1alpha1
86+
kind: TaskRun
87+
metadata:
88+
name: build-push-run
89+
spec:
90+
taskRef:
91+
name: build-push-kaniko
92+
trigger:
93+
type: manual
94+
inputs:
95+
resources:
96+
- name: workspace
97+
resourceRef:
98+
name: skaffold-git
99+
outputs:
100+
resources:
101+
- name: builtImage
102+
resourceRef:
103+
name: skaffold-image-leeroy-web

pkg/apis/pipeline/v1alpha1/image_resource.go

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ func NewImageResource(r *PipelineResource) (*ImageResource, error) {
4040
ir.URL = param.Value
4141
case strings.EqualFold(param.Name, "Digest"):
4242
ir.Digest = param.Value
43-
case strings.EqualFold(param.Name, "IndexPath"):
44-
ir.IndexPath = param.Value
4543
}
4644
}
4745

@@ -50,11 +48,11 @@ func NewImageResource(r *PipelineResource) (*ImageResource, error) {
5048

5149
// ImageResource defines an endpoint where artifacts can be stored, such as images.
5250
type ImageResource struct {
53-
Name string `json:"name"`
54-
Type PipelineResourceType `json:"type"`
55-
URL string `json:"url"`
56-
Digest string `json:"digest"`
57-
IndexPath string `json:"indexpath"`
51+
Name string `json:"name"`
52+
Type PipelineResourceType `json:"type"`
53+
URL string `json:"url"`
54+
Digest string `json:"digest"`
55+
OutputImagePath string
5856
}
5957

6058
// GetName returns the name of the resource
@@ -73,11 +71,10 @@ func (s ImageResource) GetParams() []Param { return []Param{} }
7371
// Replacements is used for template replacement on an ImageResource inside of a Taskrun.
7472
func (s *ImageResource) Replacements() map[string]string {
7573
return map[string]string{
76-
"name": s.Name,
77-
"type": string(s.Type),
78-
"url": s.URL,
79-
"digest": s.Digest,
80-
"indexpath": s.IndexPath,
74+
"name": s.Name,
75+
"type": string(s.Type),
76+
"url": s.URL,
77+
"digest": s.Digest,
8178
}
8279
}
8380

@@ -95,9 +92,9 @@ func (s *ImageResource) GetDownloadContainerSpec() ([]corev1.Container, error) {
9592
func (s *ImageResource) SetDestinationDirectory(path string) {
9693
}
9794

98-
// GetIndexPath return the path to get the index.json file
99-
func (s *ImageResource) GetIndexPath() string {
100-
return s.IndexPath
95+
// GetOutputImagePath return the path to get the index.json file
96+
func (s *ImageResource) GetOutputImagePath() string {
97+
return s.OutputImagePath
10198
}
10299

103100
func (s ImageResource) String() string {

pkg/apis/pipeline/v1alpha1/resource_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ type TaskResource struct {
9494
// +optional
9595
// TargetPath is the path in workspace directory where the task resource will be copied.
9696
TargetPath string `json:"targetPath"`
97-
// Resource Value stuff
97+
// +optional
98+
// Path to the index.json file for output container images
99+
OutputImagePath string `json:"outputImagePath"`
98100
}
99101

100102
// +genclient

pkg/apis/pipeline/v1alpha1/task_defaults.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,25 @@ limitations under the License.
1616

1717
package v1alpha1
1818

19-
import "context"
19+
import (
20+
"context"
21+
"fmt"
22+
)
2023

2124
func (t *Task) SetDefaults(ctx context.Context) {
2225
t.Spec.SetDefaults(ctx)
2326
}
2427

28+
// SetDefaults set any defaults for the task spec
2529
func (ts *TaskSpec) SetDefaults(ctx context.Context) {
30+
if ts.Outputs != nil && len(ts.Outputs.Resources) > 0 {
31+
for i, o := range ts.Outputs.Resources {
32+
if o.Type == PipelineResourceTypeImage {
33+
if o.OutputImagePath == "" {
34+
ts.Outputs.Resources[i].OutputImagePath = fmt.Sprintf("/tools/image-outputs/%s", o.Name)
35+
}
36+
}
37+
}
38+
}
2639
return
2740
}

pkg/apis/pipeline/v1alpha1/task_validation.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ func validateResourceVariables(steps []corev1.Container, inputs *Inputs, outputs
145145
if outputs != nil {
146146
for _, r := range outputs.Resources {
147147
resourceNames[r.Name] = struct{}{}
148+
if r.Type == PipelineResourceTypeImage {
149+
if r.OutputImagePath == "" {
150+
return apis.ErrMissingField("OutputImagePath")
151+
}
152+
}
148153
}
149154
}
150155
return validateVariables(steps, "resources", resourceNames)

pkg/apis/pipeline/v1alpha1/task_validation_test.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ var validResource = TaskResource{
3131
Type: "git",
3232
}
3333

34+
var validImageResource = TaskResource{
35+
Name: "source",
36+
Type: "image",
37+
}
38+
3439
var validBuildSteps = []corev1.Container{{
3540
Name: "mystep",
3641
Image: "myimage",
@@ -84,6 +89,17 @@ func TestTaskSpecValidate(t *testing.T) {
8489
},
8590
BuildSteps: validBuildSteps,
8691
},
92+
}, {
93+
name: "output image resoure",
94+
fields: fields{
95+
Inputs: &Inputs{
96+
Resources: []TaskResource{validImageResource},
97+
},
98+
Outputs: &Outputs{
99+
Resources: []TaskResource{validImageResource},
100+
},
101+
BuildSteps: validBuildSteps,
102+
},
87103
}, {
88104
name: "valid template variable",
89105
fields: fields{
@@ -116,7 +132,9 @@ func TestTaskSpecValidate(t *testing.T) {
116132
Outputs: tt.fields.Outputs,
117133
Steps: tt.fields.BuildSteps,
118134
}
119-
if err := ts.Validate(context.Background()); err != nil {
135+
ctx := context.Background()
136+
ts.SetDefaults(ctx)
137+
if err := ts.Validate(ctx); err != nil {
120138
t.Errorf("TaskSpec.Validate() = %v", err)
121139
}
122140
})

pkg/reconciler/v1alpha1/taskrun/resources/image_exporter.go

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ package resources
1919
import (
2020
"encoding/json"
2121
"flag"
22+
"os"
2223

2324
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
2425
listers "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1"
26+
"github.com/tektoncd/pipeline/pkg/names"
2527
"go.uber.org/zap"
2628
corev1 "k8s.io/api/core/v1"
2729
)
@@ -58,28 +60,49 @@ func AddOutputImageDigestExporter(
5860
logger.Errorf("Invalid Image Resource for taskRun %q resource %v; error: %s", tr.Name, boundResource, err.Error())
5961
return err
6062
}
63+
for _, o := range taskSpec.Outputs.Resources {
64+
if o.Name == boundResource.Name {
65+
if o.OutputImagePath != "" {
66+
if _, err := os.Stat(o.OutputImagePath); os.IsNotExist(err) {
67+
if err := os.MkdirAll(o.OutputImagePath, os.ModePerm); err != nil {
68+
return err
69+
}
70+
}
71+
imageResource.OutputImagePath = o.OutputImagePath
72+
break
73+
}
74+
}
75+
}
6176
output = append(output, imageResource)
6277
}
6378
}
6479

6580
if len(output) > 0 {
81+
augmentedSteps := []corev1.Container{}
6682
imagesJSON, err := json.Marshal(output)
6783
if err != nil {
6884
return err
6985
}
7086

71-
c := corev1.Container{
72-
Name: "image-digest-exporter",
73-
Image: *imageDigestExporterImage,
74-
Command: []string{"/ko-app/imagedigestexporter"},
75-
Args: []string{
76-
"-images", string(imagesJSON),
77-
},
87+
for _, s := range taskSpec.Steps {
88+
augmentedSteps = append(augmentedSteps, s)
89+
augmentedSteps = append(augmentedSteps, imageDigestExporterContainer(s.Name, imagesJSON))
7890
}
7991

80-
taskSpec.Steps = append(taskSpec.Steps, c)
92+
taskSpec.Steps = augmentedSteps
8193
}
8294
}
8395

8496
return nil
8597
}
98+
99+
func imageDigestExporterContainer(stepName string, imagesJSON []byte) corev1.Container {
100+
return corev1.Container{
101+
Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("image-digest-exporter-" + stepName),
102+
Image: *imageDigestExporterImage,
103+
Command: []string{"/ko-app/imagedigestexporter"},
104+
Args: []string{
105+
"-images", string(imagesJSON),
106+
},
107+
}
108+
}

0 commit comments

Comments
 (0)