1
0
mirror of https://github.com/rancher/types.git synced 2025-04-27 02:10:48 +00:00

Move status logic to wrangler

This commit is contained in:
Darren Shepherd 2020-02-14 16:12:47 -07:00
parent 4296a05c98
commit 308d0bce2d

View File

@ -3,315 +3,21 @@ package status
import (
"strings"
"time"
"encoding/json"
"github.com/rancher/norman/types/convert"
"github.com/rancher/norman/types/values"
"github.com/sirupsen/logrus"
"github.com/rancher/wrangler/pkg/summary"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
type status struct {
Conditions []condition `json:"conditions"`
}
type condition struct {
Reason string
Type string
Status string
Message string
}
// True ==
// False == error
// Unknown == transitioning
var transitioningMap = 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 ==
var reverseErrorMap = map[string]bool{
"OutOfDisk": true,
"MemoryPressure": true,
"DiskPressure": true,
"NetworkUnavailable": true,
"KernelHasNoDeadlock": true,
"Unschedulable": true,
"ReplicaFailure": true,
}
// True ==
// False == error
// Unknown ==
var errorMapping = map[string]bool{
"Failed": true,
"Progressing": true,
}
// True ==
// False == transitioning
// Unknown == error
var doneMap = map[string]string{
"Completed": "activating",
"Ready": "unavailable",
"Available": "updating",
"Progressing": "inactive",
}
// True == transitioning
// False ==
// Unknown ==
var progressMap = map[string]string{}
func concat(str, next string) string {
if str == "" {
return next
}
if next == "" {
return str
}
if strings.EqualFold(str, next) {
return str
}
return str + "; " + next
}
func Set(data map[string]interface{}) {
genericStatus(data)
loadBalancerStatus(data)
}
func loadBalancerStatus(data map[string]interface{}) {
if data["state"] == "active" && data["kind"] == "Service" && values.GetValueN(data, "spec", "serviceKind") == "LoadBalancer" {
addresses, ok := values.GetSlice(data, "status", "loadBalancer", "ingress")
if !ok || len(addresses) == 0 {
data["state"] = "pending"
data["transitioning"] = "yes"
data["transitioningMessage"] = "Load balancer is being provisioned"
}
}
}
func genericStatus(data map[string]interface{}) {
if data == nil {
return
}
val, conditionsOk := values.GetValue(data, "status", "conditions")
var conditions []condition
convert.ToObj(val, &conditions)
statusAnn, annOK := values.GetValue(data, "metadata", "annotations", "cattle.io/status")
if annOK {
status := &status{}
s, ok := statusAnn.(string)
if ok {
err := json.Unmarshal([]byte(s), status)
if err != nil {
logrus.Warnf("Unable to unmarshal cattle status %v. Error: %v", s, err)
}
}
if len(status.Conditions) > 0 {
conditions = append(conditions, status.Conditions...)
}
}
state := ""
error := false
transitioning := false
message := ""
for _, c := range conditions {
if (errorMapping[c.Type] && c.Status == "False") || c.Reason == "Error" {
error = true
message = c.Message
break
}
}
if !error {
for _, c := range conditions {
if reverseErrorMap[c.Type] && c.Status == "True" {
error = true
message = concat(message, c.Message)
}
}
}
for _, c := range conditions {
newState, ok := transitioningMap[c.Type]
if !ok {
continue
}
if c.Status == "False" {
error = true
state = newState
message = concat(message, c.Message)
} else if c.Status == "Unknown" && state == "" {
transitioning = true
state = newState
message = concat(message, c.Message)
}
}
for _, c := range conditions {
if state != "" {
break
}
newState, ok := doneMap[c.Type]
if !ok {
continue
}
if c.Status == "False" {
transitioning = true
state = newState
message = concat(message, c.Message)
} else if c.Status == "Unknown" {
error = true
state = newState
message = concat(message, c.Message)
}
}
for _, c := range conditions {
if state != "" {
break
}
newState, ok := progressMap[c.Type]
if !ok {
continue
}
if c.Status == "True" {
transitioning = true
state = newState
message = concat(message, c.Message)
}
}
if state == "" {
val, ok := values.GetValue(data, "spec", "active")
if ok {
if convert.ToBool(val) {
state = "active"
} else {
state = "inactive"
}
}
}
phase, ok := values.GetValueN(data, "status", "phase").(string)
if phase != "" && ok {
if phase == "Succeeded" {
state = "succeeded"
transitioning = false
} else if state == "" {
state = phase
}
}
apiVersion, _ := values.GetValueN(data, "apiVersion").(string)
if state == "" && conditionsOk && len(conditions) == 0 && strings.Contains(apiVersion, "cattle.io") {
if val, ok := values.GetValue(data, "metadata", "created"); ok {
if i, err := convert.ToTimestamp(val); err == nil {
if time.Unix(i/1000, 0).Add(5 * time.Second).After(time.Now()) {
state = "initializing"
transitioning = true
}
}
}
}
if state == "" {
state = "active"
}
if error {
summary := summary.Summarize(&unstructured.Unstructured{Object: data})
data["state"] = summary.State
data["transitioning"] = "no"
if summary.Error {
data["transitioning"] = "error"
} else if transitioning {
} else if summary.Transitioning {
data["transitioning"] = "yes"
} else {
data["transitioning"] = "no"
}
data["state"] = strings.ToLower(state)
data["transitioningMessage"] = message
val, ok = values.GetValue(data, "metadata", "removed")
if ok && val != "" && val != nil {
data["state"] = "removing"
data["transitioning"] = "yes"
finalizers, ok := values.GetStringSlice(data, "metadata", "finalizers")
if !ok {
finalizers, ok = values.GetStringSlice(data, "spec", "finalizers")
}
msg := message
for _, cond := range conditions {
if cond.Type == "Removed" && (cond.Status == "Unknown" || cond.Status == "False") && cond.Message != "" {
msg = cond.Message
}
}
if ok && len(finalizers) > 0 {
parts := strings.Split(finalizers[0], "controller.cattle.io/")
f := parts[len(parts)-1]
if f == "foregroundDeletion" {
f = "object cleanup"
}
if len(msg) > 0 {
msg = msg + "; waiting on " + f
} else {
msg = "waiting on " + f
}
data["transitioningMessage"] = msg
if i, err := convert.ToTimestamp(val); err == nil {
if time.Unix(i/1000, 0).Add(5 * time.Minute).Before(time.Now()) {
data["transitioning"] = "error"
}
}
}
return
}
data["transitioningMessage"] = strings.Join(summary.Message, "; ")
}