Skip to content

Commit 6f33f96

Browse files
committed
build: take referencePolicy into account when resolving istag
1 parent 4ec486d commit 6f33f96

File tree

3 files changed

+125
-19
lines changed

3 files changed

+125
-19
lines changed

pkg/build/generator/generator.go

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -575,25 +575,48 @@ func (g *BuildGenerator) resolveImageStreamReference(ctx kapi.Context, from kapi
575575
glog.V(4).Infof("Resolving ImageStreamReference %s of Kind %s in namespace %s", from.Name, from.Kind, namespace)
576576
switch from.Kind {
577577
case "ImageStreamImage":
578-
imageStreamImage, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name)
578+
name, id, err := imageapi.ParseImageStreamImageName(from.Name)
579579
if err != nil {
580580
err = resolveError(from.Kind, namespace, from.Name, err)
581581
glog.V(2).Info(err)
582582
return "", err
583583
}
584-
image := imageStreamImage.Image
585-
glog.V(4).Infof("Resolved ImageStreamReference %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace)
586-
return image.DockerImageReference, nil
584+
stream, err := g.Client.GetImageStream(kapi.WithNamespace(ctx, namespace), name)
585+
if err != nil {
586+
err = resolveError(from.Kind, namespace, from.Name, err)
587+
glog.V(2).Info(err)
588+
return "", err
589+
}
590+
reference, ok := imageapi.DockerImageReferenceForImage(stream, id)
591+
if !ok {
592+
err = resolveError(from.Kind, namespace, from.Name, fmt.Errorf("unable to find corresponding tag for image %q", id))
593+
glog.V(2).Info(err)
594+
return "", err
595+
}
596+
glog.V(4).Infof("Resolved ImageStreamImage %s to image %q", from.Name, reference)
597+
return reference, nil
598+
587599
case "ImageStreamTag":
588-
imageStreamTag, err := g.Client.GetImageStreamTag(kapi.WithNamespace(ctx, namespace), from.Name)
600+
name, tag, err := imageapi.ParseImageStreamTagName(from.Name)
589601
if err != nil {
590602
err = resolveError(from.Kind, namespace, from.Name, err)
591603
glog.V(2).Info(err)
592604
return "", err
593605
}
594-
image := imageStreamTag.Image
595-
glog.V(4).Infof("Resolved ImageStreamTag %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace)
596-
return image.DockerImageReference, nil
606+
stream, err := g.Client.GetImageStream(kapi.WithNamespace(ctx, namespace), name)
607+
if err != nil {
608+
err = resolveError(from.Kind, namespace, from.Name, err)
609+
glog.V(2).Info(err)
610+
return "", err
611+
}
612+
reference, ok := imageapi.ResolveLatestTaggedImage(stream, tag)
613+
if !ok {
614+
err = resolveError(from.Kind, namespace, from.Name, fmt.Errorf("unable to find latest tagged image"))
615+
glog.V(2).Info(err)
616+
return "", err
617+
}
618+
glog.V(4).Infof("Resolved ImageStreamTag %s to image %q", from.Name, reference)
619+
return reference, nil
597620
case "DockerImage":
598621
return from.Name, nil
599622
default:
@@ -672,7 +695,7 @@ func (g *BuildGenerator) resolveImageSecret(ctx kapi.Context, secrets []kapi.Sec
672695

673696
func resolveError(kind string, namespace string, name string, err error) error {
674697
msg := fmt.Sprintf("Error resolving %s %s in namespace %s: %v", kind, name, namespace, err)
675-
return &errors.StatusError{unversioned.Status{
698+
return &errors.StatusError{ErrStatus: unversioned.Status{
676699
Status: unversioned.StatusFailure,
677700
Code: errors.StatusUnprocessableEntity,
678701
Reason: unversioned.StatusReasonInvalid,

pkg/build/generator/generator_test.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,38 @@ func TestInstantiateWithImageTrigger(t *testing.T) {
370370
bc = buildConfig
371371
return nil
372372
}
373+
client.GetImageStreamFunc =
374+
func(ctx kapi.Context, name string) (*imageapi.ImageStream, error) {
375+
return &imageapi.ImageStream{
376+
ObjectMeta: kapi.ObjectMeta{Name: name},
377+
Status: imageapi.ImageStreamStatus{
378+
DockerImageRepository: originalImage,
379+
Tags: map[string]imageapi.TagEventList{
380+
"tag1": {
381+
Items: []imageapi.TagEvent{
382+
{
383+
DockerImageReference: "ref/" + name + ":tag1",
384+
},
385+
},
386+
},
387+
"tag2": {
388+
Items: []imageapi.TagEvent{
389+
{
390+
DockerImageReference: "ref/" + name + ":tag2",
391+
},
392+
},
393+
},
394+
"tag3": {
395+
Items: []imageapi.TagEvent{
396+
{
397+
DockerImageReference: "ref/" + name + ":tag3",
398+
},
399+
},
400+
},
401+
},
402+
},
403+
}, nil
404+
}
373405
generator.Client = client
374406

375407
req := &buildapi.BuildRequest{
@@ -395,7 +427,7 @@ func TestInstantiateWithImageTrigger(t *testing.T) {
395427
if i == tc.triggerIndex {
396428
// Verify that the trigger got updated
397429
if bc.Spec.Triggers[i].ImageChange.LastTriggeredImageID != imageID {
398-
t.Errorf("%s: expeccted trigger at index %d to contain imageID %s", tc.name, i, imageID)
430+
t.Errorf("%s: expected trigger at index %d to contain imageID %s", tc.name, i, imageID)
399431
}
400432
continue
401433
}
@@ -405,8 +437,8 @@ func TestInstantiateWithImageTrigger(t *testing.T) {
405437
if from == nil {
406438
from = buildutil.GetInputReference(bc.Spec.Strategy)
407439
}
408-
if bc.Spec.Triggers[i].ImageChange.LastTriggeredImageID != ("ref@" + from.Name) {
409-
t.Errorf("%s: expected LastTriggeredImageID for trigger at %d to be %s. Got: %s", tc.name, i, "ref@"+from.Name, bc.Spec.Triggers[i].ImageChange.LastTriggeredImageID)
440+
if bc.Spec.Triggers[i].ImageChange.LastTriggeredImageID != ("ref/" + from.Name) {
441+
t.Errorf("%s: expected LastTriggeredImageID for trigger at %d (%+v) to be %s. Got: %s", tc.name, i, bc.Spec.Triggers[i].ImageChange.From, "ref/"+from.Name, bc.Spec.Triggers[i].ImageChange.LastTriggeredImageID)
410442
}
411443
}
412444
}
@@ -447,16 +479,16 @@ func TestInstantiateWithLastVersion(t *testing.T) {
447479
func TestInstantiateWithMissingImageStream(t *testing.T) {
448480
g := mockBuildGenerator()
449481
c := g.Client.(Client)
450-
c.GetImageStreamTagFunc = func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
451-
return nil, errors.NewNotFound(imageapi.Resource("imagestreamtags"), "testRepo")
482+
c.GetImageStreamFunc = func(ctx kapi.Context, name string) (*imageapi.ImageStream, error) {
483+
return nil, errors.NewNotFound(imageapi.Resource("imagestreams"), "testRepo")
452484
}
453485
g.Client = c
454486

455487
_, err := g.Instantiate(kapi.NewDefaultContext(), &buildapi.BuildRequest{})
456488
se, ok := err.(*errors.StatusError)
457489

458490
if !ok {
459-
t.Errorf("Expected errors.StatusError, got %T", err)
491+
t.Fatalf("Expected errors.StatusError, got %T", err)
460492
}
461493

462494
if se.ErrStatus.Code != errors.StatusUnprocessableEntity {
@@ -1421,7 +1453,7 @@ func TestResolveImageStreamRef(t *testing.T) {
14211453
Name: imageRepoName + ":" + tagName,
14221454
},
14231455
expectedSuccess: true,
1424-
expectedDockerRef: latestDockerReference,
1456+
expectedDockerRef: dockerReference,
14251457
},
14261458
{
14271459
streamRef: kapi.ObjectReference{
@@ -1445,7 +1477,7 @@ func TestResolveImageStreamRef(t *testing.T) {
14451477
t.Errorf("Scenario %d: did not get expected error", i)
14461478
}
14471479
if ref != test.expectedDockerRef {
1448-
t.Errorf("Scenario %d: Resolved reference %s did not match expected value %s", i, ref, test.expectedDockerRef)
1480+
t.Errorf("Scenario %d: Resolved reference %q did not match expected value %q", i, ref, test.expectedDockerRef)
14491481
}
14501482
}
14511483
}
@@ -1554,7 +1586,6 @@ func mockBuildGeneratorForInstantiate() *BuildGenerator {
15541586
},
15551587
}, nil
15561588
}
1557-
g.Client = c
15581589
return g
15591590
}
15601591

@@ -1603,7 +1634,7 @@ func mockBuildGenerator() *BuildGenerator {
16031634
},
16041635
imageapi.DefaultImageTag: {
16051636
Items: []imageapi.TagEvent{
1606-
{DockerImageReference: latestDockerReference},
1637+
{DockerImageReference: latestDockerReference, Image: "myid"},
16071638
},
16081639
},
16091640
},

pkg/image/api/helper.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,30 @@ func FollowTagReference(stream *ImageStream, tag string) (finalTag string, ref *
541541
}
542542
}
543543

544+
// LatestImageTagEvent returns the most recent TagEvent and the tag for the specified
545+
// image.
546+
func LatestImageTagEvent(stream *ImageStream, imageID string) (string, *TagEvent) {
547+
var (
548+
latestTagEvent *TagEvent
549+
latestTag string
550+
)
551+
for tag, events := range stream.Status.Tags {
552+
if len(events.Items) == 0 {
553+
continue
554+
}
555+
for i, event := range events.Items {
556+
if event.Image != imageID {
557+
continue
558+
}
559+
if latestTagEvent == nil || (latestTagEvent != nil && event.Created.After(latestTagEvent.Created.Time)) {
560+
latestTagEvent = &events.Items[i]
561+
latestTag = tag
562+
}
563+
}
564+
}
565+
return latestTag, latestTagEvent
566+
}
567+
544568
// LatestTaggedImage returns the most recent TagEvent for the specified image
545569
// repository and tag. Will resolve lookups for the empty tag. Returns nil
546570
// if tag isn't present in stream.status.tags.
@@ -610,6 +634,34 @@ func ResolveLatestTaggedImage(stream *ImageStream, tag string) (string, bool) {
610634
}
611635
}
612636

637+
// DockerImageReferenceForImage returns the docker reference for specified image. Assuming
638+
// the image stream contains the image and the image has corresponding tag, this function
639+
// will try to find this tag and take the reference policy into the account.
640+
// If the image stream does not reference the image or the image does not have
641+
// corresponding tag event, this function will return false.
642+
func DockerImageReferenceForImage(stream *ImageStream, imageID string) (string, bool) {
643+
tag, event := LatestImageTagEvent(stream, imageID)
644+
if len(tag) == 0 {
645+
return "", false
646+
}
647+
ref, ok := stream.Spec.Tags[tag]
648+
if !ok {
649+
return event.DockerImageReference, true
650+
}
651+
switch ref.ReferencePolicy.Type {
652+
case LocalTagReferencePolicy:
653+
ref, err := ParseDockerImageReference(stream.Status.DockerImageRepository)
654+
if err != nil {
655+
return event.DockerImageReference, true
656+
}
657+
ref.Tag = ""
658+
ref.ID = event.Image
659+
return ref.Exact(), true
660+
default:
661+
return event.DockerImageReference, true
662+
}
663+
}
664+
613665
// DifferentTagEvent returns true if the supplied tag event matches the current stream tag event.
614666
// Generation is not compared.
615667
func DifferentTagEvent(stream *ImageStream, tag string, next TagEvent) bool {

0 commit comments

Comments
 (0)