From 4f006d209e0ffb6bf9c27b1ccf827e6ed115e935 Mon Sep 17 00:00:00 2001 From: Kavin Date: Sat, 4 Nov 2023 19:37:55 +0530 Subject: [PATCH] feat: Support Karpenter nodes and nodepoolInfo grouping --- README.md | 2 +- pkg/cmd/nodepool/nodepool.go | 38 ++++++++++++++++-------------------- pkg/constants.go | 7 ++++--- pkg/outputs/table.go | 8 ++++++-- pkg/types.go | 2 +- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 64c3907..a6de6f0 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Nodepool related information - Node list - Topology info (Region & Zone) - Instance type - - Nodepool provider (supported: EKS/AKS/GKE) + - Nodepool provider (supported: EKS/AKS/GKE/Karpenter)

Nodegizmo node

##### nodegizmo node exec nodeName diff --git a/pkg/cmd/nodepool/nodepool.go b/pkg/cmd/nodepool/nodepool.go index db0a353..f6f6bc8 100644 --- a/pkg/cmd/nodepool/nodepool.go +++ b/pkg/cmd/nodepool/nodepool.go @@ -2,7 +2,6 @@ package nodepool import ( "context" - "strings" "github.com/Kavinraja-G/node-gizmo/pkg/outputs" "github.com/Kavinraja-G/node-gizmo/utils" @@ -32,7 +31,7 @@ func NewCmdNodepoolInfo() *cobra.Command { // showNodePoolInfo driver function for the 'nodepool' command func showNodePoolInfo(cmd *cobra.Command, args []string) error { - var genericNodepoolInfos = make(map[string]pkg.GenericNodepoolInfo) + var genericNodepoolInfos []pkg.GenericNodepoolInfo nodes, err := utils.Cfg.Clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) if err != nil { @@ -40,23 +39,17 @@ func showNodePoolInfo(cmd *cobra.Command, args []string) error { } for _, node := range nodes.Items { - var genericNodepoolInfo pkg.GenericNodepoolInfo - cloudProvider, nodepoolID := getNodepoolIDAndProvider(node.Labels) - if _, ok := genericNodepoolInfos[nodepoolID]; !ok { - genericNodepoolInfo.NodepoolID = nodepoolID - genericNodepoolInfo.Nodes = append(genericNodepoolInfo.Nodes, node.Name) - genericNodepoolInfo.Provider = cloudProvider - genericNodepoolInfo.InstanceType = getNodeInstanceType(node.Labels) - genericNodepoolInfo.Region, genericNodepoolInfo.Zone = pkg.GetNodeTopologyInfo(node.Labels) - - // finally add the genericNodepoolInfo data to the genericNodepoolInfos - genericNodepoolInfos[nodepoolID] = genericNodepoolInfo - } else { - var currentNodepoolInfo = genericNodepoolInfos[nodepoolID] - currentNodepoolInfo.Nodes = append(currentNodepoolInfo.Nodes, node.Name) - genericNodepoolInfos[nodepoolID] = currentNodepoolInfo - } + region, zone := pkg.GetNodeTopologyInfo(node.Labels) + + genericNodepoolInfos = append(genericNodepoolInfos, pkg.GenericNodepoolInfo{ + NodepoolID: nodepoolID, + Node: node.Name, + Provider: cloudProvider, + InstanceType: getNodeInstanceType(node.Labels), + Region: region, + Zone: zone, + }) } outputHeaders, outputData := generateNodepoolInfoData(genericNodepoolInfos) @@ -66,7 +59,7 @@ func showNodePoolInfo(cmd *cobra.Command, args []string) error { return nil } -// getNodepoolIDAndProvider returns the cloud provider type for the nodepool (EKS, GKE, AKS, can be Unknown) +// getNodepoolIDAndProvider returns the cloud provider type for the nodepool (EKS/Karpenter, GKE, AKS, can be Unknown) func getNodepoolIDAndProvider(labels map[string]string) (string, string) { if id, ok := labels[pkg.AwsNodepoolLabel]; ok { return "EKS", id @@ -77,6 +70,9 @@ func getNodepoolIDAndProvider(labels map[string]string) (string, string) { if id, ok := labels[pkg.AksNodepoolLabel]; ok { return "AKS", id } + if id, ok := labels[pkg.KarpenterNodepool]; ok { + return "Karpenter", id + } return "Unknown", "Unknown" } @@ -91,7 +87,7 @@ func getNodeInstanceType(labels map[string]string) string { } // generateNodepoolInfoData generates the Nodepool info outputs and the required headers for table-writer -func generateNodepoolInfoData(genericNodepoolInfos map[string]pkg.GenericNodepoolInfo) ([]string, [][]string) { +func generateNodepoolInfoData(genericNodepoolInfos []pkg.GenericNodepoolInfo) ([]string, [][]string) { var headers = []string{"NODEPOOL", "PROVIDER", "REGION", "ZONE", "INSTANCE-TYPE", "NODES"} var outputData [][]string @@ -102,7 +98,7 @@ func generateNodepoolInfoData(genericNodepoolInfos map[string]pkg.GenericNodepoo nodepoolInfo.Region, nodepoolInfo.Zone, nodepoolInfo.InstanceType, - strings.Join(nodepoolInfo.Nodes, "\n"), + nodepoolInfo.Node, } outputData = append(outputData, lineItems) diff --git a/pkg/constants.go b/pkg/constants.go index d81c6cf..8127205 100644 --- a/pkg/constants.go +++ b/pkg/constants.go @@ -2,9 +2,10 @@ package pkg // required constants used across the CLI commands (mostly well-known labels, annotations etc.,) const ( - AwsNodepoolLabel = "eks.amazonaws.com/nodegroup" - GkeNodepoolLabel = "cloud.google.com/gke-nodepool" - AksNodepoolLabel = "kubernetes.azure.com/agentpool" + AwsNodepoolLabel = "eks.amazonaws.com/nodegroup" + GkeNodepoolLabel = "cloud.google.com/gke-nodepool" + AksNodepoolLabel = "kubernetes.azure.com/agentpool" + KarpenterNodepool = "karpenter.sh/provisioner-name" NodeInstanceTypeLabel = "node.kubernetes.io/instance-type" TopologyRegionLabel = "topology.kubernetes.io/region" diff --git a/pkg/outputs/table.go b/pkg/outputs/table.go index 4b2ce0d..5f189e5 100644 --- a/pkg/outputs/table.go +++ b/pkg/outputs/table.go @@ -10,7 +10,12 @@ import ( func TableOutput(headers []string, outputData [][]string) { table := tablewriter.NewWriter(os.Stdout) - // misc configs for the table-writer + // enables autoMerge only for nodepool infos + if headers[0] == "NODEPOOL" { + table.SetAutoMergeCells(true) + } + + // default configs for the table-writer table.SetRowLine(false) table.SetBorder(false) table.SetAutoWrapText(false) @@ -23,7 +28,6 @@ func TableOutput(headers []string, outputData [][]string) { table.SetColumnSeparator("") table.SetRowSeparator("") table.SetTablePadding("\t") - table.SetNoWhiteSpace(true) // set headers and add the outputData table.SetHeader(headers) diff --git a/pkg/types.go b/pkg/types.go index 2bc92f7..fa4ae78 100644 --- a/pkg/types.go +++ b/pkg/types.go @@ -35,7 +35,7 @@ type NodeCapacities struct { // GenericNodepoolInfo required node pool info which is used 'nodepool' command type GenericNodepoolInfo struct { NodepoolID string - Nodes []string + Node string Provider string InstanceType string Region string