feat: kubesphere 4.0 (#6115)
* feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> * feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> --------- Signed-off-by: ci-bot <ci-bot@kubesphere.io> Co-authored-by: ks-ci-bot <ks-ci-bot@example.com> Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
committed by
GitHub
parent
b5015ec7b9
commit
447a51f08b
301
pkg/controller/k8sapplication/status.go
Normal file
301
pkg/controller/k8sapplication/status.go
Normal file
@@ -0,0 +1,301 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package k8sapplication
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Constants defining labels
|
||||
const (
|
||||
StatusReady = "Ready"
|
||||
StatusInProgress = "InProgress"
|
||||
StatusUnknown = "Unknown"
|
||||
StatusDisabled = "Disabled"
|
||||
)
|
||||
|
||||
func status(u *unstructured.Unstructured) (string, error) {
|
||||
gk := u.GroupVersionKind().GroupKind()
|
||||
switch gk.String() {
|
||||
case "StatefulSet.apps":
|
||||
return stsStatus(u)
|
||||
case "Deployment.apps":
|
||||
return deploymentStatus(u)
|
||||
case "ReplicaSet.apps":
|
||||
return replicasetStatus(u)
|
||||
case "DaemonSet.apps":
|
||||
return daemonsetStatus(u)
|
||||
case "PersistentVolumeClaim":
|
||||
return pvcStatus(u)
|
||||
case "Service":
|
||||
return serviceStatus(u)
|
||||
case "Pod":
|
||||
return podStatus(u)
|
||||
case "PodDisruptionBudget.policy":
|
||||
return pdbStatus(u)
|
||||
case "ReplicationController":
|
||||
return replicationControllerStatus(u)
|
||||
case "Job.batch":
|
||||
return jobStatus(u)
|
||||
default:
|
||||
return statusFromStandardConditions(u)
|
||||
}
|
||||
}
|
||||
|
||||
// Status from standard conditions
|
||||
func statusFromStandardConditions(u *unstructured.Unstructured) (string, error) {
|
||||
condition := StatusReady
|
||||
|
||||
// Check Ready condition
|
||||
_, cs, found, err := getConditionOfType(u, StatusReady)
|
||||
if err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
if found && cs == corev1.ConditionFalse {
|
||||
condition = StatusInProgress
|
||||
}
|
||||
|
||||
// Check InProgress condition
|
||||
_, cs, found, err = getConditionOfType(u, StatusInProgress)
|
||||
if err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
if found && cs == corev1.ConditionTrue {
|
||||
condition = StatusInProgress
|
||||
}
|
||||
|
||||
return condition, nil
|
||||
}
|
||||
|
||||
// Statefulset
|
||||
func stsStatus(u *unstructured.Unstructured) (string, error) {
|
||||
sts := &appsv1.StatefulSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, sts); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
if sts.Status.ObservedGeneration == sts.Generation &&
|
||||
sts.Status.Replicas == *sts.Spec.Replicas &&
|
||||
sts.Status.ReadyReplicas == *sts.Spec.Replicas &&
|
||||
sts.Status.CurrentReplicas == *sts.Spec.Replicas {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// Deployment
|
||||
func deploymentStatus(u *unstructured.Unstructured) (string, error) {
|
||||
deployment := &appsv1.Deployment{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, deployment); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
replicaFailure := false
|
||||
progressing := false
|
||||
available := false
|
||||
|
||||
for _, condition := range deployment.Status.Conditions {
|
||||
switch condition.Type {
|
||||
case appsv1.DeploymentProgressing:
|
||||
if condition.Status == corev1.ConditionTrue && condition.Reason == "NewReplicaSetAvailable" {
|
||||
progressing = true
|
||||
}
|
||||
case appsv1.DeploymentAvailable:
|
||||
if condition.Status == corev1.ConditionTrue {
|
||||
available = true
|
||||
}
|
||||
case appsv1.DeploymentReplicaFailure:
|
||||
if condition.Status == corev1.ConditionTrue {
|
||||
replicaFailure = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if deployment.Status.ObservedGeneration == deployment.Generation &&
|
||||
deployment.Status.Replicas == *deployment.Spec.Replicas &&
|
||||
deployment.Status.ReadyReplicas == *deployment.Spec.Replicas &&
|
||||
deployment.Status.AvailableReplicas == *deployment.Spec.Replicas &&
|
||||
deployment.Status.Conditions != nil && len(deployment.Status.Conditions) > 0 &&
|
||||
(progressing || available) && !replicaFailure {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// Replicaset
|
||||
func replicasetStatus(u *unstructured.Unstructured) (string, error) {
|
||||
rs := &appsv1.ReplicaSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, rs); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
replicaFailure := false
|
||||
for _, condition := range rs.Status.Conditions {
|
||||
switch condition.Type {
|
||||
case appsv1.ReplicaSetReplicaFailure:
|
||||
if condition.Status == corev1.ConditionTrue {
|
||||
replicaFailure = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if rs.Status.ObservedGeneration == rs.Generation &&
|
||||
rs.Status.Replicas == *rs.Spec.Replicas &&
|
||||
rs.Status.ReadyReplicas == *rs.Spec.Replicas &&
|
||||
rs.Status.AvailableReplicas == *rs.Spec.Replicas && !replicaFailure {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// Daemonset
|
||||
func daemonsetStatus(u *unstructured.Unstructured) (string, error) {
|
||||
ds := &appsv1.DaemonSet{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, ds); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
if ds.Status.ObservedGeneration == ds.Generation &&
|
||||
ds.Status.DesiredNumberScheduled == ds.Status.NumberAvailable &&
|
||||
ds.Status.DesiredNumberScheduled == ds.Status.NumberReady {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// PVC
|
||||
func pvcStatus(u *unstructured.Unstructured) (string, error) {
|
||||
pvc := &corev1.PersistentVolumeClaim{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, pvc); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
if pvc.Status.Phase == corev1.ClaimBound {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// Service
|
||||
func serviceStatus(u *unstructured.Unstructured) (string, error) {
|
||||
service := &corev1.Service{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, service); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
stype := service.Spec.Type
|
||||
|
||||
if stype == corev1.ServiceTypeClusterIP || stype == corev1.ServiceTypeNodePort || stype == corev1.ServiceTypeExternalName ||
|
||||
stype == corev1.ServiceTypeLoadBalancer && isEmpty(service.Spec.ClusterIP) &&
|
||||
len(service.Status.LoadBalancer.Ingress) > 0 && !hasEmptyIngressIP(service.Status.LoadBalancer.Ingress) {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// Pod
|
||||
func podStatus(u *unstructured.Unstructured) (string, error) {
|
||||
pod := &corev1.Pod{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, pod); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
for _, condition := range pod.Status.Conditions {
|
||||
if condition.Type == corev1.PodReady && (condition.Reason == "PodCompleted" || condition.Status == corev1.ConditionTrue) {
|
||||
return StatusReady, nil
|
||||
}
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
// PodDisruptionBudget
|
||||
func pdbStatus(u *unstructured.Unstructured) (string, error) {
|
||||
pdb := &policyv1beta1.PodDisruptionBudget{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, pdb); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
if pdb.Status.ObservedGeneration == pdb.Generation &&
|
||||
pdb.Status.CurrentHealthy >= pdb.Status.DesiredHealthy {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
func replicationControllerStatus(u *unstructured.Unstructured) (string, error) {
|
||||
rc := &corev1.ReplicationController{}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, rc); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
if rc.Status.ObservedGeneration == rc.Generation &&
|
||||
rc.Status.Replicas == *rc.Spec.Replicas &&
|
||||
rc.Status.ReadyReplicas == *rc.Spec.Replicas &&
|
||||
rc.Status.AvailableReplicas == *rc.Spec.Replicas {
|
||||
return StatusReady, nil
|
||||
}
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
func jobStatus(u *unstructured.Unstructured) (string, error) {
|
||||
job := &batchv1.Job{}
|
||||
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, job); err != nil {
|
||||
return StatusUnknown, err
|
||||
}
|
||||
|
||||
if job.Status.StartTime == nil {
|
||||
return StatusInProgress, nil
|
||||
}
|
||||
|
||||
return StatusReady, nil
|
||||
}
|
||||
|
||||
func hasEmptyIngressIP(ingress []corev1.LoadBalancerIngress) bool {
|
||||
for _, i := range ingress {
|
||||
if isEmpty(i.IP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isEmpty(s string) bool {
|
||||
return len(strings.TrimSpace(s)) == 0
|
||||
}
|
||||
|
||||
func getConditionOfType(u *unstructured.Unstructured, conditionType string) (string, corev1.ConditionStatus, bool, error) {
|
||||
conditions, found, err := unstructured.NestedSlice(u.Object, "status", "conditions")
|
||||
if err != nil || !found {
|
||||
return "", corev1.ConditionFalse, false, err
|
||||
}
|
||||
|
||||
for _, c := range conditions {
|
||||
condition, ok := c.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
t, found := condition["type"]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
condType, ok := t.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if condType == conditionType {
|
||||
reason := condition["reason"].(string)
|
||||
conditionStatus := condition["status"].(string)
|
||||
return reason, corev1.ConditionStatus(conditionStatus), true, nil
|
||||
}
|
||||
}
|
||||
return "", corev1.ConditionFalse, false, nil
|
||||
}
|
||||
Reference in New Issue
Block a user