mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
This commit adds the ReadyReplicas and Total Replicas count, the information is useful if you want to look over a new release of your application and k8s and want to know how many pods are ready/started from k8s. Otherwise the deployment option of this module is not that useful. Signed-off-by: Lukas Kämmerling <lukas.kaemmerling@hetzner-cloud.de>
216 lines
6.1 KiB
Go
216 lines
6.1 KiB
Go
package kubernetes
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/rivo/tview"
|
|
"github.com/wtfutil/wtf/utils"
|
|
"github.com/wtfutil/wtf/view"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// Widget contains all the config for the widget
|
|
type Widget struct {
|
|
view.TextWidget
|
|
|
|
objects []string
|
|
title string
|
|
kubeconfig string
|
|
namespaces []string
|
|
context string
|
|
settings *Settings
|
|
}
|
|
|
|
// NewWidget creates a new instance of the widget
|
|
func NewWidget(tviewApp *tview.Application, settings *Settings) *Widget {
|
|
widget := Widget{
|
|
TextWidget: view.NewTextWidget(tviewApp, nil, settings.Common),
|
|
|
|
objects: settings.objects,
|
|
title: settings.title,
|
|
kubeconfig: settings.kubeconfig,
|
|
namespaces: settings.namespaces,
|
|
settings: settings,
|
|
context: settings.context,
|
|
}
|
|
|
|
widget.View.SetWrap(true)
|
|
|
|
return &widget
|
|
}
|
|
|
|
// Refresh executes the command and updates the view with the results
|
|
func (widget *Widget) Refresh() {
|
|
title := widget.generateTitle()
|
|
client, err := widget.getInstance()
|
|
|
|
if err != nil {
|
|
widget.Redraw(func() (string, string, bool) { return title, err.Error(), true })
|
|
return
|
|
}
|
|
|
|
var content string
|
|
|
|
if utils.Includes(widget.objects, "nodes") {
|
|
nodeList, nodeError := client.getNodes()
|
|
if nodeError != nil {
|
|
widget.Redraw(func() (string, string, bool) { return title, "[red] Error getting node data [white]\n", true })
|
|
return
|
|
}
|
|
content += fmt.Sprintf("[%s]Nodes[white]\n", widget.settings.Colors.Subheading)
|
|
for _, node := range nodeList {
|
|
content += fmt.Sprintf("%s\n", node)
|
|
}
|
|
content += "\n"
|
|
}
|
|
|
|
if utils.Includes(widget.objects, "deployments") {
|
|
deploymentList, deploymentError := client.getDeployments(widget.namespaces)
|
|
if deploymentError != nil {
|
|
widget.Redraw(func() (string, string, bool) { return title, "[red] Error getting deployment data [white]\n", true })
|
|
return
|
|
}
|
|
content += fmt.Sprintf("[%s]Deployments[white]\n", widget.settings.Colors.Subheading)
|
|
for _, deployment := range deploymentList {
|
|
content += fmt.Sprintf("%s\n", deployment)
|
|
}
|
|
content += "\n"
|
|
}
|
|
|
|
if utils.Includes(widget.objects, "pods") {
|
|
podList, podError := client.getPods(widget.namespaces)
|
|
if podError != nil {
|
|
widget.Redraw(func() (string, string, bool) { return title, "[red] Error getting pod data [white]\n", false })
|
|
return
|
|
}
|
|
content += fmt.Sprintf("[%s]Pods[white]\n", widget.settings.Colors.Subheading)
|
|
for _, pod := range podList {
|
|
content += fmt.Sprintf("%s\n", pod)
|
|
}
|
|
content += "\n"
|
|
}
|
|
|
|
widget.Redraw(func() (string, string, bool) { return title, content, false })
|
|
}
|
|
|
|
/* -------------------- Unexported Functions -------------------- */
|
|
|
|
// generateTitle generates a title for the widget
|
|
func (widget *Widget) generateTitle() string {
|
|
if len(widget.title) != 0 {
|
|
return widget.title
|
|
}
|
|
title := "Kube"
|
|
|
|
if widget.context != "" {
|
|
title = fmt.Sprintf("%s (%s)", title, widget.context)
|
|
}
|
|
|
|
if len(widget.namespaces) == 1 {
|
|
title += fmt.Sprintf(" - Namespace: %s", widget.namespaces[0])
|
|
} else if len(widget.namespaces) > 1 {
|
|
title += fmt.Sprintf(" - Namespaces: %q", widget.namespaces)
|
|
}
|
|
return title
|
|
}
|
|
|
|
// getPods returns a slice of pod strings
|
|
func (client *clientInstance) getPods(namespaces []string) ([]string, error) {
|
|
var podList []string
|
|
if len(namespaces) != 0 {
|
|
for _, namespace := range namespaces {
|
|
pods, err := client.Client.CoreV1().Pods(namespace).List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, pod := range pods.Items {
|
|
var podString string
|
|
status := pod.Status.Phase
|
|
name := pod.ObjectMeta.Name
|
|
if len(namespaces) == 1 {
|
|
podString = fmt.Sprintf("%-50s %s", name, status)
|
|
} else {
|
|
podString = fmt.Sprintf("%-20s %-50s %s", namespace, name, status)
|
|
}
|
|
podList = append(podList, podString)
|
|
}
|
|
}
|
|
} else {
|
|
pods, err := client.Client.CoreV1().Pods("").List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, pod := range pods.Items {
|
|
podString := fmt.Sprintf("%-20s %-50s %s", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, pod.Status.Phase)
|
|
podList = append(podList, podString)
|
|
}
|
|
}
|
|
|
|
return podList, nil
|
|
}
|
|
|
|
// get Deployments returns a string slice of pod strings
|
|
func (client *clientInstance) getDeployments(namespaces []string) ([]string, error) {
|
|
var deploymentList []string
|
|
if len(namespaces) != 0 {
|
|
for _, namespace := range namespaces {
|
|
deployments, err := client.Client.AppsV1().Deployments(namespace).List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, deployment := range deployments.Items {
|
|
var deployString string
|
|
if len(namespaces) == 1 {
|
|
deployString = fmt.Sprintf("%-50s (%d/%d)", deployment.ObjectMeta.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
|
|
} else {
|
|
deployString = fmt.Sprintf("%-20s %-50s (%d/%d)", deployment.ObjectMeta.Namespace, deployment.ObjectMeta.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
|
|
}
|
|
deploymentList = append(deploymentList, deployString)
|
|
}
|
|
}
|
|
} else {
|
|
deployments, err := client.Client.AppsV1().Deployments("").List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, deployment := range deployments.Items {
|
|
deployString := fmt.Sprintf("%-20s %-50s (%d/%d)", deployment.ObjectMeta.Namespace, deployment.ObjectMeta.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
|
|
deploymentList = append(deploymentList, deployString)
|
|
}
|
|
}
|
|
return deploymentList, nil
|
|
}
|
|
|
|
// getNodes returns a string slice of nodes
|
|
func (client *clientInstance) getNodes() ([]string, error) {
|
|
var nodeList []string
|
|
|
|
nodes, err := client.Client.CoreV1().Nodes().List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, node := range nodes.Items {
|
|
var nodeStatus string
|
|
for _, condition := range node.Status.Conditions {
|
|
if condition.Reason == "KubeletReady" {
|
|
switch {
|
|
case condition.Status == "True":
|
|
nodeStatus = "Ready"
|
|
case condition.Reason == "False":
|
|
nodeStatus = "NotReady"
|
|
default:
|
|
nodeStatus = "Unknown"
|
|
}
|
|
}
|
|
}
|
|
nodeString := fmt.Sprintf("%-50s %s", node.ObjectMeta.Name, nodeStatus)
|
|
nodeList = append(nodeList, nodeString)
|
|
}
|
|
return nodeList, nil
|
|
}
|