Skip to content

Commit

Permalink
agent: api: rest: Add Kubernetes information
Browse files Browse the repository at this point in the history
  • Loading branch information
taking committed Sep 6, 2024
1 parent 94096ff commit a263d89
Show file tree
Hide file tree
Showing 15 changed files with 645 additions and 12 deletions.
26 changes: 26 additions & 0 deletions agent/driver/kubernetes/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package infra

import (
"os"
"path/filepath"

"k8s.io/client-go/kubernetes"
// "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

func GetClientSet() (*kubernetes.Clientset, error) {

configPath := filepath.Join(os.Getenv("HOME"), ".kube", "config")
config, err := clientcmd.BuildConfigFromFlags("", configPath)
if err != nil {
panic(err.Error())
}

clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}

return clientset, nil
}
34 changes: 34 additions & 0 deletions agent/driver/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package infra

import (
"errors"
"sync"

"github.com/cloud-barista/cm-honeybee/agent/pkg/api/rest/model/onprem/kubernetes"
)

var kubernetesInfoLock sync.Mutex

func GetKubernetesInfo() (*kubernetes.Kubernetes, error) {
if !kubernetesInfoLock.TryLock() {
return nil, errors.New("kubernetes info collection is in progress")
}
defer func() {
kubernetesInfoLock.Unlock()
}()

var i kubernetes.Kubernetes
var err error

i.Nodes, err = GetNodeInfo()
if err != nil {
return nil, err
}

i.Workloads, err = GetWorkloadInfo()
if err != nil {
return nil, err
}

return &i, nil
}
49 changes: 49 additions & 0 deletions agent/driver/kubernetes/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package infra

