Skip to content

Commit e01fe60

Browse files
dlorenctekton-robot
authored andcommitted
Update TaskRunStatus.ResourcesResult to be more generic.
This commit extends ResourcesResult to work for more than just ImageOutputs, but moving to a key/value map instead of a fixed key of "digest". This also updates the image_digest_exporter to write data in both formats for backwards compatibility, and updates our e2e test to use this mechanism.
1 parent f8aca59 commit e01fe60

File tree

8 files changed

+81
-67
lines changed

8 files changed

+81
-67
lines changed

cmd/imagedigestexporter/main.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,20 @@ func main() {
5959
if err != nil {
6060
log.Fatalf("Unexpected error getting image digest for %s: %v", imageResource.Name, err)
6161
}
62-
output = append(output, v1alpha1.PipelineResourceResult{Name: imageResource.Name, Digest: digest.String()})
62+
// We need to write both the old Name/Digest style and the new Key/Value styles.
63+
output = append(output, v1alpha1.PipelineResourceResult{
64+
Name: imageResource.Name,
65+
Digest: digest.String(),
66+
})
67+
68+
output = append(output, v1alpha1.PipelineResourceResult{
69+
Key: "digest",
70+
Value: digest.String(),
71+
ResourceRef: v1alpha1.PipelineResourceRef{
72+
Name: imageResource.Name,
73+
},
74+
})
75+
6376
}
6477

6578
imagesJSON, err := json.Marshal(output)

docs/resources.md

