From 7560fd25ceb8ccff52811da169c095cfdad00ab3 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 17:23:01 +0300 Subject: [PATCH 01/10] fix: refactor generic ruleset generation Signed-off-by: Ilya Lesikov --- .../generic/resource_state_json_paths.go | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index eb19912..d823ab8 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -21,14 +21,14 @@ type ResourceStatusJSONPath struct { func initResourceStatusJSONPathsByPriority() { casers := []cases.Caser{cases.Lower(language.Und), cases.Title(language.Und)} - for _, actionPackByPriority := range [][]string{ + for _, actionGroupsByPriority := range [][]string{ {"ready", "success", "succeeded"}, {"complete", "completed", "finished"}, {"available"}, {"running"}, {"started", "initialized", "approved"}, } { - for _, action := range actionPackByPriority { + for _, action := range actionGroupsByPriority { for _, caser := range casers { ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: fmt.Sprintf(`$.status.conditions[?(@.type==%q)].status`, caser.String(action)), @@ -36,11 +36,7 @@ func initResourceStatusJSONPathsByPriority() { ReadyValue: caser.String("true"), PendingValues: []string{caser.String("false"), caser.String("unknown")}, }) - } - } - for _, action := range actionPackByPriority { - for _, caser := range casers { ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.phase`, HumanPath: "status.phase", @@ -48,6 +44,7 @@ func initResourceStatusJSONPathsByPriority() { PendingValues: []string{caser.String("pending"), caser.String("unknown")}, FailedValue: caser.String("failed"), }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.currentPhase`, HumanPath: "status.currentPhase", @@ -55,11 +52,7 @@ func initResourceStatusJSONPathsByPriority() { PendingValues: []string{caser.String("pending"), caser.String("unknown")}, FailedValue: caser.String("failed"), }) - } - } - for _, action := range actionPackByPriority { - for _, caser := range casers { ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.state`, HumanPath: "status.state", @@ -67,6 +60,7 @@ func initResourceStatusJSONPathsByPriority() { PendingValues: []string{caser.String("pending"), caser.String("unknown")}, FailedValue: caser.String("failed"), }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.currentState`, HumanPath: "status.currentState", @@ -74,11 +68,7 @@ func initResourceStatusJSONPathsByPriority() { PendingValues: []string{caser.String("pending"), caser.String("unknown")}, FailedValue: caser.String("failed"), }) - } - } - for _, action := range actionPackByPriority { - for _, caser := range casers { ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.health`, HumanPath: "status.health", @@ -86,6 +76,7 @@ func initResourceStatusJSONPathsByPriority() { PendingValues: []string{caser.String("pending"), caser.String("unknown")}, FailedValue: caser.String("failed"), }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.currentHealth`, HumanPath: "status.currentHealth", @@ -98,32 +89,33 @@ func initResourceStatusJSONPathsByPriority() { } for _, caser := range casers { + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ + JSONPath: `$.status.state`, + HumanPath: "status.state", + ReadyValue: caser.String("valid"), + PendingValues: []string{caser.String("invalid"), caser.String("unknown")}, + }) + + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ + JSONPath: `$.status.currentState`, + HumanPath: "status.currentState", + ReadyValue: caser.String("valid"), + PendingValues: []string{caser.String("invalid"), caser.String("unknown")}, + }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.health`, HumanPath: "status.health", ReadyValue: caser.String("green"), PendingValues: []string{caser.String("yellow"), caser.String("red"), caser.String("unknown")}, }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.currentHealth`, HumanPath: "status.currentHealth", ReadyValue: caser.String("green"), PendingValues: []string{caser.String("yellow"), caser.String("red"), caser.String("unknown")}, }) - } - for _, caser := range casers { - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.state`, - HumanPath: "status.state", - ReadyValue: caser.String("valid"), - PendingValues: []string{caser.String("invalid"), caser.String("unknown")}, - }) - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentState`, - HumanPath: "status.currentState", - ReadyValue: caser.String("valid"), - PendingValues: []string{caser.String("invalid"), caser.String("unknown")}, - }) } } From 03ed5b2ddf87a2474fba92502f741b2ac870367b Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 17:28:51 +0300 Subject: [PATCH 02/10] feat: track status.(current)status in generic tracker Signed-off-by: Ilya Lesikov --- pkg/tracker/generic/resource_state_json_paths.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index d823ab8..349bf82 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -69,6 +69,22 @@ func initResourceStatusJSONPathsByPriority() { FailedValue: caser.String("failed"), }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ + JSONPath: `$.status.status`, + HumanPath: "status.status", + ReadyValue: caser.String(action), + PendingValues: []string{caser.String("pending"), caser.String("unknown")}, + FailedValue: caser.String("failed"), + }) + + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ + JSONPath: `$.status.currentStatus`, + HumanPath: "status.currentStatus", + ReadyValue: caser.String(action), + PendingValues: []string{caser.String("pending"), caser.String("unknown")}, + FailedValue: caser.String("failed"), + }) + ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ JSONPath: `$.status.health`, HumanPath: "status.health", From 855ef9dcf1810ad18929825a8102920a25eba6d0 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 18:55:03 +0300 Subject: [PATCH 03/10] fix: refactor generic status rules /2 Signed-off-by: Ilya Lesikov --- pkg/tracker/generic/ready_condition.go | 51 ++-- .../generic/resource_state_json_paths.go | 246 ++++++++++-------- pkg/tracker/indicators/indicators.go | 19 ++ .../rollout/multitrack/multitrack_display.go | 2 +- 4 files changed, 181 insertions(+), 137 deletions(-) diff --git a/pkg/tracker/generic/ready_condition.go b/pkg/tracker/generic/ready_condition.go index ff6d596..933b228 100644 --- a/pkg/tracker/generic/ready_condition.go +++ b/pkg/tracker/generic/ready_condition.go @@ -3,6 +3,7 @@ package generic import ( "fmt" + "github.com/samber/lo" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/werf/kubedog/pkg/tracker/indicators" @@ -10,40 +11,40 @@ import ( ) func NewResourceStatusIndicator(object *unstructured.Unstructured) (indicator *indicators.StringEqualConditionIndicator, humanJSONPath string, err error) { - var matchedJSONPath *ResourceStatusJSONPath - for _, readyJSONPath := range ResourceStatusJSONPathsByPriority { - result, found, err := utils.JSONPath(readyJSONPath.JSONPath, object.UnstructuredContent()) - if err != nil { - return nil, "", fmt.Errorf("jsonpath error: %w", err) - } else if !found { + groupKind := object.GroupVersionKind().GroupKind() + + var matchedCondition *ResourceStatusJSONPathCondition + for _, condition := range ResourceStatusJSONPathConditions { + if condition.GroupKind != nil && *condition.GroupKind != groupKind { continue } - var resultIsValidValue bool - for _, validValue := range append(readyJSONPath.PendingValues, readyJSONPath.ReadyValue, readyJSONPath.FailedValue) { - if result == validValue { - resultIsValidValue = true - break - } - } - if !resultIsValidValue { + currentValue, found, err := utils.JSONPath(condition.JSONPath, object.UnstructuredContent()) + if err != nil { + return nil, "", fmt.Errorf("jsonpath error: %w", err) + } else if !found { continue } - path := readyJSONPath - matchedJSONPath = &path - matchedJSONPath.CurrentValue = result + knownValues := append(condition.ReadyValues, + append(condition.PendingValues, condition.FailedValues...)..., + ) - break + if lo.Contains(knownValues, currentValue) { + matchedCondition = condition + matchedCondition.CurrentValue = currentValue + break + } } - - if matchedJSONPath == nil { + if matchedCondition == nil { return nil, "", nil } - return &indicators.StringEqualConditionIndicator{ - Value: matchedJSONPath.CurrentValue, - TargetValue: matchedJSONPath.ReadyValue, - FailedValue: matchedJSONPath.FailedValue, - }, matchedJSONPath.HumanPath, nil + indicator = &indicators.StringEqualConditionIndicator{ + Value: matchedCondition.CurrentValue, + } + indicator.SetReady(lo.Contains(matchedCondition.ReadyValues, matchedCondition.CurrentValue)) + indicator.SetFailed(lo.Contains(matchedCondition.FailedValues, matchedCondition.CurrentValue)) + + return indicator, matchedCondition.HumanPath, nil } diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index 349bf82..881fa76 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -5,133 +5,157 @@ import ( "golang.org/x/text/cases" "golang.org/x/text/language" + "k8s.io/apimachinery/pkg/runtime/schema" ) -var ResourceStatusJSONPathsByPriority []ResourceStatusJSONPath +var ResourceStatusJSONPathConditions []*ResourceStatusJSONPathCondition -type ResourceStatusJSONPath struct { +type ResourceStatusJSONPathCondition struct { + GroupKind *schema.GroupKind JSONPath string HumanPath string - ReadyValue string - FailedValue string + ReadyValues []string PendingValues []string - CurrentValue string + FailedValues []string + + CurrentValue string } func initResourceStatusJSONPathsByPriority() { - casers := []cases.Caser{cases.Lower(language.Und), cases.Title(language.Und)} + genericReadyValuesByPriority := []string{ + "ready", + "success", + "succeeded", + "complete", + "completed", + "finished", + "available", + "running", + "started", + "initialized", + "approved", + } - for _, actionGroupsByPriority := range [][]string{ - {"ready", "success", "succeeded"}, - {"complete", "completed", "finished"}, - {"available"}, - {"running"}, - {"started", "initialized", "approved"}, - } { - for _, action := range actionGroupsByPriority { - for _, caser := range casers { - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: fmt.Sprintf(`$.status.conditions[?(@.type==%q)].status`, caser.String(action)), - HumanPath: fmt.Sprintf("status.conditions[type=%s].status", caser.String(action)), - ReadyValue: caser.String("true"), - PendingValues: []string{caser.String("false"), caser.String("unknown")}, - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.phase`, - HumanPath: "status.phase", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentPhase`, - HumanPath: "status.currentPhase", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.state`, - HumanPath: "status.state", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentState`, - HumanPath: "status.currentState", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.status`, - HumanPath: "status.status", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentStatus`, - HumanPath: "status.currentStatus", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.health`, - HumanPath: "status.health", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentHealth`, - HumanPath: "status.currentHealth", - ReadyValue: caser.String(action), - PendingValues: []string{caser.String("pending"), caser.String("unknown")}, - FailedValue: caser.String("failed"), - }) - } - } + genericPendingValuesByPriority := []string{ + "pending", + "unknown", } - for _, caser := range casers { - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.state`, - HumanPath: "status.state", - ReadyValue: caser.String("valid"), - PendingValues: []string{caser.String("invalid"), caser.String("unknown")}, - }) + genericFailedValuesByPriority := []string{ + "failed", + } - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentState`, - HumanPath: "status.currentState", - ReadyValue: caser.String("valid"), - PendingValues: []string{caser.String("invalid"), caser.String("unknown")}, + for _, readyValue := range genericReadyValuesByPriority { + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: fmt.Sprintf(`$.status.conditions[?(@.type==%q)].status`, casify(readyValue)[0]), + HumanPath: fmt.Sprintf("status.conditions[type=%s].status", casify(readyValue)[0]), + ReadyValues: casify("true"), + PendingValues: casify("false", "unknown"), }) + } - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.health`, - HumanPath: "status.health", - ReadyValue: caser.String("green"), - PendingValues: []string{caser.String("yellow"), caser.String("red"), caser.String("unknown")}, - }) + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.phase`, + HumanPath: "status.phase", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.currentPhase`, + HumanPath: "status.currentPhase", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.state`, + HumanPath: "status.state", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.currentState`, + HumanPath: "status.currentState", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.status`, + HumanPath: "status.status", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.currentStatus`, + HumanPath: "status.currentStatus", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.health`, + HumanPath: "status.health", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.currentHealth`, + HumanPath: "status.currentHealth", + ReadyValues: casify(genericReadyValuesByPriority...), + PendingValues: casify(genericPendingValuesByPriority...), + FailedValues: casify(genericFailedValuesByPriority...), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.state`, + HumanPath: "status.state", + ReadyValues: casify("valid"), + PendingValues: casify("invalid", "unknown"), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.currentState`, + HumanPath: "status.currentState", + ReadyValues: casify("valid"), + PendingValues: casify("invalid", "unknown"), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.health`, + HumanPath: "status.health", + ReadyValues: casify("green"), + PendingValues: casify("yellow", "red", "unknown"), + }) + + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + JSONPath: `$.status.currentHealth`, + HumanPath: "status.currentHealth", + ReadyValues: casify("green"), + PendingValues: casify("yellow", "red", "unknown"), + }) +} - ResourceStatusJSONPathsByPriority = append(ResourceStatusJSONPathsByPriority, ResourceStatusJSONPath{ - JSONPath: `$.status.currentHealth`, - HumanPath: "status.currentHealth", - ReadyValue: caser.String("green"), - PendingValues: []string{caser.String("yellow"), caser.String("red"), caser.String("unknown")}, - }) +func casify(in ...string) []string { + var result []string + casers := []cases.Caser{cases.Lower(language.Und), cases.Title(language.Und)} + for _, value := range in { + for _, caser := range casers { + result = append(result, caser.String(value)) + } } + + return result } diff --git a/pkg/tracker/indicators/indicators.go b/pkg/tracker/indicators/indicators.go index a936512..fdf352e 100644 --- a/pkg/tracker/indicators/indicators.go +++ b/pkg/tracker/indicators/indicators.go @@ -25,17 +25,36 @@ type StringEqualConditionIndicator struct { Value string TargetValue string FailedValue string + + forceReady *bool + forceFailed *bool } func (indicator *StringEqualConditionIndicator) IsProgressing(prevIndicator *StringEqualConditionIndicator) bool { return (prevIndicator != nil) && (indicator.Value != prevIndicator.Value) } +func (indicator *StringEqualConditionIndicator) SetReady(ready bool) { + indicator.forceReady = &ready +} + func (indicator *StringEqualConditionIndicator) IsReady() bool { + if indicator.forceReady != nil { + return *indicator.forceReady + } + return indicator.Value == indicator.TargetValue } +func (indicator *StringEqualConditionIndicator) SetFailed(failed bool) { + indicator.forceFailed = &failed +} + func (indicator *StringEqualConditionIndicator) IsFailed() bool { + if indicator.forceFailed != nil { + return *indicator.forceFailed + } + return indicator.Value == indicator.FailedValue } diff --git a/pkg/trackers/rollout/multitrack/multitrack_display.go b/pkg/trackers/rollout/multitrack/multitrack_display.go index d96a072..9d2d902 100644 --- a/pkg/trackers/rollout/multitrack/multitrack_display.go +++ b/pkg/trackers/rollout/multitrack/multitrack_display.go @@ -661,7 +661,7 @@ func (mt *multitracker) displayGenericsStatusProgress() { currentAndDesiredState = lastStatus.Indicator.FormatTableElem(lastPrintedStatusIndicator, indicators.FormatTableElemOptions{ ShowProgress: showProgress, DisableWarningColors: disableWarningColors, - WithTargetValue: true, + WithTargetValue: false, }) } } else { From 869b5fee19a6cff6f31204e85fae73d865fa0708 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 19:02:55 +0300 Subject: [PATCH 04/10] fix: preserve original case for values when building generic status ruleset Signed-off-by: Ilya Lesikov --- pkg/tracker/generic/resource_state_json_paths.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index 881fa76..80853c9 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -3,6 +3,7 @@ package generic import ( "fmt" + "github.com/samber/lo" "golang.org/x/text/cases" "golang.org/x/text/language" "k8s.io/apimachinery/pkg/runtime/schema" @@ -152,7 +153,15 @@ func casify(in ...string) []string { casers := []cases.Caser{cases.Lower(language.Und), cases.Title(language.Und)} for _, value := range in { + result = append(result, value) + for _, caser := range casers { + cased := caser.String(value) + + if lo.Contains(result, cased) { + continue + } + result = append(result, caser.String(value)) } } From a8eeb674f64492a02d9673c8bcb5178617679d90 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 19:10:19 +0300 Subject: [PATCH 05/10] fix: refactor generic status rules /3 Signed-off-by: Ilya Lesikov --- .../generic/resource_state_json_paths.go | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index 80853c9..e489061 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -23,7 +23,15 @@ type ResourceStatusJSONPathCondition struct { } func initResourceStatusJSONPathsByPriority() { - genericReadyValuesByPriority := []string{ + buildResourceSpecificConditions() + buildUniversalConditions() + buildLowPriorityConditions() +} + +func buildResourceSpecificConditions() {} + +func buildUniversalConditions() { + readyValuesByPriority := []string{ "ready", "success", "succeeded", @@ -37,16 +45,16 @@ func initResourceStatusJSONPathsByPriority() { "approved", } - genericPendingValuesByPriority := []string{ + pendingValuesByPriority := []string{ "pending", "unknown", } - genericFailedValuesByPriority := []string{ + failedValuesByPriority := []string{ "failed", } - for _, readyValue := range genericReadyValuesByPriority { + for _, readyValue := range readyValuesByPriority { ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: fmt.Sprintf(`$.status.conditions[?(@.type==%q)].status`, casify(readyValue)[0]), HumanPath: fmt.Sprintf("status.conditions[type=%s].status", casify(readyValue)[0]), @@ -58,67 +66,69 @@ func initResourceStatusJSONPathsByPriority() { ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.phase`, HumanPath: "status.phase", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.currentPhase`, HumanPath: "status.currentPhase", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.state`, HumanPath: "status.state", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.currentState`, HumanPath: "status.currentState", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.status`, HumanPath: "status.status", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.currentStatus`, HumanPath: "status.currentStatus", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.health`, HumanPath: "status.health", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.currentHealth`, HumanPath: "status.currentHealth", - ReadyValues: casify(genericReadyValuesByPriority...), - PendingValues: casify(genericPendingValuesByPriority...), - FailedValues: casify(genericFailedValuesByPriority...), + ReadyValues: casify(readyValuesByPriority...), + PendingValues: casify(pendingValuesByPriority...), + FailedValues: casify(failedValuesByPriority...), }) +} +func buildLowPriorityConditions() { ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ JSONPath: `$.status.state`, HumanPath: "status.state", From d7d86482772583645f6022d16956260b9b034c75 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 19:11:36 +0300 Subject: [PATCH 06/10] feat: add acid.zalan.do/postrgresql generic tracker rule Signed-off-by: Ilya Lesikov --- pkg/tracker/generic/resource_state_json_paths.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index e489061..de496ea 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -28,7 +28,16 @@ func initResourceStatusJSONPathsByPriority() { buildLowPriorityConditions() } -func buildResourceSpecificConditions() {} +func buildResourceSpecificConditions() { + ResourceStatusJSONPathConditions = append(ResourceStatusJSONPathConditions, &ResourceStatusJSONPathCondition{ + GroupKind: &schema.GroupKind{Group: "acid.zalan.do", Kind: "postgresql"}, + JSONPath: `$.status.PostgresClusterStatus`, + HumanPath: "status.PostgresClusterStatus", + ReadyValues: casify("Running"), + PendingValues: casify("Creating", "Updating"), + FailedValues: casify("CreateFailed", "UpdateFailed", "SyncFailed"), + }) +} func buildUniversalConditions() { readyValuesByPriority := []string{ From 7373f0d5b44e9f42d1988334238131ff4d914007 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 19:15:38 +0300 Subject: [PATCH 07/10] chore: fix lint Signed-off-by: Ilya Lesikov --- pkg/tracker/generic/ready_condition.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/tracker/generic/ready_condition.go b/pkg/tracker/generic/ready_condition.go index 933b228..02580ee 100644 --- a/pkg/tracker/generic/ready_condition.go +++ b/pkg/tracker/generic/ready_condition.go @@ -26,9 +26,7 @@ func NewResourceStatusIndicator(object *unstructured.Unstructured) (indicator *i continue } - knownValues := append(condition.ReadyValues, - append(condition.PendingValues, condition.FailedValues...)..., - ) + knownValues := lo.Union(condition.ReadyValues, condition.PendingValues, condition.FailedValues) if lo.Contains(knownValues, currentValue) { matchedCondition = condition From 8c44e5d6ff6ff3a0693d1fcbc4d748ea3382a5cf Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 20:46:17 +0300 Subject: [PATCH 08/10] feat: add a lot of new generic conditions for generic tracker Signed-off-by: Ilya Lesikov --- .../generic/resource_state_json_paths.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index de496ea..732faf4 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -47,20 +47,43 @@ func buildUniversalConditions() { "complete", "completed", "finished", + "finalized", + "done", "available", "running", + "ok", + "active", + "live", + "healthy", "started", "initialized", "approved", } pendingValuesByPriority := []string{ + "creating", + "updating", + "waiting", "pending", + "finishing", + "starting", + "readying", + "progressing", + "initializing", + "approving", "unknown", } failedValuesByPriority := []string{ + "failure", "failed", + "abort", + "aborted", + "terminated", + "error", + "errored", + "rejection", + "rejected", } for _, readyValue := range readyValuesByPriority { From f7bed28512312f7f9bdde4d8f3d957a873183bb8 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 21:14:47 +0300 Subject: [PATCH 09/10] fix: condition column name Signed-off-by: Ilya Lesikov --- pkg/trackers/rollout/multitrack/multitrack_display.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/trackers/rollout/multitrack/multitrack_display.go b/pkg/trackers/rollout/multitrack/multitrack_display.go index 9d2d902..dd9045d 100644 --- a/pkg/trackers/rollout/multitrack/multitrack_display.go +++ b/pkg/trackers/rollout/multitrack/multitrack_display.go @@ -612,7 +612,7 @@ func (mt *multitracker) displayDeploymentsStatusProgress() { func (mt *multitracker) displayGenericsStatusProgress() { t := utils.NewTable([]float64{.43, .14, .43}...) t.SetWidth(logboek.Context(context.Background()).Streams().ContentWidth() - 1) - t.Header("RESOURCE", "NAMESPACE", "CONDITION: CURRENT (DESIRED)") + t.Header("RESOURCE", "NAMESPACE", "WATCHING FOR FIELD") var tableChangesCount int for _, resource := range mt.GenericResources { From 969cad97bf11a1c73211c41b7133cb057334a0a5 Mon Sep 17 00:00:00 2001 From: Ilya Lesikov Date: Mon, 18 Dec 2023 21:30:15 +0300 Subject: [PATCH 10/10] feat: add more status conditions, add extra case options for conditions Signed-off-by: Ilya Lesikov --- go.mod | 3 +- go.sum | 2 ++ .../generic/resource_state_json_paths.go | 33 +++++++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 4c79d60..583b03d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d + github.com/chanced/caps v1.0.1 github.com/dominikbraun/graph v0.23.0 github.com/fluxcd/flagger v1.29.0 github.com/gookit/color v1.5.2 @@ -11,7 +12,6 @@ require ( github.com/spf13/cobra v1.6.1 github.com/werf/logboek v0.5.5 golang.org/x/crypto v0.7.0 - golang.org/x/text v0.8.0 k8s.io/api v0.26.2 k8s.io/apimachinery v0.26.2 k8s.io/cli-runtime v0.26.2 @@ -60,6 +60,7 @@ require ( golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 3dbe0aa..e59ad6c 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/avelino/slugify v0.0.0-20180501145920-855f152bd774/go.mod h1:5wi5YYOp github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chanced/caps v1.0.1 h1:B9LhH2mmAcNjn1argkddu9fRdU+VMrfomRoeXL1DYhg= +github.com/chanced/caps v1.0.1/go.mod h1:SJhRzeYLKJ3OmzyQXhdZ7Etj7lqqWoPtQ1zcSJRtQjs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= diff --git a/pkg/tracker/generic/resource_state_json_paths.go b/pkg/tracker/generic/resource_state_json_paths.go index 732faf4..83b32de 100644 --- a/pkg/tracker/generic/resource_state_json_paths.go +++ b/pkg/tracker/generic/resource_state_json_paths.go @@ -2,10 +2,10 @@ package generic import ( "fmt" + "strings" + "github.com/chanced/caps" "github.com/samber/lo" - "golang.org/x/text/cases" - "golang.org/x/text/language" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -64,11 +64,14 @@ func buildUniversalConditions() { "creating", "updating", "waiting", + "awaiting", "pending", "finishing", "starting", "readying", + "in progress", "progressing", + "initialization", "initializing", "approving", "unknown", @@ -193,20 +196,24 @@ func buildLowPriorityConditions() { func casify(in ...string) []string { var result []string - casers := []cases.Caser{cases.Lower(language.Und), cases.Title(language.Und)} for _, value := range in { result = append(result, value) - - for _, caser := range casers { - cased := caser.String(value) - - if lo.Contains(result, cased) { - continue - } - - result = append(result, caser.String(value)) - } + result = append(result, strings.ReplaceAll(value, " ", "")) + result = append(result, caps.ToUpper(strings.ReplaceAll(value, " ", ""))) + result = append(result, caps.ToCamel(value)) + result = append(result, caps.ToKebab(value)) + result = append(result, caps.ToDotNotation(value)) + result = append(result, caps.ToSnake(value)) + result = append(result, caps.ToTitle(value)) + result = append(result, caps.ToUpper(value)) + result = append(result, caps.ToLower(value)) + result = append(result, caps.ToLowerCamel(value)) + result = append(result, caps.ToScreamingDotNotation(value)) + result = append(result, caps.ToScreamingKebab(value)) + result = append(result, caps.ToScreamingSnake(value)) } + result = lo.Uniq(result) + return result }