// makeImageStreamTagAdmissionUsageFunc returns a function that computes a resource usage for given image
// stream tag during admission.
func makeImageStreamTagAdmissionUsageFunc(isNamespacer osclient.ImageStreamsNamespacer) generic.UsageFunc {
	return func(object runtime.Object) kapi.ResourceList {
		ist, ok := object.(*imageapi.ImageStreamTag)
		if !ok {
			return kapi.ResourceList{}
		}

		res := map[kapi.ResourceName]resource.Quantity{
			imageapi.ResourceImageStreams: *resource.NewQuantity(0, resource.BinarySI),
		}

		isName, _, err := imageapi.ParseImageStreamTagName(ist.Name)
		if err != nil {
			utilruntime.HandleError(err)
			return kapi.ResourceList{}
		}

		is, err := isNamespacer.ImageStreams(ist.Namespace).Get(isName)
		if err != nil {
			if !kerrors.IsNotFound(err) {
				utilruntime.HandleError(fmt.Errorf("failed to get image stream %s/%s: %v", ist.Namespace, isName, err))
			}
		}
		if is == nil {
			res[imageapi.ResourceImageStreams] = *resource.NewQuantity(1, resource.BinarySI)
		}

		return res
	}
}
示例#2
0
// DeletingImageStreamPruneFunc returns an ImageStreamPruneFunc that deletes the imageStream.
func DeletingImageStreamPruneFunc(streams client.ImageStreamsNamespacer) ImageStreamPruneFunc {
	return func(stream *imageapi.ImageStream, image *imageapi.Image) (*imageapi.ImageStream, error) {
		glog.V(4).Infof("Checking if ImageStream %s/%s has references to image in status.tags", stream.Namespace, stream.Name)
		for tag, history := range stream.Status.Tags {
			glog.V(4).Infof("Checking tag %q", tag)
			newHistory := imageapi.TagEventList{}
			for i, tagEvent := range history.Items {
				glog.V(4).Infof("Checking tag event %d with image %q", i, tagEvent.Image)
				if tagEvent.Image != image.Name {
					glog.V(4).Infof("Tag event doesn't match deleting image - keeping")
					newHistory.Items = append(newHistory.Items, tagEvent)
				}
			}
			stream.Status.Tags[tag] = newHistory
		}

		glog.V(4).Infof("Updating ImageStream %s/%s", stream.Namespace, stream.Name)
		glog.V(5).Infof("Updated stream: %#v", stream)
		updatedStream, err := streams.ImageStreams(stream.Namespace).UpdateStatus(stream)
		if err != nil {
			return nil, err
		}
		return updatedStream, nil
	}
}
// makeImageStreamImportAdmissionUsageFunc retuns a function for computing a usage of an image stream import.
func makeImageStreamImportAdmissionUsageFunc(isNamespacer osclient.ImageStreamsNamespacer) generic.UsageFunc {
	return func(object runtime.Object) kapi.ResourceList {
		isi, ok := object.(*imageapi.ImageStreamImport)
		if !ok {
			return kapi.ResourceList{}
		}

		usage := map[kapi.ResourceName]resource.Quantity{
			imageapi.ResourceImageStreams: *resource.NewQuantity(0, resource.DecimalSI),
		}

		if !isi.Spec.Import || (len(isi.Spec.Images) == 0 && isi.Spec.Repository == nil) {
			return usage
		}

		is, err := isNamespacer.ImageStreams(isi.Namespace).Get(isi.Name)
		if err != nil {
			if !kerrors.IsNotFound(err) {
				utilruntime.HandleError(fmt.Errorf("failed to list image streams: %v", err))
			}
		}
		if is == nil {
			usage[imageapi.ResourceImageStreams] = *resource.NewQuantity(1, resource.DecimalSI)
		}

		return usage
	}
}
示例#4
0
// NewImageStreamEvaluator computes resource usage of ImageStreams. Instantiating this is necessary for
// resource quota admission controller to properly work on image stream related objects.
func NewImageStreamEvaluator(isNamespacer osclient.ImageStreamsNamespacer) kquota.Evaluator {
	allResources := []kapi.ResourceName{
		imageapi.ResourceImageStreams,
	}

	return &generic.GenericEvaluator{
		Name:              imageStreamEvaluatorName,
		InternalGroupKind: imageapi.Kind("ImageStream"),
		InternalOperationResources: map[admission.Operation][]kapi.ResourceName{
			admission.Create: allResources,
		},
		MatchedResourceNames: allResources,
		MatchesScopeFunc:     generic.MatchesNoScopeFunc,
		ConstraintsFunc:      generic.ObjectCountConstraintsFunc(imageapi.ResourceImageStreams),
		UsageFunc:            generic.ObjectCountUsageFunc(imageapi.ResourceImageStreams),
		ListFuncByNamespace: func(namespace string, options kapi.ListOptions) (runtime.Object, error) {
			return isNamespacer.ImageStreams(namespace).List(options)
		},
	}
}
示例#5
0
// processTriggers will go over all deployment triggers that require processing and update
// the deployment config accordingly. This contains the work that the image change controller
// had been doing up to the point we got the /instantiate endpoint.
func processTriggers(config *deployapi.DeploymentConfig, isn client.ImageStreamsNamespacer, force bool) error {
	errs := []error{}

	// Process any image change triggers.
	for _, trigger := range config.Spec.Triggers {
		if trigger.Type != deployapi.DeploymentTriggerOnImageChange {
			continue
		}

		params := trigger.ImageChangeParams

		// Forced deployments should always try to resolve the images in the template.
		// On the other hand, paused deployments or non-automatic triggers shouldn't.
		if !force && (config.Spec.Paused || !params.Automatic) {
			continue
		}

		// Tag references are already validated
		name, tag, _ := imageapi.SplitImageStreamTag(params.From.Name)
		stream, err := isn.ImageStreams(params.From.Namespace).Get(name)
		if err != nil {
			if !errors.IsNotFound(err) {
				errs = append(errs, err)
			}
			continue
		}

		// Find the latest tag event for the trigger reference.
		latestEvent := imageapi.LatestTaggedImage(stream, tag)
		if latestEvent == nil {
			continue
		}

		// Ensure a change occurred
		latestRef := latestEvent.DockerImageReference
		if len(latestRef) == 0 || latestRef == params.LastTriggeredImage {
			continue
		}

		// Update containers
		names := sets.NewString(params.ContainerNames...)
		for i := range config.Spec.Template.Spec.Containers {
			container := &config.Spec.Template.Spec.Containers[i]
			if !names.Has(container.Name) {
				continue
			}

			if container.Image != latestRef {
				// Update the image
				container.Image = latestRef
				// Log the last triggered image ID
				params.LastTriggeredImage = latestRef
			}
		}
	}

	if err := utilerrors.NewAggregate(errs); err != nil {
		return errors.NewInternalError(err)
	}

	return nil
}