import (
"context"
"fmt"

"github.com/cloud-barista/cm-honeybee/agent/pkg/api/rest/common"
"github.com/cloud-barista/cm-honeybee/agent/pkg/api/rest/model/onprem/kubernetes"

"github.com/jollaman999/utils/logger"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func GetNodeInfo() ([]kubernetes.Node, error) {
clientset, err := GetClientSet()
if err != nil {
logger.Println(logger.ERROR, true, "Kubernetes Connection Error: "+err.Error())
return []kubernetes.Node{}, err
}

objects, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
if err != nil {
logger.Println(logger.ERROR, true, "Nodes: "+err.Error())
return []kubernetes.Node{}, err
}

nodeMap, err := common.Unmarshal(objects)
if err != nil {
logger.Println(logger.ERROR, true, "Error unmarshaling nodes: "+err.Error())
return []kubernetes.Node{}, err
}

ObjectCnt := len(objects.Items)

var nodes []kubernetes.Node

for i := 0; i < ObjectCnt; i++ {
node := kubernetes.Node{
Name: common.GoJq(nodeMap, fmt.Sprintf(".items[%d].metadata.name", i)),
Labels: common.GoJq(nodeMap, fmt.Sprintf(".items[%d].metadata.labels", i)),
Addresses: common.GoJq(nodeMap, fmt.Sprintf(".items[%d].status.addresses[]", i)),
NodeInfo: common.GoJq(nodeMap, fmt.Sprintf(".items[%d].status.nodeInfo", i)),
}
nodes = append(nodes, node)
}

return nodes, nil
}
163 changes: 163 additions & 0 deletions agent/driver/kubernetes/workload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package infra

import (
"context"
"fmt"
"reflect"
"strings"

"github.com/cloud-barista/cm-honeybee/agent/pkg/api/rest/common"

"github.com/jollaman999/utils/logger"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var kindList = []string{
"namespaces",
"pods",
"services",
"deployments",
"daemonsets",
"replicasets",
"statefulsets",
"job",
"cronjobs",
"ingresses",
"persistentvolumes",
"persistentvolumeclaims",
"storageclasses",
"configmaps",
"servicesaccounts",
"secrets",
"roles",
"rolebindings",
"clusterroles",
"clusterrolebindings",
}

var clientFilter = map[string]string{
"namespaces": "CoreV1.Namespaces",
"pods": "CoreV1.Pods.\"\"",
"services": "CoreV1.Services.\"\"",
"configmaps": "CoreV1.ConfigMaps.\"\"",
"servicesaccounts": "CoreV1.ServiceAccounts.\"\"",
"secrets": "CoreV1.Secrets.\"\"",
"persistentvolumes": "CoreV1.PersistentVolumes",
"persistentvolumeclaims": "CoreV1.PersistentVolumeClaims.\"\"",
"deployments": "AppsV1.Deployments.\"\"",
"daemonsets": "AppsV1.DaemonSets.\"\"",
"replicasets": "AppsV1.ReplicaSets.\"\"",
"statefulsets": "AppsV1.StatefulSets.\"\"",
"job": "BatchV1.Jobs.\"\"",
"cronjobs": "BatchV1.CronJobs.\"\"",
"ingresses": "NetworkingV1.Ingresses.\"\"",
"storageclasses": "StorageV1.StorageClasses",
}

func GetWorkloadInfo() (map[string]interface{}, error) {
workloads := make(map[string]interface{})

for _, kind := range kindList {
if clientMethod, exists := clientFilter[kind]; exists {
objects, err := callClientMethod(clientMethod)
if err != nil {
logger.Println(logger.ERROR, true, fmt.Sprintf("Error fetching %s: %s", kind, err.Error()))
continue
}

processObjects(kind, objects, workloads)
}
}

return workloads, nil
}

func callClientMethod(methodName string) (interface{}, error) {
clientset, err := GetClientSet()
if err != nil {
logger.Println(logger.ERROR, true, "Kubernetes Connection Error: "+err.Error())
return nil, err
}

methods := strings.Split(methodName, ".")
var result reflect.Value = reflect.ValueOf(clientset)

for _, method := range methods {
if method == "\"\"" {
// 빈 문자열 인자로 메소드 호출
result = result.Call([]reflect.Value{reflect.ValueOf("")})[0]
} else {
result = result.MethodByName(method)
if !result.IsValid() {
return nil, fmt.Errorf("invalid method: %s in %s", method, methodName)
}
if result.Type().NumIn() == 0 {
result = result.Call(nil)[0]
}
}
}

listMethod := result.MethodByName("List")
if !listMethod.IsValid() {
return nil, fmt.Errorf("invalid List method for: %s", methodName)
}

results := listMethod.Call([]reflect.Value{
reflect.ValueOf(context.TODO()),
reflect.ValueOf(metav1.ListOptions{}),
})

if len(results) != 2 {
return nil, fmt.Errorf("unexpected number of return values")
}

if !results[1].IsNil() {
return nil, results[1].Interface().(error)
}

return results[0].Interface(), nil
}

func processObjects(kind string, objects interface{}, workloads map[string]interface{}) {

objectMap, err := common.Unmarshal(objects)
if err != nil {
logger.Println(logger.ERROR, true, fmt.Sprintf("Error unmarshaling %s: %s", kind, err.Error()))
return
}

items := common.GoJq(objectMap, ".items")
objectCnt := 0
if itemsSlice, ok := items.([]interface{}); ok {
objectCnt = len(itemsSlice)
}

var newStruct []map[string]interface{}

for i := 0; i < objectCnt; i++ {
item := make(map[string]interface{})

if namespace := common.GoJq(objectMap, fmt.Sprintf(".items[%d].metadata.namespace", i)); namespace != nil {
item["Namespace"] = namespace
}
if name := common.GoJq(objectMap, fmt.Sprintf(".items[%d].metadata.name", i)); name != nil {
item["Name"] = name
}
if svcType := common.GoJq(objectMap, fmt.Sprintf(".items[%d].spec.type", i)); svcType != nil {
item["Type"] = svcType
}
if svcClusterIp := common.GoJq(objectMap, fmt.Sprintf(".items[%d].spec.clusterIP", i)); svcClusterIp != nil {
item["ClusterIP"] = svcClusterIp
}
if status := common.GoJq(objectMap, fmt.Sprintf(".items[%d].status.phase", i)); status != nil {
item["Status"] = status
}

if len(item) > 0 {
newStruct = append(newStruct, item)
}
}

workloads[kind] = newStruct
}
29 changes: 29 additions & 0 deletions agent/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ require (
require (
github.com/cavaliergopher/rpm v1.2.0
github.com/coreos/go-iptables v0.8.0
github.com/itchyny/gojq v0.12.16
github.com/jaypipes/ghw v0.12.0
github.com/knqyf263/go-rpmdb v0.1.1
github.com/kumako/go-win64api v0.0.0-20200829071356-ddc2195639e5
github.com/swaggo/echo-swagger v1.4.1
github.com/swaggo/swag v1.16.3
github.com/taigrr/systemctl v1.0.7
github.com/ulikunitz/xz v0.5.12
k8s.io/apimachinery v0.31.0
k8s.io/client-go v0.31.0
)

require (
Expand All @@ -34,12 +37,15 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
Expand All @@ -50,9 +56,16 @@ require (
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jaypipes/pcidb v1.0.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
Expand All @@ -61,7 +74,10 @@ require (
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
Expand All @@ -70,11 +86,13 @@ require (
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/swaggo/files/v2 v2.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
Expand All @@ -84,17 +102,28 @@ require (
go.opentelemetry.io/otel/trace v1.29.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.5.1 // indirect
howett.net/plist v1.0.1 // indirect
k8s.io/api v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
modernc.org/libc v1.60.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.32.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

replace github.com/knqyf263/go-rpmdb v0.0.0-facee9e1ddaf => ./go-rpmdb
Loading

0 comments on commit a263d89

Please sign in to comment.