Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 31 additions & 24 deletions cmd/release-controller-api/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (c *Controller) findReleaseStreamTags(includeStableTags bool, tags ...strin
needed[tag.Name] = &ReleaseStreamTag{
Release: r,
Tag: tag,
Previous: findPreviousRelease(releaseTags[i+1:], r),
Previous: findPreviousRelease(releaseTags[i+1:], r, c.resolvePhase),
PreviousRelease: r,
Older: releaseTags[i+1:],
Stable: stable,
Expand Down Expand Up @@ -550,7 +550,7 @@ func (c *Controller) apiReleaseLatest(w http.ResponseWriter, req *http.Request)
Name: latest.Name,
PullSpec: resolveReleasePullSpec(r, latest.Name),
DownloadURL: downloadURL,
Phase: latest.Annotations[releasecontroller.ReleaseAnnotationPhase],
Phase: c.resolvePhase(*latest),
}

switch req.URL.Query().Get("format") {
Expand Down Expand Up @@ -627,7 +627,7 @@ func (c *Controller) apiReleaseTags(w http.ResponseWriter, req *http.Request) {
var tags []releasecontroller.APITag
for _, tag := range r.Tags {
downloadURL, _ := c.urlForArtifacts(tag.Name)
phase := tag.Annotations[releasecontroller.ReleaseAnnotationPhase]
phase := c.resolvePhase(*tag)
if len(filterPhase) > 0 && !slices.Contains(filterPhase, phase) {
continue
}
Expand Down Expand Up @@ -802,7 +802,7 @@ func (c *Controller) apiReleaseInfo(w http.ResponseWriter, req *http.Request) {

summary := releasecontroller.APIReleaseInfo{
Name: tagInfo.Tag,
Phase: tagInfo.Info.Tag.Annotations[releasecontroller.ReleaseAnnotationPhase],
Phase: c.resolvePhase(*tagInfo.Info.Tag),
Results: verificationJobs,
UpgradesTo: c.graph.UpgradesTo(tagInfo.Tag),
UpgradesFrom: c.graph.UpgradesFrom(tagInfo.Tag),
Expand Down Expand Up @@ -1412,9 +1412,12 @@ func (c *Controller) httpReleaseInfo(w http.ResponseWriter, req *http.Request) {
linkifyURLs(override.Reason))
}

switch tagInfo.Info.Tag.Annotations[releasecontroller.ReleaseAnnotationPhase] {
switch c.resolvePhase(*tagInfo.Info.Tag) {
case releasecontroller.ReleasePhaseFailed:
fmt.Fprintf(w, `<div class="alert alert-danger"><p>%s</p>`, template.HTMLEscapeString(tagInfo.Info.Tag.Annotations[releasecontroller.ReleaseAnnotationMessage]))
fmt.Fprintf(w, `<div class="alert alert-danger">`)
if payload := c.GetReleasePayload(tagInfo.Tag); payload != nil && payload.Spec.PayloadOverride.Reason != "" {
fmt.Fprintf(w, `<p>%s</p>`, template.HTMLEscapeString(payload.Spec.PayloadOverride.Reason))
}
if log := tagInfo.Info.Tag.Annotations[releasecontroller.ReleaseAnnotationLog]; len(log) > 0 {
fmt.Fprintf(w, `<pre class="small">%s</pre>`, template.HTMLEscapeString(log))
} else {
Expand Down Expand Up @@ -1657,19 +1660,21 @@ func (c *Controller) doesInconsistencyExist(tag string) bool {
}

func (c *Controller) tableLink(config *releasecontroller.ReleaseConfig, tag imagev1.TagReference) string {
if canLink(tag) {
if value, ok := tag.Annotations[releasecontroller.ReleaseAnnotationKeep]; ok {
return fmt.Sprintf(`<td class="text-monospace"><a title="%s" class="%s" href="/releasestream/%s/release/%s">%s <span>*</span></a></td>`, template.HTMLEscapeString(value), phaseAlert(tag), template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name))
phase := c.resolvePhase(tag)
alert := phaseAlert(phase)
if canLink(phase) {
if _, ok := tag.Annotations[releasecontroller.ReleaseAnnotationKeep]; ok {
return fmt.Sprintf(`<td class="text-monospace"><a title="%s" class="%s" href="/releasestream/%s/release/%s">%s <span>*</span></a></td>`, template.HTMLEscapeString("keep"), alert, template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name))
}
if strings.Contains(tag.Name, "nightly") && c.doesInconsistencyExist(tag.Name) {
return fmt.Sprintf(`<td class="text-monospace"><a class="%s" href="/releasestream/%s/release/%s">%s</a> <a href="/releasestream/%s/inconsistency/%s"><i title="Inconsistency detected! Click for more details" class="bi bi-exclamation-circle"></i></a></td>`, phaseAlert(tag), template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name))
return fmt.Sprintf(`<td class="text-monospace"><a class="%s" href="/releasestream/%s/release/%s">%s</a> <a href="/releasestream/%s/inconsistency/%s"><i title="Inconsistency detected! Click for more details" class="bi bi-exclamation-circle"></i></a></td>`, alert, template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name))
} else if config.As == releasecontroller.ReleaseConfigModeStable {
return fmt.Sprintf(`<td class="text-monospace"><a class="%s" style="padding-left:15px" href="/releasestream/%s/release/%s">%s</a></td>`, phaseAlert(tag), template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name))
return fmt.Sprintf(`<td class="text-monospace"><a class="%s" style="padding-left:15px" href="/releasestream/%s/release/%s">%s</a></td>`, alert, template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name))
} else {
return fmt.Sprintf(`<td class="text-monospace"><a class="%s" href="/releasestream/%s/release/%s">%s</a></td>`, phaseAlert(tag), template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name))
return fmt.Sprintf(`<td class="text-monospace"><a class="%s" href="/releasestream/%s/release/%s">%s</a></td>`, alert, template.HTMLEscapeString(config.Name), template.HTMLEscapeString(tag.Name), template.HTMLEscapeString(tag.Name))
}
}
return fmt.Sprintf(`<td class="text-monospace %s">%s</td>`, phaseAlert(tag), template.HTMLEscapeString(tag.Name))
return fmt.Sprintf(`<td class="text-monospace %s">%s</td>`, alert, template.HTMLEscapeString(tag.Name))
}

func (c *Controller) httpReleases(w http.ResponseWriter, req *http.Request) {
Expand Down Expand Up @@ -1756,7 +1761,6 @@ func (c *Controller) httpReleases(w http.ResponseWriter, req *http.Request) {
"versionGrouping": versionGrouping,
"streamNames": streamNames,
"phaseCell": c.phaseCell,
"phaseAlert": phaseAlert,
"alerts": renderAlerts,
"links": c.links,
"releaseJoin": releaseJoin,
Expand Down Expand Up @@ -1996,7 +2000,6 @@ func (c *Controller) httpReleaseStreamTable(w http.ResponseWriter, req *http.Req
"versionGrouping": versionGrouping,
"streamNames": streamNames,
"phaseCell": c.phaseCell,
"phaseAlert": phaseAlert,
"alerts": renderAlerts,
"links": c.links,
"releaseJoin": releaseJoin,
Expand Down Expand Up @@ -2144,7 +2147,6 @@ func (c *Controller) httpDashboardOverview(w http.ResponseWriter, req *http.Requ
},
"tableLink": c.tableLink,
"phaseCell": c.phaseCell,
"phaseAlert": phaseAlert,
"inc": func(i int) int { return i + 1 },
"upgradeJobs": upgradeJobs,
"releaseJoin": releaseJoin,
Expand Down Expand Up @@ -2186,7 +2188,11 @@ func (c *Controller) httpDashboardOverview(w http.ResponseWriter, req *http.Requ
delays = append(delays, fmt.Sprintf("no more than %d pending", r.Config.MaxUnreadyReleases))
}
}
if isReleaseFailing(s.Tags, r.Config.MaxUnreadyReleases) {
phases := make([]string, len(s.Tags))
for i, tag := range s.Tags {
phases[i] = c.resolvePhase(*tag)
}
if isReleaseFailing(phases, r.Config.MaxUnreadyReleases) {
s.Failing = true
}

Expand Down Expand Up @@ -2223,10 +2229,13 @@ func generateStreamMessage(r *ReleaseStream) string {
return fmt.Sprintf("%s%s", prefix, message)
}

func isReleaseFailing(tags []*imagev1.TagReference, maxUnready int) bool {
func isReleaseFailing(phases []string, maxUnready int) bool {
if maxUnready == 0 {
return false
}
unreadyCount := 0
for i := 0; unreadyCount < maxUnready && i < len(tags); i++ {
switch tags[i].Annotations[releasecontroller.ReleaseAnnotationPhase] {
for i := 0; unreadyCount < maxUnready && i < len(phases); i++ {
switch phases[i] {
case releasecontroller.ReleasePhaseReady:
continue
case releasecontroller.ReleasePhaseAccepted:
Expand Down Expand Up @@ -2422,10 +2431,8 @@ func (c *Controller) filteredStreams(phase string) ([]byte, error) {
if phase == "" {
tags = append(tags, tag.Name)
} else {
if annotation, ok := tag.Annotations[releasecontroller.ReleaseAnnotationPhase]; ok {
if annotation == phase {
tags = append(tags, tag.Name)
}
if c.resolvePhase(*tag) == phase {
tags = append(tags, tag.Name)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/release-controller-api/http_candidate.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func (c *Controller) findReleaseCandidates(upgradeSuccessPercent float64, releas
candidates := make([]*releasecontroller.ReleaseCandidate, 0)
releaseTags := releasecontroller.SortedReleaseTags(releaseStreamTagMap[stream].Release)
for _, tag := range releaseTags {
if tag.Annotations != nil && tag.Annotations[releasecontroller.ReleaseAnnotationPhase] == releasecontroller.ReleasePhaseAccepted &&
if c.resolvePhase(*tag) == releasecontroller.ReleasePhaseAccepted &&
tag.Annotations[releasecontroller.ReleaseAnnotationCreationTimestamp] != "" {
t, _ := time.Parse(time.RFC3339, tag.Annotations[releasecontroller.ReleaseAnnotationCreationTimestamp])
ts := t.Unix()
Expand Down
37 changes: 20 additions & 17 deletions cmd/release-controller-api/http_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,24 @@ func resolveReleasePullSpec(release *releasecontroller.Release, tagName string)
return releasecontroller.FindPublicImagePullSpec(release.Target, tagName)
}

func (c *Controller) resolvePhase(tag imagev1.TagReference) string {
payload := c.GetReleasePayload(tag.Name)
if payload == nil {
klog.Errorf("no ReleasePayload found for tag %q, phase is unknown", tag.Name)
return "Unknown"
}
return releasecontroller.GetReleasePhase(payload)
}

func (c *Controller) phaseCell(tag imagev1.TagReference) string {
phase := tag.Annotations[releasecontroller.ReleaseAnnotationPhase]
alert := phaseAlert(tag)
phase := c.resolvePhase(tag)
alert := phaseAlert(phase)

var title string
var overridden bool
if payload := c.GetReleasePayload(tag.Name); payload != nil && payload.Spec.PayloadOverride.Reason != "" {
title = payload.Spec.PayloadOverride.Reason
overridden = true
} else if phase == releasecontroller.ReleasePhaseRejected {
title = tag.Annotations[releasecontroller.ReleaseAnnotationMessage]
}

display := template.HTMLEscapeString(phase)
Expand All @@ -158,8 +165,7 @@ func (c *Controller) phaseCell(tag imagev1.TagReference) string {
return fmt.Sprintf("<td class=\"%s\">%s</td>", alert, display)
}

func phaseAlert(tag imagev1.TagReference) string {
phase := tag.Annotations[releasecontroller.ReleaseAnnotationPhase]
func phaseAlert(phase string) string {
switch phase {
case releasecontroller.ReleasePhasePending:
return ""
Expand Down Expand Up @@ -295,13 +301,8 @@ func upgradeJobs(upgrades *ReleaseUpgrades, index int, tagCreationTimestampStrin

return buf2.String()
}
func canLink(tag imagev1.TagReference) bool {
switch tag.Annotations[releasecontroller.ReleaseAnnotationPhase] {
case releasecontroller.ReleasePhasePending:
return false
default:
return true
}
func canLink(phase string) bool {
return phase != releasecontroller.ReleasePhasePending
}

func (c *Controller) GetReleasePayload(name string) *v1alpha1.ReleasePayload {
Expand Down Expand Up @@ -409,7 +410,8 @@ func (c *Controller) links(tag imagev1.TagReference, release *releasecontroller.
buf.WriteString("</span>")
continue
}
final := tag.Annotations[releasecontroller.ReleaseAnnotationPhase] == releasecontroller.ReleasePhaseRejected || tag.Annotations[releasecontroller.ReleaseAnnotationPhase] == releasecontroller.ReleasePhaseAccepted
phase := c.resolvePhase(tag)
final := phase == releasecontroller.ReleasePhaseRejected || phase == releasecontroller.ReleasePhaseAccepted
if !verificationJobs[key].Disabled && !final {
buf.WriteString(" <span title=\"Pending\">")
buf.WriteString(template.HTMLEscapeString(key))
Expand Down Expand Up @@ -487,7 +489,8 @@ func (c *Controller) renderVerifyLinks(w io.Writer, tag imagev1.TagReference, re
return
}
buf := &bytes.Buffer{}
final := tag.Annotations[releasecontroller.ReleaseAnnotationPhase] == releasecontroller.ReleasePhaseRejected || tag.Annotations[releasecontroller.ReleaseAnnotationPhase] == releasecontroller.ReleasePhaseAccepted
phase := c.resolvePhase(tag)
final := phase == releasecontroller.ReleasePhaseRejected || phase == releasecontroller.ReleasePhaseAccepted
if len(verificationJobs.BlockingJobs) > 0 {
buf.WriteString("<li>Blocking jobs<ul>")
buf.WriteString(c.renderVerificationJobsList(verificationJobs.BlockingJobs, release, tag, final))
Expand Down Expand Up @@ -667,7 +670,7 @@ func hasPublishTag(config *releasecontroller.ReleaseConfig) (string, bool) {
return "", false
}

func findPreviousRelease(older []*imagev1.TagReference, release *releasecontroller.Release) *imagev1.TagReference {
func findPreviousRelease(older []*imagev1.TagReference, release *releasecontroller.Release, phaseOf func(imagev1.TagReference) string) *imagev1.TagReference {
if len(older) == 0 {
return nil
}
Expand All @@ -682,7 +685,7 @@ func findPreviousRelease(older []*imagev1.TagReference, release *releasecontroll
}
}
for _, old := range older {
if old.Annotations[releasecontroller.ReleaseAnnotationPhase] == releasecontroller.ReleasePhaseAccepted {
if phaseOf(*old) == releasecontroller.ReleasePhaseAccepted {
return old
}
}
Expand Down
Loading