forked from rancher/wrangler
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5eddba9
commit 8321517
Showing
3 changed files
with
338 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package summary | ||
|
||
import ( | ||
"encoding/json" | ||
|
||
"github.com/rancher/wrangler/pkg/data" | ||
) | ||
|
||
func getRawConditions(obj data.Object) []data.Object { | ||
statusAnn := obj.String("metadata", "annotations", "cattle.io/status") | ||
if statusAnn != "" { | ||
status := data.Object{} | ||
if err := json.Unmarshal([]byte(statusAnn), &status); err == nil { | ||
return append(obj.Slice("status", "conditions"), status.Slice("conditions")...) | ||
} | ||
} | ||
return obj.Slice("status", "conditions") | ||
} | ||
|
||
func getConditions(obj data.Object) (result []Condition) { | ||
for _, condition := range getRawConditions(obj) { | ||
result = append(result, Condition{d: condition}) | ||
} | ||
return | ||
} | ||
|
||
type Condition struct { | ||
d data.Object | ||
} | ||
|
||
func (c Condition) Type() string { | ||
return c.d.String("type") | ||
} | ||
|
||
func (c Condition) Status() string { | ||
return c.d.String("status") | ||
} | ||
|
||
func (c Condition) Reason() string { | ||
return c.d.String("reason") | ||
} | ||
|
||
func (c Condition) Message() string { | ||
return c.d.String("message") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
package summary | ||
|
||
import ( | ||
"strings" | ||
"time" | ||
|
||
"github.com/rancher/wrangler/pkg/data" | ||
"github.com/rancher/wrangler/pkg/data/convert" | ||
"github.com/rancher/wrangler/pkg/kv" | ||
) | ||
|
||
var ( | ||
// True == | ||
// False == error | ||
// Unknown == transitioning | ||
TransitioningUnknown = map[string]string{ | ||
"Active": "activating", | ||
"AddonDeploy": "provisioning", | ||
"AgentDeployed": "provisioning", | ||
"BackingNamespaceCreated": "configuring", | ||
"Built": "building", | ||
"CertsGenerated": "provisioning", | ||
"ConfigOK": "configuring", | ||
"Created": "creating", | ||
"CreatorMadeOwner": "configuring", | ||
"DefaultNamespaceAssigned": "configuring", | ||
"DefaultNetworkPolicyCreated": "configuring", | ||
"DefaultProjectCreated": "configuring", | ||
"DockerProvisioned": "provisioning", | ||
"Deployed": "deploying", | ||
"Drained": "draining", | ||
"Downloaded": "downloading", | ||
"etcd": "provisioning", | ||
"Inactive": "deactivating", | ||
"Initialized": "initializing", | ||
"Installed": "installing", | ||
"NodesCreated": "provisioning", | ||
"Pending": "pending", | ||
"PodScheduled": "scheduling", | ||
"Provisioned": "provisioning", | ||
"Refreshed": "refreshed", | ||
"Registered": "registering", | ||
"Removed": "removing", | ||
"Saved": "saving", | ||
"Updated": "updating", | ||
"Updating": "updating", | ||
"Waiting": "waiting", | ||
"InitialRolesPopulated": "activating", | ||
"ScalingActive": "pending", | ||
"AbleToScale": "pending", | ||
"RunCompleted": "running", | ||
} | ||
|
||
// True == error | ||
// False == | ||
// Unknown == | ||
ErrorTrue = map[string]bool{ | ||
"OutOfDisk": true, | ||
"MemoryPressure": true, | ||
"DiskPressure": true, | ||
"NetworkUnavailable": true, | ||
"KernelHasNoDeadlock": true, | ||
"Unschedulable": true, | ||
"ReplicaFailure": true, | ||
} | ||
|
||
// True == | ||
// False == error | ||
// Unknown == | ||
ErrorFalse = map[string]bool{ | ||
"Failed": true, | ||
"Progressing": true, | ||
} | ||
|
||
// True == | ||
// False == transitioning | ||
// Unknown == error | ||
TransitioningFalse = map[string]string{ | ||
"Completed": "activating", | ||
"Ready": "unavailable", | ||
"Available": "updating", | ||
"Progressing": "inactive", | ||
} | ||
|
||
Summarizers []Summarizer | ||
) | ||
|
||
type Summarizer func(obj data.Object, conditions []Condition, summary Summary) Summary | ||
|
||
func init() { | ||
Summarizers = []Summarizer{ | ||
checkErrors, | ||
checkTransitioning, | ||
checkActive, | ||
checkPhase, | ||
checkInitializing, | ||
checkRemoving, | ||
checkLoadBalancer, | ||
} | ||
} | ||
|
||
func checkErrors(_ data.Object, conditions []Condition, summary Summary) Summary { | ||
for _, c := range conditions { | ||
if (ErrorFalse[c.Type()] && c.Status() == "False") || c.Reason() == "Error" { | ||
summary.Error = true | ||
summary.Message = append(summary.Message, c.Message()) | ||
break | ||
} | ||
} | ||
|
||
if summary.Error { | ||
return summary | ||
} | ||
|
||
for _, c := range conditions { | ||
if ErrorTrue[c.Type()] && c.Status() == "True" { | ||
summary.Error = true | ||
summary.Message = append(summary.Message, c.Message()) | ||
} | ||
} | ||
return summary | ||
} | ||
|
||
func checkTransitioning(_ data.Object, conditions []Condition, summary Summary) Summary { | ||
for _, c := range conditions { | ||
newState, ok := TransitioningUnknown[c.Type()] | ||
if !ok { | ||
continue | ||
} | ||
|
||
if c.Status() == "False" { | ||
summary.Error = true | ||
summary.State = newState | ||
summary.Message = append(summary.Message, c.Message()) | ||
} else if c.Status() == "Unknown" && summary.State == "" { | ||
summary.Transitioning = true | ||
summary.State = newState | ||
summary.Message = append(summary.Message, c.Message()) | ||
} | ||
} | ||
|
||
for _, c := range conditions { | ||
if summary.State != "" { | ||
break | ||
} | ||
newState, ok := TransitioningFalse[c.Type()] | ||
if !ok { | ||
continue | ||
} | ||
if c.Status() == "False" { | ||
summary.Transitioning = true | ||
summary.State = newState | ||
summary.Message = append(summary.Message, c.Message()) | ||
} else if c.Status() == "Unknown" { | ||
summary.Error = true | ||
summary.State = newState | ||
summary.Message = append(summary.Message, c.Message()) | ||
} | ||
} | ||
|
||
return summary | ||
} | ||
|
||
func checkActive(obj data.Object, _ []Condition, summary Summary) Summary { | ||
if summary.State != "" { | ||
return summary | ||
} | ||
|
||
switch obj.String("spec", "active") { | ||
case "true": | ||
summary.State = "active" | ||
case "false": | ||
summary.State = "inactive" | ||
} | ||
|
||
return summary | ||
} | ||
|
||
func checkPhase(obj data.Object, _ []Condition, summary Summary) Summary { | ||
phase := obj.String("status", "phase") | ||
if phase == "Succeeded" { | ||
summary.State = "succeeded" | ||
summary.Transitioning = false | ||
} else if phase != "" && summary.State == "" { | ||
summary.State = phase | ||
} | ||
return summary | ||
} | ||
|
||
func checkInitializing(obj data.Object, conditions []Condition, summary Summary) Summary { | ||
apiVersion := obj.String("apiVersion") | ||
_, hasConditions := obj.Map("status")["conditions"] | ||
if summary.State == "" && hasConditions && len(conditions) == 0 && strings.Contains(apiVersion, "cattle.io") { | ||
val := obj.String("metadata", "created") | ||
if i, err := convert.ToTimestamp(val); err == nil { | ||
if time.Unix(i/1000, 0).Add(5 * time.Second).After(time.Now()) { | ||
summary.State = "initializing" | ||
summary.Transitioning = true | ||
} | ||
} | ||
} | ||
return summary | ||
} | ||
|
||
func checkRemoving(obj data.Object, conditions []Condition, summary Summary) Summary { | ||
removed := obj.String("metadata", "removed") | ||
if removed == "" { | ||
return summary | ||
} | ||
|
||
summary.State = "removing" | ||
summary.Transitioning = true | ||
|
||
finalizers := obj.StringSlice("metadata", "finalizers") | ||
if len(finalizers) == 0 { | ||
finalizers = obj.StringSlice("spec", "finalizers") | ||
} | ||
|
||
for _, cond := range conditions { | ||
if cond.Type() == "Removed" && (cond.Status() == "Unknown" || cond.Status() == "False") && cond.Message() != "" { | ||
summary.Message = append(summary.Message, cond.Message()) | ||
} | ||
} | ||
|
||
if len(finalizers) == 0 { | ||
return summary | ||
} | ||
|
||
_, f := kv.RSplit(finalizers[0], "controller.cattle.io/") | ||
if f == "foregroundDeletion" { | ||
f = "object cleanup" | ||
} | ||
|
||
summary.Message = append(summary.Message, "waiting on "+f) | ||
if i, err := convert.ToTimestamp(removed); err == nil { | ||
if time.Unix(i/1000, 0).Add(5 * time.Minute).Before(time.Now()) { | ||
summary.Error = true | ||
} | ||
} | ||
|
||
return summary | ||
} | ||
|
||
func checkLoadBalancer(obj data.Object, _ []Condition, summary Summary) Summary { | ||
if (summary.State == "active" || summary.State == "") && | ||
obj.String("kind") == "Service" && | ||
obj.String("spec", "serviceKind") == "LoadBalancer" { | ||
addresses := obj.Slice("status", "loadBalancer", "ingress") | ||
if len(addresses) == 0 { | ||
summary.State = "pending" | ||
summary.Transitioning = true | ||
summary.Message = append(summary.Message, "Load balancer is being provisioned") | ||
} | ||
} | ||
|
||
return summary | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package summary | ||
|
||
import ( | ||
"github.com/rancher/wrangler/pkg/data" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
) | ||
|
||
type Summary struct { | ||
State string | ||
Error bool | ||
Transitioning bool | ||
Message []string | ||
} | ||
|
||
func Summarize(unstr *unstructured.Unstructured) Summary { | ||
var ( | ||
obj data.Object | ||
summary Summary | ||
) | ||
|
||
if unstr != nil { | ||
obj = unstr.Object | ||
} | ||
|
||
conditions := getConditions(obj) | ||
|
||
for _, summarizer := range Summarizers { | ||
summary = summarizer(obj, conditions, summary) | ||
} | ||
|
||
if summary.State == "" { | ||
summary.State = "active" | ||
} | ||
|
||
return summary | ||
} |