+17
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,23 @@ spec:
194194
emptyDir: {}
195195
```
196196

197+
### Resource Status
198+
199+
When resources are bound inside a TaskRun, they can include extra information in the TaskRun Status.ResourcesResult field.
200+
This information can be useful for auditing the exact resources used by a TaskRun later.
201+
Currently the only resource that uses this mechanism is the Image resource, which includes the exact digest
202+
of an image built by a TaskRun and declared as an output.
203+
204+
For an example of what this output looks like:
205+
206+
```yaml
207+
resourcesResult:
208+
- key: digest
209+
value: sha256:a08412a4164b85ae521b0c00cf328e3aab30ba94a526821367534b81e51cb1cb
210+
resourceRef:
211+
name: skaffold-image-leeroy-web
212+
```
213+
197214
## Resource Types
198215

199216
The following `PipelineResources` are currently supported:

examples/taskruns/build-push-kaniko.yaml

+6-1
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,18 @@ spec:
4343
type: image
4444
steps:
4545
- name: build-and-push
46-
image: gcr.io/kaniko-project/executor:v0.9.0
46+
image: gcr.io/kaniko-project/executor:v0.13.0
47+
# specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential
48+
env:
49+
- name: "DOCKER_CONFIG"
50+
value: "/builder/home/.docker/"
4751
command:
4852
- /kaniko/executor
4953
args:
5054
- --dockerfile=$(inputs.params.pathToDockerFile)
5155
- --destination=$(outputs.resources.builtImage.url)
5256
- --context=$(inputs.params.pathToContext)
57+
- --oci-layout-path=/builder/home/image-outputs/builtImage
5358
sidecars:
5459
- image: registry
5560
name: registry

pkg/apis/pipeline/v1alpha1/resource_types.go

+5
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,13 @@ type PipelineResourceBinding struct {
164164

165165
// PipelineResourceResult used to export the image name and digest as json
166166
type PipelineResourceResult struct {
167+
// Name and Digest are deprecated.
167168
Name string `json:"name"`
168169
Digest string `json:"digest"`
170+
// These will replace Name and Digest (https://github.com/tektoncd/pipeline/issues/1392)
171+
Key string `json:"key"`
172+
Value string `json:"value"`
173+
ResourceRef PipelineResourceRef `json:"resourceRef,omitempty"`
169174
}
170175

171176
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/reconciler/taskrun/resources/image_exporter.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ func AddOutputImageDigestExporter(
8484

8585
// UpdateTaskRunStatusWithResourceResult if there is an update to the outout image resource, add to taskrun status result
8686
func UpdateTaskRunStatusWithResourceResult(taskRun *v1alpha1.TaskRun, logContent []byte) error {
87-
err := json.Unmarshal(logContent, &taskRun.Status.ResourcesResult)
88-
if err != nil {
87+
if err := json.Unmarshal(logContent, &taskRun.Status.ResourcesResult); err != nil {
8988
return xerrors.Errorf("Failed to unmarshal output image exporter JSON output: %w", err)
9089
}
9190
return nil

test/kaniko_task_test.go

+36-62
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ package test
2020

2121
import (
2222
"fmt"
23-
"io/ioutil"
24-
"regexp"
25-
"strings"
2623
"testing"
2724
"time"
2825

@@ -34,32 +31,41 @@ import (
3431
"golang.org/x/xerrors"
3532
corev1 "k8s.io/api/core/v1"
3633
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
37-
"k8s.io/client-go/kubernetes"
3834
knativetest "knative.dev/pkg/test"
3935
)
4036

4137
const (
42-
kanikoTaskName = "kanikotask"
43-
kanikoTaskRunName = "kanikotask-run"
44-
kanikoResourceName = "go-example-git"
38+
kanikoTaskName = "kanikotask"
39+
kanikoTaskRunName = "kanikotask-run"
40+
kanikoGitResourceName = "go-example-git"
41+
kanikoImageResourceName = "go-example-image"
4542
)
4643

4744
func getGitResource(namespace string) *v1alpha1.PipelineResource {
48-
return tb.PipelineResource(kanikoResourceName, namespace, tb.PipelineResourceSpec(
45+
return tb.PipelineResource(kanikoGitResourceName, namespace, tb.PipelineResourceSpec(
4946
v1alpha1.PipelineResourceTypeGit,
5047
tb.PipelineResourceSpecParam("Url", "https://github.com/GoogleContainerTools/kaniko"),
5148
))
5249
}
5350

51+
func getImageResource(namespace, repo string) *v1alpha1.PipelineResource {
52+
return tb.PipelineResource(kanikoImageResourceName, namespace, tb.PipelineResourceSpec(
53+
v1alpha1.PipelineResourceTypeImage,
54+
tb.PipelineResourceSpecParam("url", repo),
55+
))
56+
}
57+
5458
func getTask(repo, namespace string, withSecretConfig bool) *v1alpha1.Task {
5559
taskSpecOps := []tb.TaskSpecOp{
5660
tb.TaskInputs(tb.InputsResource("gitsource", v1alpha1.PipelineResourceTypeGit)),
61+
tb.TaskOutputs(tb.OutputsResource("builtImage", v1alpha1.PipelineResourceTypeImage)),
5762
}
5863
stepOps := []tb.StepOp{
5964
tb.StepArgs(
6065
"--dockerfile=/workspace/gitsource/integration/dockerfiles/Dockerfile_test_label",
6166
fmt.Sprintf("--destination=%s", repo),
6267
"--context=/workspace/gitsource",
68+
"--oci-layout-path=/builder/home/image-outputs/builtImage",
6369
),
6470
}
6571
if withSecretConfig {
@@ -73,7 +79,7 @@ func getTask(repo, namespace string, withSecretConfig bool) *v1alpha1.Task {
7379
},
7480
})))
7581
}
76-
step := tb.Step("kaniko", "gcr.io/kaniko-project/executor:v0.9.0", stepOps...)
82+
step := tb.Step("kaniko", "gcr.io/kaniko-project/executor:v0.13.0", stepOps...)
7783
taskSpecOps = append(taskSpecOps, step)
7884

7985
return tb.Task(kanikoTaskName, namespace, tb.TaskSpec(taskSpecOps...))
@@ -83,7 +89,8 @@ func getTaskRun(namespace string) *v1alpha1.TaskRun {
8389
return tb.TaskRun(kanikoTaskRunName, namespace, tb.TaskRunSpec(
8490
tb.TaskRunTaskRef(kanikoTaskName),
8591
tb.TaskRunTimeout(2*time.Minute),
86-
tb.TaskRunInputs(tb.TaskRunInputsResource("gitsource", tb.TaskResourceBindingRef(kanikoResourceName))),
92+
tb.TaskRunInputs(tb.TaskRunInputsResource("gitsource", tb.TaskResourceBindingRef(kanikoGitResourceName))),
93+
tb.TaskRunOutputs(tb.TaskRunOutputsResource("builtImage", tb.TaskResourceBindingRef(kanikoImageResourceName))),
8794
))
8895
}
8996

@@ -101,9 +108,14 @@ func TestKanikoTaskRun(t *testing.T) {
101108
t.Fatalf("Expected to create kaniko creds: %v", err)
102109
}
103110

104-
t.Logf("Creating Git PipelineResource %s", kanikoResourceName)
111+
t.Logf("Creating Git PipelineResource %s", kanikoGitResourceName)
105112
if _, err := c.PipelineResourceClient.Create(getGitResource(namespace)); err != nil {
106-
t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoResourceName, err)
113+
t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
114+
}
115+
116+
t.Logf("Creating Image PipelineResource %s", repo)
117+
if _, err := c.PipelineResourceClient.Create(getImageResource(namespace, repo)); err != nil {
118+
t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
107119
}
108120

109121
t.Logf("Creating Task %s", kanikoTaskName)
@@ -117,32 +129,28 @@ func TestKanikoTaskRun(t *testing.T) {
117129
}
118130

119131
// Verify status of TaskRun (wait for it)
120-
var podName string
132+
121133
if err := WaitForTaskRunState(c, kanikoTaskRunName, func(tr *v1alpha1.TaskRun) (bool, error) {
122-
podName = tr.Status.PodName
123134
return TaskRunSucceed(kanikoTaskRunName)(tr)
124135
}, "TaskRunCompleted"); err != nil {
125136
t.Errorf("Error waiting for TaskRun %s to finish: %s", kanikoTaskRunName, err)
126137
}
127138

128-
// There will be a Pod with the expected name.
129-
if _, err := c.KubeClient.Kube.CoreV1().Pods(namespace).Get(podName, metav1.GetOptions{}); err != nil {
130-
t.Fatalf("Error getting build pod: %v", err)
131-
}
132-
133-
logs, err := getAllLogsFromPod(c.KubeClient.Kube, podName, namespace)
139+
tr, err := c.TaskRunClient.Get(kanikoTaskRunName, metav1.GetOptions{})
134140
if err != nil {
135-
t.Fatalf("Expected to get logs from pod %s: %v", podName, err)
141+
t.Errorf("Error retrieving taskrun: %s", err)
142+
}
143+
digest := ""
144+
for _, rr := range tr.Status.ResourcesResult {
145+
if rr.Key == "digest" {
146+
digest = rr.Value
147+
}
136148
}
137-
// make sure the pushed digest matches the one we pushed
138-
re := regexp.MustCompile(`digest: (sha256:\w+)`)
139-
match := re.FindStringSubmatch(logs)
140-
// make sure we found a match and it has the capture group
141-
if len(match) != 2 {
142-
t.Fatalf("Expected to find an image digest in the build output: %s", logs)
149+
if digest == "" {
150+
t.Errorf("Digest not found in TaskRun.Status: %v", tr.Status)
143151
}
152+
144153
// match the local digest, which is first capture group against the remote image
145-
digest := match[1]
146154
remoteDigest, err := getRemoteDigest(repo)
147155
if err != nil {
148156
t.Fatalf("Expected to get digest for remote image %s", repo)
@@ -152,40 +160,6 @@ func TestKanikoTaskRun(t *testing.T) {
152160
}
153161
}
154162

155-
func getContainerLogs(c kubernetes.Interface, pod, namespace string, containers ...string) (string, error) {
156-
sb := strings.Builder{}
157-
for _, container := range containers {
158-
req := c.CoreV1().Pods(namespace).GetLogs(pod, &corev1.PodLogOptions{Follow: true, Container: container})
159-
rc, err := req.Stream()
160-
if err != nil {
161-
return "", err
162-
}
163-
bs, err := ioutil.ReadAll(rc)
164-
if err != nil {
165-
return "", err
166-
}
167-
sb.Write(bs)
168-
}
169-
return sb.String(), nil
170-
}
171-
172-
func getAllLogsFromPod(c kubernetes.Interface, pod, namespace string) (string, error) {
173-
p, err := c.CoreV1().Pods(namespace).Get(pod, metav1.GetOptions{})
174-
if err != nil {
175-
return "", err
176-
}
177-
178-
var containers []string
179-
for _, initContainer := range p.Spec.InitContainers {
180-
containers = append(containers, initContainer.Name)
181-
}
182-
for _, container := range p.Spec.Containers {
183-
containers = append(containers, container.Name)
184-
}
185-
186-
return getContainerLogs(c, pod, namespace, containers...)
187-
}
188-
189163
func getRemoteDigest(image string) (string, error) {
190164
ref, err := name.ParseReference(image, name.WeakValidation)
191165
if err != nil {

test/pipelinerun_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func TestPipelineRun(t *testing.T) {
7070

7171
for _, res := range getFanInFanOutGitResources(namespace) {
7272
if _, err := c.PipelineResourceClient.Create(res); err != nil {
73-
t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoResourceName, err)
73+
t.Fatalf("Failed to create Pipeline Resource `%s`: %s", kanikoGitResourceName, err)
7474
}
7575
}
7676

0 commit comments

Comments
 (0)