diff --git a/handler/handler.go b/handler/handler.go index 1e31c06..3c0c300 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -9,8 +9,11 @@ import ( "main/argohandler" "main/db" "net/http" + "sort" "strings" + "time" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" // "github.com/gorilla/mux" @@ -43,7 +46,7 @@ type Pod struct { Name string `json:name` Namespace string `json:name` Status string `json:status` - Restart string `json:restart` + Restart int32 `json:restart` Age string `json:age` } @@ -58,22 +61,23 @@ type Service struct { } type Deployment struct { - Name string `json:name` - Namespace string `json:namespace` - Ready string `json:Ready` - UpdateToDate string `json:uptodate` - Available string `json:available` + Name string `json:name` + Namespace string `json:namespace` + Available string `json:available` + Replicas int32 `json:replicas` + Message string `json:message` + Reason string `json:reason` } type Daemonset struct { Name string `json:name` Namespace string `json:namespace` - Ready string `json:Ready` + Ready int32 `json:Ready` Age string `json:age` - DESIRED string `json:desired` - CURRENT string `json:current` - UpdateToDate string `json:uptodate` - Available string `json:available` + DESIRED int32 `json:desired` + CURRENT int32 `json:current` + UpdateToDate int32 `json:uptodate` + Available int32 `json:available` Node string `json:node` Selector string `json:selector` } @@ -112,6 +116,59 @@ type StatefulSet struct { Age string `json:age` } +func joinNodeSelector(m map[string]string) string { + if len(m) == 0 { + return "" + } + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + parts := make([]string, 0, len(keys)) + for _, k := range keys { + parts = append(parts, k+"="+m[k]) + } + return strings.Join(parts, ",") +} + +// human prints like 3d4h5m (compact) +func human(d time.Duration) string { + if d < 0 { + d = -d + } + d = d.Round(time.Second) + + days := int(d / (24 * time.Hour)) + d -= time.Duration(days) * 24 * time.Hour + + hours := int(d / time.Hour) + d -= time.Duration(hours) * time.Hour + + mins := int(d / time.Minute) + d -= time.Duration(mins) * time.Minute + + secs := int(d / time.Second) + + if days > 0 { + if mins > 0 { + return fmt.Sprintf("%dd%dm", days, mins) + } + return fmt.Sprintf("%dd", days) + } + if hours > 0 { + if mins > 0 { + return fmt.Sprintf("%dh%dm", hours, mins) + } + return fmt.Sprintf("%dh", hours) + } + if mins > 0 { + return fmt.Sprintf("%dm", mins) + } + return fmt.Sprintf("%ds", secs) +} + func CreateClusterHandler(w http.ResponseWriter, r *http.Request) { var cluster Cluster @@ -243,12 +300,15 @@ func Cluster_services(w http.ResponseWriter, r *http.Request) { Allservice := []Service{} var service Service + now := time.Now() for _, s := range services.Items { service.Name = s.Name service.Namespace = s.Namespace service.Type = string(s.Spec.Type) service.Ports = servicePortsToString(s.Spec.Ports) service.ClusterIP = s.Spec.ClusterIP + age := now.Sub(s.CreationTimestamp.Time) + service.Age = human(age) if len(s.Spec.ExternalIPs) > 0 { service.ExternalIP = s.Spec.ExternalIPs[0] } @@ -290,10 +350,17 @@ func Cluster_statefulset(w http.ResponseWriter, r *http.Request) { AllstatefulSets := []StatefulSet{} var StatefulSet StatefulSet + now := time.Now() for _, s := range statefulSets.Items { + desired := int32(1) + if s.Spec.Replicas != nil { + desired = *s.Spec.Replicas + } + StatefulSet.Ready = fmt.Sprintf("%d/%d", s.Status.ReadyReplicas, desired) StatefulSet.Name = s.Name StatefulSet.Namespace = s.Namespace - StatefulSet.Ready = string(s.Status.ReadyReplicas) + age := now.Sub(s.CreationTimestamp.Time) // same as kubectl AGE + StatefulSet.Age = human(age) AllstatefulSets = append(AllstatefulSets, StatefulSet) } @@ -331,13 +398,19 @@ func Cluster_daemonsets(w http.ResponseWriter, r *http.Request) { AllDaemonSets := []Daemonset{} var DaemonSets Daemonset + now := time.Now() for _, s := range DaemonSetss.Items { DaemonSets.Name = s.Name DaemonSets.Namespace = s.Namespace - DaemonSets.DESIRED = string(s.Status.DesiredNumberScheduled) - DaemonSets.CURRENT = string(s.Status.NumberReady) - - DaemonSets.Available = string(s.Status.NumberAvailable) + DaemonSets.DESIRED = s.Status.DesiredNumberScheduled + DaemonSets.CURRENT = s.Status.CurrentNumberScheduled + DaemonSets.Available = s.Status.NumberAvailable + DaemonSets.Ready = s.Status.NumberReady + DaemonSets.UpdateToDate = s.Status.UpdatedNumberScheduled + DaemonSets.Node = s.Spec.Template.Spec.NodeName + DaemonSets.Selector = joinNodeSelector(s.Spec.Template.Spec.NodeSelector) + age := now.Sub(s.CreationTimestamp.Time) // same as kubectl AGE + DaemonSets.Age = human(age) AllDaemonSets = append(AllDaemonSets, DaemonSets) } @@ -376,9 +449,22 @@ func Cluster_deployments(w http.ResponseWriter, r *http.Request) { Alldeployment := []Deployment{} var deployment Deployment + var avail bool + var reason, msg string for _, d := range deployments.Items { deployment.Name = d.Name deployment.Namespace = d.Namespace + deployment.Replicas = *d.Spec.Replicas + for _, c := range d.Status.Conditions { + if c.Type == appsv1.DeploymentAvailable { + avail = (c.Status == corev1.ConditionTrue) + reason, msg = c.Reason, c.Message + deployment.Available = fmt.Sprintf("%t", avail) + deployment.Message = msg + deployment.Reason = reason + } + } + Alldeployment = append(Alldeployment, deployment) } @@ -423,11 +509,22 @@ func Cluster_pods(w http.ResponseWriter, r *http.Request) { Allpod := []Pod{} var pod Pod + now := time.Now() for _, p := range pods.Items { fmt.Printf(p.Name, p.Namespace) pod.Name = p.Name pod.Namespace = p.Namespace pod.Status = string(p.Status.Phase) + age := now.Sub(p.CreationTimestamp.Time) // same as kubectl AGE + pod.Age = human(age) + + var restartedCount int32 + var restarts int32 + for _, st := range p.Status.ContainerStatuses { + restarts += st.RestartCount + } + pod.Restart = restartedCount + Allpod = append(Allpod, pod) } @@ -504,9 +601,13 @@ func Cluster_jobs(w http.ResponseWriter, r *http.Request) { AllJob := []Jobs{} var job Jobs + now := time.Now() for _, d := range jobs.Items { job.Name = d.Name job.Namespace = d.Namespace + age := now.Sub(d.CreationTimestamp.Time) // same as kubectl AGE + job.Age = human(age) + AllJob = append(AllJob, job) } @@ -543,9 +644,12 @@ func Cluster_replicasets(w http.ResponseWriter, r *http.Request) { Allreplicaset := []Replicaset{} var replicaset Replicaset + now := time.Now() for _, d := range replicasets.Items { replicaset.Name = d.Name replicaset.Namespace = d.Namespace + age := now.Sub(d.CreationTimestamp.Time) // same as kubectl AGE + replicaset.Age = human(age) Allreplicaset = append(Allreplicaset, replicaset) } @@ -582,9 +686,12 @@ func Cluster_replicationcontrollers(w http.ResponseWriter, r *http.Request) { AllreplicationController := []ReplicationController{} var ReplicationController ReplicationController + now := time.Now() for _, d := range replicationcontrollers.Items { ReplicationController.Name = d.Name ReplicationController.Namespace = d.Namespace + age := now.Sub(d.CreationTimestamp.Time) // same as kubectl AGE + ReplicationController.Age = human(age) AllreplicationController = append(AllreplicationController, ReplicationController) } @@ -621,9 +728,12 @@ func Cluster_cronjobs(w http.ResponseWriter, r *http.Request) { AllreplicationController := []ReplicationController{} var ReplicationController ReplicationController + now := time.Now() for _, d := range replicationcontrollers.Items { ReplicationController.Name = d.Name ReplicationController.Namespace = d.Namespace + age := now.Sub(d.CreationTimestamp.Time) // same as kubectl AGE + ReplicationController.Age = human(age) AllreplicationController = append(AllreplicationController, ReplicationController) }