cluster/cluster.go (123 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cluster
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
type ComputeClass int8
const (
ComputeClassGeneralPurpose ComputeClass = 0
ComputeClassBalanced ComputeClass = 1
ComputeClassScaleout ComputeClass = 2
ComputeClassScaleoutArm ComputeClass = 3
ComputeClassPerformance ComputeClass = 4
ComputeClassAccelerator ComputeClass = 5
ComputeClassGPUPod ComputeClass = 6
)
var ComputeClasses [7]string = [7]string{"General-purpose", "Balanced", "Scale-out", "Scale-out arm64", "Performance", "Accelerator", "GPU Pod"}
type Workload struct {
Name string
Node_name string
Containers int
Cpu int64
Memory int64
Storage int64
AcceleratorType string
AcceleratorAmount int64
Cost float64
ComputeClass ComputeClass
}
type Node struct {
Name string
Workloads []Workload
InstanceType string
Region string
Spot bool
Cost float64
Accelerator string
}
func GetKubeConfig() (*rest.Config, string, error) {
userHomeDir, err := os.UserHomeDir()
if err != nil {
err = fmt.Errorf("error getting user home dir: %v", err)
return nil, "", err
}
kubeConfigPath := filepath.Join(userHomeDir, ".kube", "config")
// log.Printf("Using kubeconfig: %s\n", kubeConfigPath)
kubeConfig, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)
if err != nil {
err = fmt.Errorf("error getting kubernetes config: %v", err)
return nil, "", err
}
return kubeConfig, kubeConfigPath, nil
}
func GetCurrentContext(kubeConfigPath string) ([]string, error) {
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeConfigPath},
&clientcmd.ConfigOverrides{
CurrentContext: "",
}).RawConfig()
if err != nil {
err = fmt.Errorf("error getting kubernetes current context: %v", err)
return nil, err
}
return strings.Split(config.CurrentContext, "_"), nil
}
func GetClusterNodes(clientset *kubernetes.Clientset) (map[string]Node, error) {
nodes := make(map[string]Node)
clusterNodes, err := ListNodes(clientset)
if err != nil {
err = fmt.Errorf("error getting nodes: %v", err)
return nil, err
}
for _, clusterNode := range clusterNodes.Items {
nodes[clusterNode.Name] = Node{
Name: clusterNode.Name,
Region: clusterNode.Labels["topology.kubernetes.io/region"],
Spot: clusterNode.Labels["cloud.google.com/gke-spot"] == "true",
Accelerator: clusterNode.Labels["cloud.google.com/gke-accelerator"],
InstanceType: clusterNode.Labels["beta.kubernetes.io/instance-type"]}
}
return nodes, nil
}
func ListPods(client kubernetes.Interface) (*v1.PodList, error) {
pods, err := client.CoreV1().Pods("").List(
context.Background(),
metav1.ListOptions{FieldSelector: "status.phase=Running,metadata.namespace!=kube-system,metadata.namespace!=gke-gmp-system"},
)
if err != nil {
err = fmt.Errorf("error getting pods: %v", err)
return nil, err
}
return pods, nil
}
func ListNamespaces(client kubernetes.Interface) (*v1.NamespaceList, error) {
namespaces, err := client.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
if err != nil {
err = fmt.Errorf("error getting namespaces: %v", err)
return nil, err
}
return namespaces, nil
}
func ListNodes(client kubernetes.Interface) (*v1.NodeList, error) {
nodes, err := client.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{})
if err != nil {
err = fmt.Errorf("error getting namespaces: %v", err)
return nil, err
}
return nodes, nil
}
func DescribePod(client kubernetes.Interface, podName string, namespace string) (*v1.Pod, error) {
pod, err := client.CoreV1().Pods(namespace).Get(context.Background(), podName, metav1.GetOptions{})
if err != nil {
err = fmt.Errorf("error getting pods: %v", err)
return nil, err
}
return pod, nil
}