// tagNeedsImport is true if the observed tag generation for this tag is older than the // specified tag generation (if no tag generation is specified, the controller does not // need to import this tag). func tagNeedsImport(stream *api.ImageStream, tag string, tagRef api.TagReference, importWhenGenerationNil bool) bool { if !tagImportable(tagRef) { return false } if tagRef.Generation == nil { return importWhenGenerationNil } return *tagRef.Generation > api.LatestObservedTagGeneration(stream, tag) }
func formatImageStreamTags(out *tabwriter.Writer, stream *imageapi.ImageStream) { if len(stream.Status.Tags) == 0 && len(stream.Spec.Tags) == 0 { fmt.Fprintf(out, "Tags:\t<none>\n") return } now := timeNowFn() images := make(map[string]string) for tag, tags := range stream.Status.Tags { for _, item := range tags.Items { switch { case len(item.Image) > 0: if _, ok := images[item.Image]; !ok { images[item.Image] = tag } case len(item.DockerImageReference) > 0: if _, ok := images[item.DockerImageReference]; !ok { images[item.Image] = item.DockerImageReference } } } } sortedTags := []string{} for k := range stream.Status.Tags { sortedTags = append(sortedTags, k) } var localReferences sets.String var referentialTags map[string]sets.String for k := range stream.Spec.Tags { if target, _, ok, multiple := imageapi.FollowTagReference(stream, k); ok && multiple { if referentialTags == nil { referentialTags = make(map[string]sets.String) } if localReferences == nil { localReferences = sets.NewString() } localReferences.Insert(k) v := referentialTags[target] if v == nil { v = sets.NewString() referentialTags[target] = v } v.Insert(k) } if _, ok := stream.Status.Tags[k]; !ok { sortedTags = append(sortedTags, k) } } fmt.Fprintf(out, "Unique Images:\t%d\nTags:\t%d\n\n", len(images), len(sortedTags)) first := true imageapi.PrioritizeTags(sortedTags) for _, tag := range sortedTags { if localReferences.Has(tag) { continue } if first { first = false } else { fmt.Fprintf(out, "\n") } taglist, _ := stream.Status.Tags[tag] tagRef, hasSpecTag := stream.Spec.Tags[tag] scheduled := false insecure := false importing := false var name string if hasSpecTag && tagRef.From != nil { if len(tagRef.From.Namespace) > 0 && tagRef.From.Namespace != stream.Namespace { name = fmt.Sprintf("%s/%s", tagRef.From.Namespace, tagRef.From.Name) } else { name = tagRef.From.Name } scheduled, insecure = tagRef.ImportPolicy.Scheduled, tagRef.ImportPolicy.Insecure gen := imageapi.LatestObservedTagGeneration(stream, tag) importing = !tagRef.Reference && tagRef.Generation != nil && *tagRef.Generation != gen } // updates whenever tag :5.2 is changed // :latest (30 minutes ago) -> 102.205.358.453/foo/bar@sha256:abcde734 // error: last import failed 20 minutes ago // updates automatically from index.docker.io/mysql/bar // will use insecure HTTPS connections or HTTP // // MySQL 5.5 // --------- // Describes a system for updating based on practical changes to a database system // with some other data involved // // 20 minutes ago <import failed> // Failed to locate the server in time // 30 minutes ago 102.205.358.453/foo/bar@sha256:abcdef // 1 hour ago 102.205.358.453/foo/bar@sha256:bfedfc //var shortErrors []string /* var internalReference *imageapi.DockerImageReference if value := stream.Status.DockerImageRepository; len(value) > 0 { ref, err := imageapi.ParseDockerImageReference(value) if err != nil { internalReference = &ref } } */ if referentialTags[tag].Len() > 0 { references := referentialTags[tag].List() imageapi.PrioritizeTags(references) fmt.Fprintf(out, "%s (%s)\n", tag, strings.Join(references, ", ")) } else { fmt.Fprintf(out, "%s\n", tag) } switch { case !hasSpecTag || tagRef.From == nil: fmt.Fprintf(out, " pushed image\n") case tagRef.From.Kind == "ImageStreamTag": switch { case tagRef.Reference: fmt.Fprintf(out, " reference to %s\n", name) case scheduled: fmt.Fprintf(out, " updates automatically from %s\n", name) default: fmt.Fprintf(out, " tagged from %s\n", name) } case tagRef.From.Kind == "DockerImage": switch { case tagRef.Reference: fmt.Fprintf(out, " reference to registry %s\n", name) case scheduled: fmt.Fprintf(out, " updates automatically from registry %s\n", name) default: fmt.Fprintf(out, " tagged from %s\n", name) } case tagRef.From.Kind == "ImageStreamImage": switch { case tagRef.Reference: fmt.Fprintf(out, " reference to image %s\n", name) default: fmt.Fprintf(out, " tagged from %s\n", name) } default: switch { case tagRef.Reference: fmt.Fprintf(out, " reference to %s %s\n", tagRef.From.Kind, name) default: fmt.Fprintf(out, " updates from %s %s\n", tagRef.From.Kind, name) } } if insecure { fmt.Fprintf(out, " will use insecure HTTPS or HTTP connections\n") } fmt.Fprintln(out) extraOutput := false if d := tagRef.Annotations["description"]; len(d) > 0 { fmt.Fprintf(out, " %s\n", d) extraOutput = true } if t := tagRef.Annotations["tags"]; len(t) > 0 { fmt.Fprintf(out, " Tags: %s\n", strings.Join(strings.Split(t, ","), ", ")) extraOutput = true } if t := tagRef.Annotations["supports"]; len(t) > 0 { fmt.Fprintf(out, " Supports: %s\n", strings.Join(strings.Split(t, ","), ", ")) extraOutput = true } if t := tagRef.Annotations["sampleRepo"]; len(t) > 0 { fmt.Fprintf(out, " Example Repo: %s\n", t) extraOutput = true } if extraOutput { fmt.Fprintln(out) } if importing { fmt.Fprintf(out, " ~ importing latest image ...\n") } for i := range taglist.Conditions { condition := &taglist.Conditions[i] switch condition.Type { case imageapi.ImportSuccess: if condition.Status == api.ConditionFalse { d := now.Sub(condition.LastTransitionTime.Time) fmt.Fprintf(out, " ! error: Import failed (%s): %s\n %s ago\n", condition.Reason, condition.Message, units.HumanDuration(d)) } } } if len(taglist.Items) == 0 { continue } for i, event := range taglist.Items { d := now.Sub(event.Created.Time) if i == 0 { fmt.Fprintf(out, " * %s\n", event.DockerImageReference) } else { fmt.Fprintf(out, " %s\n", event.DockerImageReference) } ref, err := imageapi.ParseDockerImageReference(event.DockerImageReference) id := event.Image if len(id) > 0 && err == nil && ref.ID != id { fmt.Fprintf(out, " %s ago\t%s\n", units.HumanDuration(d), id) } else { fmt.Fprintf(out, " %s ago\n", units.HumanDuration(d)) } } } }