mirror of
https://github.com/rancher/types.git
synced 2025-06-28 06:26:49 +00:00
The hpa condition ScalingLimited should be in reverseErrorMap. It means the the hps object is currently not able to scale due to the scaling speed is too high.
318 lines
7.4 KiB
Go
318 lines
7.4 KiB
Go
package status
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/rancher/norman/types/convert"
|
|
"github.com/rancher/norman/types/values"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
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",
|
|
}
|
|
|
|
// True == error
|
|
// False ==
|
|
// Unknown ==
|
|
var reverseErrorMap = map[string]bool{
|
|
"OutOfDisk": true,
|
|
"MemoryPressure": true,
|
|
"DiskPressure": true,
|
|
"NetworkUnavailable": true,
|
|
"KernelHasNoDeadlock": true,
|
|
"Unschedulable": true,
|
|
"ReplicaFailure": true,
|
|
"ScalingLimited": 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 {
|
|
data["transitioning"] = "error"
|
|
} else if 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
|
|
}
|
|
}
|