Skip to content

Commit

Permalink
fix: refactor generic status rules /2
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
  • Loading branch information
ilya-lesikov committed Dec 18, 2023
1 parent 03ed5b2 commit 855ef9d
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 137 deletions.
51 changes: 26 additions & 25 deletions pkg/tracker/generic/ready_condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,48 @@ package generic
import (
"fmt"

"github.com/samber/lo"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

"github.com/werf/kubedog/pkg/tracker/indicators"
"github.com/werf/kubedog/pkg/utils"
)

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
}
246 changes: 135 additions & 111 deletions pkg/tracker/generic/resource_state_json_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
19 changes: 19 additions & 0 deletions pkg/tracker/indicators/indicators.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/trackers/rollout/multitrack/multitrack_display.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ func (mt *multitracker) displayGenericsStatusProgress() {
currentAndDesiredState = lastStatus.Indicator.FormatTableElem(lastPrintedStatusIndicator, indicators.FormatTableElemOptions{
ShowProgress: showProgress,
DisableWarningColors: disableWarningColors,
WithTargetValue: true,
WithTargetValue: false,
})
}
} else {
Expand Down

0 comments on commit 855ef9d

Please sign in to comment.