github.com/wtfutil/wtf@v0.43.0/modules/kubernetes/widget.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/rivo/tview"
     9  	"github.com/wtfutil/wtf/utils"
    10  	"github.com/wtfutil/wtf/view"
    11  
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  )
    14  
    15  // Widget contains all the config for the widget
    16  type Widget struct {
    17  	view.TextWidget
    18  
    19  	client     *clientInstance
    20  	clientOnce sync.Once
    21  
    22  	objects    []string
    23  	title      string
    24  	kubeconfig string
    25  	namespaces []string
    26  	context    string
    27  	settings   *Settings
    28  }
    29  
    30  // NewWidget creates a new instance of the widget
    31  func NewWidget(tviewApp *tview.Application, redrawChan chan bool, settings *Settings) *Widget {
    32  	widget := Widget{
    33  		TextWidget: view.NewTextWidget(tviewApp, redrawChan, nil, settings.Common),
    34  
    35  		objects:    settings.objects,
    36  		title:      settings.title,
    37  		kubeconfig: settings.kubeconfig,
    38  		namespaces: settings.namespaces,
    39  		settings:   settings,
    40  		context:    settings.context,
    41  	}
    42  
    43  	widget.View.SetWrap(true)
    44  
    45  	return &widget
    46  }
    47  
    48  // Refresh executes the command and updates the view with the results
    49  func (widget *Widget) Refresh() {
    50  	title := widget.generateTitle()
    51  	client, err := widget.getInstance()
    52  
    53  	if err != nil {
    54  		widget.Redraw(func() (string, string, bool) { return title, err.Error(), true })
    55  		return
    56  	}
    57  
    58  	var content string
    59  
    60  	if utils.Includes(widget.objects, "nodes") {
    61  		nodeList, nodeError := client.getNodes()
    62  		if nodeError != nil {
    63  			widget.Redraw(func() (string, string, bool) { return title, "[red] Error getting node data [white]\n", true })
    64  			return
    65  		}
    66  		content += fmt.Sprintf("[%s]Nodes[white]\n", widget.settings.Colors.Subheading)
    67  		for _, node := range nodeList {
    68  			content += fmt.Sprintf("%s\n", node)
    69  		}
    70  		content += "\n"
    71  	}
    72  
    73  	if utils.Includes(widget.objects, "deployments") {
    74  		deploymentList, deploymentError := client.getDeployments(widget.namespaces)
    75  		if deploymentError != nil {
    76  			widget.Redraw(func() (string, string, bool) { return title, "[red] Error getting deployment data [white]\n", true })
    77  			return
    78  		}
    79  		content += fmt.Sprintf("[%s]Deployments[white]\n", widget.settings.Colors.Subheading)
    80  		for _, deployment := range deploymentList {
    81  			content += fmt.Sprintf("%s\n", deployment)
    82  		}
    83  		content += "\n"
    84  	}
    85  
    86  	if utils.Includes(widget.objects, "pods") {
    87  		podList, podError := client.getPods(widget.namespaces)
    88  		if podError != nil {
    89  			widget.Redraw(func() (string, string, bool) { return title, "[red] Error getting pod data [white]\n", false })
    90  			return
    91  		}
    92  		content += fmt.Sprintf("[%s]Pods[white]\n", widget.settings.Colors.Subheading)
    93  		for _, pod := range podList {
    94  			content += fmt.Sprintf("%s\n", pod)
    95  		}
    96  		content += "\n"
    97  	}
    98  
    99  	widget.Redraw(func() (string, string, bool) { return title, content, false })
   100  }
   101  
   102  /* -------------------- Unexported Functions -------------------- */
   103  
   104  // generateTitle generates a title for the widget
   105  func (widget *Widget) generateTitle() string {
   106  	if widget.title != "" {
   107  		return widget.title
   108  	}
   109  	title := "Kube"
   110  
   111  	if widget.context != "" {
   112  		title = fmt.Sprintf("%s (%s)", title, widget.context)
   113  	}
   114  
   115  	if len(widget.namespaces) == 1 {
   116  		title += fmt.Sprintf(" - Namespace: %s", widget.namespaces[0])
   117  	} else if len(widget.namespaces) > 1 {
   118  		title += fmt.Sprintf(" - Namespaces: %q", widget.namespaces)
   119  	}
   120  	return title
   121  }
   122  
   123  // getPods returns a slice of pod strings
   124  func (client *clientInstance) getPods(namespaces []string) ([]string, error) {
   125  	var podList []string
   126  	if len(namespaces) != 0 {
   127  		for _, namespace := range namespaces {
   128  			pods, err := client.Client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{})
   129  			if err != nil {
   130  				return nil, err
   131  			}
   132  
   133  			for _, pod := range pods.Items {
   134  				var podString string
   135  				status := pod.Status.Phase
   136  				name := pod.ObjectMeta.Name
   137  				if len(namespaces) == 1 {
   138  					podString = fmt.Sprintf("%-50s %s", name, status)
   139  				} else {
   140  					podString = fmt.Sprintf("%-20s %-50s %s", namespace, name, status)
   141  				}
   142  				podList = append(podList, podString)
   143  			}
   144  		}
   145  	} else {
   146  		pods, err := client.Client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{})
   147  		if err != nil {
   148  			return nil, err
   149  		}
   150  		for _, pod := range pods.Items {
   151  			podString := fmt.Sprintf("%-20s %-50s %s", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, pod.Status.Phase)
   152  			podList = append(podList, podString)
   153  		}
   154  	}
   155  
   156  	return podList, nil
   157  }
   158  
   159  // get Deployments returns a string slice of pod strings
   160  func (client *clientInstance) getDeployments(namespaces []string) ([]string, error) {
   161  	var deploymentList []string
   162  	if len(namespaces) != 0 {
   163  		for _, namespace := range namespaces {
   164  			deployments, err := client.Client.AppsV1().Deployments(namespace).List(context.Background(), metav1.ListOptions{})
   165  			if err != nil {
   166  				return nil, err
   167  			}
   168  
   169  			for _, deployment := range deployments.Items {
   170  				var deployString string
   171  				if len(namespaces) == 1 {
   172  					deployString = fmt.Sprintf("%-50s (%d/%d)", deployment.ObjectMeta.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
   173  				} else {
   174  					deployString = fmt.Sprintf("%-20s %-50s (%d/%d)", deployment.ObjectMeta.Namespace, deployment.ObjectMeta.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
   175  				}
   176  				deploymentList = append(deploymentList, deployString)
   177  			}
   178  		}
   179  	} else {
   180  		deployments, err := client.Client.AppsV1().Deployments("").List(context.Background(), metav1.ListOptions{})
   181  		if err != nil {
   182  			return nil, err
   183  		}
   184  
   185  		for _, deployment := range deployments.Items {
   186  			deployString := fmt.Sprintf("%-20s %-50s (%d/%d)", deployment.ObjectMeta.Namespace, deployment.ObjectMeta.Name, deployment.Status.ReadyReplicas, deployment.Status.Replicas)
   187  			deploymentList = append(deploymentList, deployString)
   188  		}
   189  	}
   190  	return deploymentList, nil
   191  }
   192  
   193  // getNodes returns a string slice of nodes
   194  func (client *clientInstance) getNodes() ([]string, error) {
   195  	var nodeList []string
   196  
   197  	nodes, err := client.Client.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	for _, node := range nodes.Items {
   203  		var nodeStatus string
   204  		for _, condition := range node.Status.Conditions {
   205  			if condition.Reason == "KubeletReady" {
   206  				switch {
   207  				case condition.Status == "True":
   208  					nodeStatus = "Ready"
   209  				case condition.Reason == "False":
   210  					nodeStatus = "NotReady"
   211  				default:
   212  					nodeStatus = "Unknown"
   213  				}
   214  			}
   215  		}
   216  		nodeString := fmt.Sprintf("%-50s %s", node.ObjectMeta.Name, nodeStatus)
   217  		nodeList = append(nodeList, nodeString)
   218  	}
   219  	return nodeList, nil
   220  }