makocchi-git/kubectl-free

View on GitHub
pkg/util/util.go

Summary

Maintainability
A
0 mins
Test Coverage
package util

import (
    "fmt"
    "strings"

    color "github.com/gookit/color"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    clientv1 "k8s.io/client-go/kubernetes/typed/core/v1"
    metricsapiv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"

    "github.com/makocchi-git/kubectl-free/pkg/constants"
)

// GetSiUnit defines unit for usage (SI prefix)
// If multiple options are selected, returns a biggest unit
func GetSiUnit(b, k, m, g bool) (int64, string) {

    if g {
        return constants.UnitGigaBytes, constants.UnitGigaBytesStr
    }

    if m {
        return constants.UnitMegaBytes, constants.UnitMegaBytesStr
    }

    if k {
        return constants.UnitKiloBytes, constants.UnitKiloBytesStr
    }

    if b {
        return constants.UnitBytes, constants.UnitBytesStr
    }

    // default output is "kilobytes"
    return constants.UnitKiloBytes, constants.UnitKiloBytesStr
}

// GetBinUnit defines unit for usage (Binary prefix)
// If multiple options are selected, returns a biggest unit
func GetBinUnit(b, k, m, g bool) (int64, string) {

    if g {
        return constants.UnitGibiBytes, constants.UnitGibiBytesStr
    }

    if m {
        return constants.UnitMibiBytes, constants.UnitMibiBytesStr
    }

    if k {
        return constants.UnitKibiBytes, constants.UnitKibiBytesStr
    }

    if b {
        return constants.UnitBytes, constants.UnitBytesStr
    }

    // default output is "kibibytes"
    return constants.UnitKibiBytes, constants.UnitKibiBytesStr
}

// JoinTab joins string slice with tab
func JoinTab(s []string) string {
    return strings.Join(s, "\t")
}

// SetPercentageColor returns colored string
//        percentage < warn : Green
// warn < percentage < crit : Yellow
// crit < percentage        : Red
func SetPercentageColor(s *string, p, warn, crit int64) {
    green := color.FgGreen.Render
    yellow := color.FgYellow.Render
    red := color.FgRed.Render

    if p < warn {
        *s = green(*s)
        return
    }

    if p < crit {
        *s = yellow(*s)
        return
    }

    *s = red(*s)
}

// SetNodeStatusColor defined color of node status
func SetNodeStatusColor(status *string, nocolor bool) {

    if nocolor {
        // nothing to do
        return
    }

    if *status != "Ready" {
        // Red
        *status = color.FgRed.Render(*status)
        return
    }

    // Green
    *status = color.FgGreen.Render(*status)

}

// GetPodStatus defined pod status with color
func GetPodStatus(status string, nocolor, emoji bool) string {

    var s string

    switch status {
    case string(v1.PodRunning):
        if emoji {
            s = constants.EmojiPodRunning
        } else {
            s = string(v1.PodRunning)
        }

        if !nocolor {
            Green(&s)
        }
    case string(v1.PodSucceeded):
        if emoji {
            s = constants.EmojiPodSucceeded
        } else {
            s = string(v1.PodSucceeded)
        }

        if !nocolor {
            Green(&s)
        }
    case string(v1.PodPending):
        if emoji {
            s = constants.EmojiPodPending
        } else {
            s = string(v1.PodPending)
        }

        if !nocolor {
            Yellow(&s)
        }
    case string(v1.PodFailed):
        if emoji {
            s = constants.EmojiPodFailed
        } else {
            s = string(v1.PodFailed)
        }

        if !nocolor {
            Red(&s)
        }
    default:
        if emoji {
            s = constants.EmojiPodUnknown
        } else {
            s = "Unknown"
        }

        if !nocolor {
            DefaultColor(&s)
        }
    }

    return s
}

// GetNodes returns node objects
func GetNodes(c clientv1.NodeInterface, args []string, label string) ([]v1.Node, error) {
    nodes := []v1.Node{}

    if len(args) > 0 {
        for _, a := range args {
            n, nerr := c.Get(a, metav1.GetOptions{})
            if nerr != nil {
                return nodes, fmt.Errorf("failed to get node: %v", nerr)
            }
            nodes = append(nodes, *n)
        }
    } else {
        na, naerr := c.List(metav1.ListOptions{LabelSelector: label})
        if naerr != nil {
            return nodes, fmt.Errorf("failed to list nodes: %v", naerr)
        }
        nodes = append(nodes, na.Items...)
    }

    return nodes, nil
}

// GetNodeStatus returns node status
func GetNodeStatus(node v1.Node, emoji bool) (string, error) {
    status := "NotReady"

    for _, condition := range node.Status.Conditions {
        if condition.Type == v1.NodeReady && condition.Status == v1.ConditionTrue {
            status = "Ready"
        }
    }

    if emoji {
        switch status {
        case "Ready":
            status = constants.EmojiReady
        case "NotReady":
            status = constants.EmojiNotReady
        }
    }

    return status, nil
}

// GetPods returns node objects
func GetPods(c clientv1.PodInterface, nodeName string) (*v1.PodList, error) {

    pods, err := c.List(metav1.ListOptions{FieldSelector: "spec.nodeName=" + nodeName})
    if err != nil {
        return pods, fmt.Errorf("failed to get pods: %s", err)
    }

    return pods, nil
}

// GetContainerMetrics returns container metrics usage
func GetContainerMetrics(metrics *metricsapiv1beta1.PodMetricsList, podName, containerName string) (cpu, mem int64) {

    var c int64
    var m int64

    for _, pod := range metrics.Items {
        if pod.ObjectMeta.Name == podName {
            for _, container := range pod.Containers {
                if container.Name == containerName {
                    c = container.Usage.Cpu().MilliValue()
                    m = container.Usage.Memory().Value()
                    break
                }
            }
        }
    }

    // if no metrics found, return 0 0
    return c, m
}

// GetPodResources returns sum of requested/limit resources
func GetPodResources(pods v1.PodList) (int64, int64, int64, int64) {
    var rc, rm, lc, lm int64

    for _, pod := range pods.Items {

        // skip if pod status is not running
        if pod.Status.Phase != v1.PodRunning {
            continue
        }

        for _, container := range pod.Spec.Containers {
            rc += container.Resources.Requests.Cpu().MilliValue()
            lc += container.Resources.Limits.Cpu().MilliValue()
            rm += container.Resources.Requests.Memory().Value()
            lm += container.Resources.Limits.Memory().Value()
        }
    }

    return rc, rm, lc, lm
}

// GetPodCount returns count of pods
func GetPodCount(pods v1.PodList) int {
    return len(pods.Items)
}

// GetContainerCount returns count of containers
func GetContainerCount(pods v1.PodList) int {
    var c int
    for _, pod := range pods.Items {
        c += len(pod.Spec.Containers)
    }
    return c
}

// GetPercentage returns (a*100)/b
func GetPercentage(a, b int64) int64 {
    // avoid 0 divide
    if b == 0 {
        return 0
    }
    return (a * 100) / b
}

// DefaultColor set default color
func DefaultColor(s *string) {
    // add dummy escape code
    *s = color.FgDefault.Render(*s)
}

// Green is coloring string to green
func Green(s *string) {
    *s = color.FgGreen.Render(*s)
}

// Red is coloring string to red
func Red(s *string) {
    *s = color.FgRed.Render(*s)
}

// Yellow is coloring string to yellow
func Yellow(s *string) {
    *s = color.FgYellow.Render(*s)
}