Example #1
0
func agedStream(registry, namespace, name string, ageInMinutes int64, tags map[string]imageapi.TagEventList) imageapi.ImageStream {
	stream := imageapi.ImageStream{
		ObjectMeta: kapi.ObjectMeta{
			Namespace: namespace,
			Name:      name,
		},
		Status: imageapi.ImageStreamStatus{
			DockerImageRepository: fmt.Sprintf("%s/%s/%s", registry, namespace, name),
			Tags: tags,
		},
	}

	if ageInMinutes >= 0 {
		stream.CreationTimestamp = unversioned.NewTime(unversioned.Now().Add(time.Duration(-1*ageInMinutes) * time.Minute))
	}

	return stream
}
Example #2
0
// dockerImageRepository determines the docker image stream for stream.
// If stream.DockerImageRepository is set, that value is returned. Otherwise,
// if a default registry exists, the value returned is of the form
// <default registry>/<namespace>/<stream name>.
func (s Strategy) dockerImageRepository(stream *api.ImageStream) string {
	registry, ok := s.defaultRegistry.DefaultRegistry()
	if !ok {
		return stream.Spec.DockerImageRepository
	}

	if len(stream.Namespace) == 0 {
		stream.Namespace = kapi.NamespaceDefault
	}
	ref := api.DockerImageReference{
		Registry:  registry,
		Namespace: stream.Namespace,
		Name:      stream.Name,
	}
	return ref.String()
}
Example #3
0
// done marks the stream as being processed due to an error or failure condition.
func (c *ImportController) done(stream *api.ImageStream, reason string) error {
	if len(reason) == 0 {
		reason = unversioned.Now().UTC().Format(time.RFC3339)
	} else if len(reason) > 300 {
		// cut down the reason up to 300 characters max.
		reason = reason[:300]
	}
	if stream.Annotations == nil {
		stream.Annotations = make(map[string]string)
	}
	stream.Annotations[api.DockerImageRepositoryCheckAnnotation] = reason
	if _, err := c.streams.ImageStreams(stream.Namespace).Update(stream); err != nil {
		return err
	}
	return nil
}
Example #4
0
// done marks the stream as being processed due to an error or failure condition
func (c *ImportController) done(stream *api.ImageStream, reason string, retry int) error {
	if len(reason) == 0 {
		reason = util.Now().UTC().Format(time.RFC3339)
	}
	if stream.Annotations == nil {
		stream.Annotations = make(map[string]string)
	}
	stream.Annotations[api.DockerImageRepositoryCheckAnnotation] = reason
	if _, err := c.streams.ImageStreams(stream.Namespace).Update(stream); err != nil && !errors.IsNotFound(err) {
		if errors.IsConflict(err) && retry > 0 {
			if stream, err := c.streams.ImageStreams(stream.Namespace).Get(stream.Name); err == nil {
				return c.done(stream, reason, retry-1)
			}
		}
		return err
	}
	return nil
}
func TestImageStreamAdmissionEvaluatorUsage(t *testing.T) {
	for _, tc := range []struct {
		name           string
		oldSpec        *imageapi.ImageStreamSpec
		oldStatus      *imageapi.ImageStreamStatus
		newSpec        *imageapi.ImageStreamSpec
		newStatus      *imageapi.ImageStreamStatus
		expectedImages int64
	}{
		{
			name:           "empty image stream",
			oldStatus:      nil,
			newStatus:      &imageapi.ImageStreamStatus{},
			expectedImages: 0,
		},

		{
			name:      "new image stream with one image",
			oldStatus: nil,
			newStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
				},
			},
			expectedImages: 1,
		},

		{
			name: "no change",
			oldSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"new": {
						Name: "new",
						From: &kapi.ObjectReference{
							Kind:      "ImageStreamImage",
							Namespace: "shared",
							Name:      fmt.Sprintf("is@%s", miscImageDigest),
						},
					},
				},
			},
			oldStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
				},
			},
			newSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"new": {
						Name: "new",
						From: &kapi.ObjectReference{
							Kind:      "ImageStreamImage",
							Namespace: "shared",
							Name:      fmt.Sprintf("is@%s", miscImageDigest),
						},
					},
				},
			},
			newStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
				},
			},
			// misc image is already present in common is
			expectedImages: 1,
		},

		{
			name: "adding two new tags",
			oldStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
				},
			},
			newStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
					"foo": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/sharedlayer@%s", childImageWith2LayersDigest),
								Image:                childImageWith2LayersDigest,
							},
						},
					},
					"bar": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/sharedlayer@%s", baseImageWith2LayersDigest),
								Image:                baseImageWith2LayersDigest,
							},
						},
					},
				},
			},
			expectedImages: 3,
		},

		{
			name: "adding an item and deleting the other tag",
			oldStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"foo": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/sharedlayer@%s", miscImageDigest),
								Image:                miscImageDigest,
							},
						},
					},
					"bar": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/sharedlayer@%s", baseImageWith2LayersDigest),
								Image:                baseImageWith2LayersDigest,
							},
						},
					},
				},
			},
			newStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"foo": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/sharedlayer@%s", childImageWith3LayersDigest),
								Image:                childImageWith3LayersDigest,
							},
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/sharedlayer@%s", miscImageDigest),
								Image:                miscImageDigest,
							},
						},
					},
				},
			},
			// misc image is already present in common is
			expectedImages: 1,
		},

		{
			name: "adding a tag to spec",
			oldStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
				},
			},
			newSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"new": {
						Name: "new",
						From: &kapi.ObjectReference{
							Kind:      "ImageStreamImage",
							Namespace: "shared",
							Name:      fmt.Sprintf("is@%s", baseImageWith2LayersDigest),
						},
					},
				},
			},
			newStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith1LayerDigest),
								Image:                baseImageWith1LayerDigest,
							},
						},
					},
				},
			},
			expectedImages: 2,
		},

		{
			name: "adding a tag to status already present in spec",
			oldSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"latest": {
						Name: "new",
						From: &kapi.ObjectReference{
							Kind:      "ImageStreamImage",
							Namespace: "shared",
							Name:      fmt.Sprintf("is@%s", childImageWith2LayersDigest),
						},
					},
				},
			},
			newSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"latest": {
						Name: "new",
						From: &kapi.ObjectReference{
							Kind:      "ImageStreamImage",
							Namespace: "shared",
							Name:      fmt.Sprintf("is@%s", childImageWith2LayersDigest),
						},
					},
				},
			},
			newStatus: &imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"latest": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/is@%s", baseImageWith2LayersDigest),
								Image:                childImageWith2LayersDigest,
							},
						},
					},
				},
			},
			expectedImages: 1,
		},

		{
			name: "refer to image in another namespace already present",
			newSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"misc": {
						Name: "misc",
						From: &kapi.ObjectReference{
							Kind:      "ImageStreamImage",
							Namespace: "shared",
							Name:      fmt.Sprintf("is@%s", miscImageDigest),
						},
					},
				},
			},
			expectedImages: 0,
		},

		{
			name: "refer to imagestreamimage in the same namespace",
			newSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"commonisi": {
						Name: "commonisi",
						From: &kapi.ObjectReference{
							Kind: "ImageStreamImage",
							Name: fmt.Sprintf("common@%s", miscImageDigest),
						},
					},
				},
			},
			expectedImages: 0,
		},

		{
			name: "refer to imagestreamtag in the same namespace",
			newSpec: &imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{
					"commonist": {
						Name: "commonist",
						From: &kapi.ObjectReference{
							Kind: "ImageStreamTag",
							Name: "common:misc",
						},
					},
				},
			},
			expectedImages: 0,
		},
	} {

		var newIS, oldIS *imageapi.ImageStream

		if tc.oldStatus != nil || tc.oldSpec != nil {
			oldIS = &imageapi.ImageStream{
				ObjectMeta: kapi.ObjectMeta{
					Namespace: "test",
					Name:      "is",
				},
			}
			if tc.oldSpec != nil {
				oldIS.Spec = *tc.oldSpec
			}
			if tc.oldStatus != nil {
				oldIS.Status = *tc.oldStatus
			}
		}

		if tc.newStatus != nil || tc.newSpec != nil {
			newIS = &imageapi.ImageStream{
				ObjectMeta: kapi.ObjectMeta{
					Namespace: "test",
					Name:      "is",
				},
			}
			if tc.newSpec != nil {
				newIS.Spec = *tc.newSpec
			}
			if tc.newStatus != nil {
				newIS.Status = *tc.newStatus
			}
		}

		commonIS := imageapi.ImageStream{
			ObjectMeta: kapi.ObjectMeta{
				Namespace: "test",
				Name:      "common",
			},
			Status: imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{
					"misc": {
						Items: []imageapi.TagEvent{
							{
								DockerImageReference: fmt.Sprintf("172.30.12.34:5000/test/common@%s", miscImageDigest),
								Image:                miscImageDigest,
							},
						},
					},
				},
			},
		}
		iss := []imageapi.ImageStream{commonIS}
		if oldIS != nil {
			iss = append(iss, *oldIS)
		}

		fakeClient := &testclient.Fake{}
		fakeClient.AddReactor("get", "imagestreams", getFakeImageStreamGetHandler(t, iss...))
		fakeClient.AddReactor("list", "imagestreams", getFakeImageStreamListHandler(t, iss...))
		fakeClient.AddReactor("get", "images", getFakeImageGetHandler(t, "test"))

		evaluator := NewImageStreamAdmissionEvaluator(fakeClient)

		usage := evaluator.Usage(newIS)

		if len(usage) != len(expectedResources) {
			t.Errorf("[%s]: got unexpected number of computed resources: %d != %d", tc.name, len(usage), len(expectedResources))
		}

		expectedUsage := kapi.ResourceList{
			imageapi.ResourceImages: *resource.NewQuantity(tc.expectedImages, resource.DecimalSI),
		}

		masked := kquota.Mask(usage, expectedResources)
		if len(masked) != len(expectedUsage) {
			for k := range usage {
				if _, exists := masked[k]; !exists {
					t.Errorf("[%s]: got unexpected resource %q from Usage() method", tc.name, k)
				}
			}

			for k := range expectedUsage {
				if _, exists := masked[k]; !exists {
					t.Errorf("[%s]: expected resource %q not computed", tc.name, k)
				}
			}
		}

		for rname, expectedValue := range expectedUsage {
			if v, exists := masked[rname]; exists {
				if v.Cmp(expectedValue) != 0 {
					t.Errorf("[%s]: got unexpected usage for %q: %s != %s", tc.name, rname, v.String(), expectedValue.String())
				}
			}
		}
	}
}
Example #6
0
// getImageStreamImageSuggestion will return the appropriate marker Suggestion for when a BuildConfig is missing its input ImageStreamImage
func getImageStreamImageSuggestion(imageID string, imageStream *imageapi.ImageStream) osgraph.Suggestion {
	// check the images stream to see if any import images are in flight or have failed
	annotation, ok := imageStream.Annotations[imageapi.DockerImageRepositoryCheckAnnotation]
	if !ok {
		return osgraph.Suggestion(fmt.Sprintf("`oc import-image %s --from=` where `--from` specifies an image with hexadecimal ID %s", imageStream.GetName(), imageID))
	}

	if checkTime, err := time.Parse(time.RFC3339, annotation); err == nil {
		// this time based annotation is set by pkg/image/controller/controller.go whenever import/tag operations are performed; unless
		// in the midst of an import/tag operation, it stays set and serves as a timestamp for when the last operation occurred;
		// so we will check if the image stream has been updated "recently";
		// in case it is a slow link to the remote repo, see if if the check annotation occured within the last 5 minutes; if so, consider that as potentially "in progress"
		compareTime := checkTime.Add(5 * time.Minute)
		currentTime, _ := time.Parse(time.RFC3339, unversioned.Now().UTC().Format(time.RFC3339))
		if compareTime.Before(currentTime) {
			return osgraph.Suggestion(fmt.Sprintf("`oc import-image %s --from=` where `--from` specifies an image with hexadecimal ID %s", imageStream.GetName(), imageID))
		}

		return osgraph.Suggestion(fmt.Sprintf("`oc import-image %s --from=` with hexadecimal ID %s possibly in progress", imageStream.GetName(), imageID))

	}
	return osgraph.Suggestion(fmt.Sprintf("Possible error occurred with `oc import-image %s --from=` with hexadecimal ID %s; inspect images stream annotations", imageStream.GetName(), imageID))
}