diff --git a/client/client.go b/client/client.go index bfd62c3..1b0b8d6 100644 --- a/client/client.go +++ b/client/client.go @@ -2,6 +2,7 @@ package client import ( "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -15,40 +16,33 @@ type Args struct { KubeConfig string } -func createClient(kubeconfig string) (*kubernetes.Clientset, error) { - config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) +func Run(args *Args) error { + config, err := clientcmd.BuildConfigFromFlags("", args.KubeConfig) if err != nil { - return nil, fmt.Errorf("failed to get kubeconfig: %v", err) + return fmt.Errorf("failed to get kubeconfig: %v", err) } - - clientset, err := kubernetes.NewForConfig(config) + metricsResponse, err := FetchMetrics(config, args.Namespace) if err != nil { - return nil, err + return fmt.Errorf("failed to fetch metrics: %v", err) } - return clientset, nil -} - -type Resource struct { - Request int - Limit int - Usage int -} + podResponse, err := FetchPods(config, args.Namespace) + if err != nil { + return fmt.Errorf("failed to fetch pod: %v", err) + } -type ContainerResource struct { - Cpu *Resource - Memory *Resource -} + resources, err := MergePodResources(metricsResponse, podResponse) + if err != nil { + return fmt.Errorf("failed to merge responses: %v", err) + } -type PodResource struct { - Name string - Namespace string - Node string - Containers map[string]*ContainerResource + if err := Write(resources, args); err != nil { + return fmt.Errorf("faild to write: %v", err) + } + return nil } func FetchMetrics(cfg *rest.Config, ns string) (map[string]*PodResource, error) { - metricsclient, err := metrics.NewForConfig(cfg) if err != nil { return nil, fmt.Errorf("failed to create metrics client: %v", err) @@ -81,11 +75,8 @@ func FetchMetrics(cfg *rest.Config, ns string) (map[string]*PodResource, error) } } } - return res, nil -} -func uid(name, ns string) string { - return name + "~" + ns + return res, nil } func FetchPods(cfg *rest.Config, ns string) (map[string]*PodResource, error) { @@ -124,86 +115,10 @@ func FetchPods(cfg *rest.Config, ns string) (map[string]*PodResource, error) { } } } - return res, nil -} -func Run(args *Args) error { - config, err := clientcmd.BuildConfigFromFlags("", args.KubeConfig) - if err != nil { - return fmt.Errorf("failed to get kubeconfig: %v", err) - } - metricsResponse, err := FetchMetrics(config, args.Namespace) - if err != nil { - return fmt.Errorf("failed to fetch metrics: %v", err) - } - - podResponse, err := FetchPods(config, args.Namespace) - if err != nil { - return fmt.Errorf("failed to fetch pod: %v", err) - } - - resources, err := MergePodResources(metricsResponse, podResponse) - if err != nil { - return fmt.Errorf("failed to merge responses: %v", err) - } - - if err := Write(resources); err != nil { - return fmt.Errorf("faild to write: %v", err) - } - return nil + return res, nil } -func MergePodResources(resources ...map[string]*PodResource) (map[string]*PodResource, error) { - merged := map[string]*PodResource{} - for _, resource := range resources { - for key, pod := range resource { - if merged[key] != nil { - if merged[key].Name != pod.Name { - return nil, fmt.Errorf("attempted to merge pods with mismatched names %v %v", merged[key].Name, pod.Name) - } - if merged[key].Namespace != pod.Namespace { - return nil, fmt.Errorf("attempted to merge pods with mismatched namespace %v %v", merged[key].Namespace, pod.Namespace) - } - } else { - merged[key] = &PodResource{ - Name: pod.Name, - Namespace: pod.Namespace, - Containers: make(map[string]*ContainerResource), - } - } - - if pod.Node != "" { - merged[key].Node = pod.Node - } - - for containerName, container := range pod.Containers { - if merged[key].Containers[containerName] == nil { - merged[key].Containers[containerName] = &ContainerResource{ - Memory: &Resource{}, - Cpu: &Resource{}, - } - } - c := merged[key].Containers[containerName] - if container.Memory.Request != 0 { - c.Memory.Request = container.Memory.Request - } - if container.Memory.Limit != 0 { - c.Memory.Limit = container.Memory.Limit - } - if container.Memory.Usage != 0 { - c.Memory.Usage = container.Memory.Usage - } - if container.Cpu.Request != 0 { - c.Cpu.Request = container.Cpu.Request - } - if container.Cpu.Limit != 0 { - c.Cpu.Limit = container.Cpu.Limit - } - if container.Cpu.Usage != 0 { - c.Cpu.Usage = container.Cpu.Usage - } - } - } - } - return merged, nil +func uid(name, ns string) string { + return name + "~" + ns } diff --git a/client/podresource.go b/client/podresource.go new file mode 100644 index 0000000..93cd283 --- /dev/null +++ b/client/podresource.go @@ -0,0 +1,76 @@ +package client + +import "fmt" + +type Resource struct { + Request int + Limit int + Usage int +} + +type ContainerResource struct { + Cpu *Resource + Memory *Resource +} + +type PodResource struct { + Name string + Namespace string + Node string + Containers map[string]*ContainerResource +} + +func MergePodResources(resources ...map[string]*PodResource) (map[string]*PodResource, error) { + merged := map[string]*PodResource{} + for _, resource := range resources { + for key, pod := range resource { + if merged[key] != nil { + if merged[key].Name != pod.Name { + return nil, fmt.Errorf("attempted to merge pods with mismatched names %v %v", merged[key].Name, pod.Name) + } + if merged[key].Namespace != pod.Namespace { + return nil, fmt.Errorf("attempted to merge pods with mismatched namespace %v %v", merged[key].Namespace, pod.Namespace) + } + } else { + merged[key] = &PodResource{ + Name: pod.Name, + Namespace: pod.Namespace, + Containers: make(map[string]*ContainerResource), + } + } + + if pod.Node != "" { + merged[key].Node = pod.Node + } + + for containerName, container := range pod.Containers { + if merged[key].Containers[containerName] == nil { + merged[key].Containers[containerName] = &ContainerResource{ + Memory: &Resource{}, + Cpu: &Resource{}, + } + } + c := merged[key].Containers[containerName] + if container.Memory.Request != 0 { + c.Memory.Request = container.Memory.Request + } + if container.Memory.Limit != 0 { + c.Memory.Limit = container.Memory.Limit + } + if container.Memory.Usage != 0 { + c.Memory.Usage = container.Memory.Usage + } + if container.Cpu.Request != 0 { + c.Cpu.Request = container.Cpu.Request + } + if container.Cpu.Limit != 0 { + c.Cpu.Limit = container.Cpu.Limit + } + if container.Cpu.Usage != 0 { + c.Cpu.Usage = container.Cpu.Usage + } + } + } + } + return merged, nil +} diff --git a/client/writer.go b/client/writer.go index 55f311f..e643b27 100644 --- a/client/writer.go +++ b/client/writer.go @@ -1,6 +1,7 @@ package client import ( + "fmt" "io" "os" "sort" @@ -23,7 +24,7 @@ func sortPodResources(res []*PodResource) { }) } -func Write(response map[string]*PodResource) error { +func Write(response map[string]*PodResource, args *Args) error { resources := make([]*PodResource, 0, len(response)) for _, res := range response { resources = append(resources, res) @@ -31,17 +32,29 @@ func Write(response map[string]*PodResource) error { sortPodResources(resources) w := getNewTabWriter(os.Stdout) - if _, err := w.Write([]byte("NAME\tNAMESPACE\tNODE\n")); err != nil { - return err + if _, err := w.Write([]byte(formatHeader(args))); err != nil { + return fmt.Errorf("write failed: %v", err) } - for _, pod := range resources { - if _, err := w.Write([]byte(pod.Name + "\t" + pod.Namespace + "\t" + pod.Node + "\n")); err != nil { - return err + for _, res := range resources { + row := formatRow(res, args) + if _, err := w.Write([]byte(row)); err != nil { + return fmt.Errorf("write failed: %v", err) } } + return w.Flush() } +func formatHeader(args *Args) string { + // TODO + return "NAME" +} + +func formatRow(resource *PodResource, args *Args) string { + // TODO + return resource.Name + "\n" +} + // GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text. func getNewTabWriter(output io.Writer) *tabwriter.Writer { return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, 0)