Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement describe functionality via client-go apis. #120

Merged
merged 1 commit into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/aks-periscope/aks-periscope.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func main() {

networkOutboundCollector := collector.NewNetworkOutboundCollector()
dnsCollector := collector.NewDNSCollector()
kubeObjectsCollector := collector.NewKubeObjectsCollector()
kubeObjectsCollector := collector.NewKubeObjectsCollector(config)
systemLogsCollector := collector.NewSystemLogsCollector()
ipTablesCollector := collector.NewIPTablesCollector()
nodeLogsCollector := collector.NewNodeLogsCollector()
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
k8s.io/apimachinery v0.21.3
k8s.io/cli-runtime v0.21.3
k8s.io/client-go v0.21.3
k8s.io/kubectl v0.21.0 // indirect
k8s.io/metrics v0.21.0
rsc.io/letsencrypt v0.0.3 // indirect
)
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
Expand Down
46 changes: 28 additions & 18 deletions pkg/collector/kubeobjects_collector.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package collector

import (
"fmt"
"os"
"strings"

"github.com/Azure/aks-periscope/pkg/utils"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/describe"
)

// KubeObjectsCollector defines a KubeObjects Collector struct
type KubeObjectsCollector struct {
data map[string]string
kubeconfig *restclient.Config
data map[string]string
}

// NewKubeObjectsCollector is a constructor
func NewKubeObjectsCollector() *KubeObjectsCollector {
func NewKubeObjectsCollector(config *restclient.Config) *KubeObjectsCollector {
return &KubeObjectsCollector{
data: make(map[string]string),
data: make(map[string]string),
kubeconfig: config,
}
}

Expand All @@ -27,32 +33,36 @@ func (collector *KubeObjectsCollector) GetName() string {
func (collector *KubeObjectsCollector) Collect() error {
kubernetesObjects := strings.Fields(os.Getenv("DIAGNOSTIC_KUBEOBJECTS_LIST"))

// Creates the clientset
clientset, err := kubernetes.NewForConfig(collector.kubeconfig)
if err != nil {
return fmt.Errorf("getting access to K8S failed: %w", err)
}

for _, kubernetesObject := range kubernetesObjects {
kubernetesObjectParts := strings.Split(kubernetesObject, "/")
nameSpace := kubernetesObjectParts[0]
objectType := kubernetesObjectParts[1]
objects := []string{}
if len(kubernetesObjectParts) == 3 {
objects = append(objects, kubernetesObjectParts[2])
}

if len(objects) == 0 {
output, err := utils.RunCommandOnContainer("kubectl", "-n", nameSpace, "get", objectType, "--output=jsonpath={.items..metadata.name}")
if err != nil {
return err
}

objects = strings.Split(output, " ")
// List the pods in the given namespace
podList, err := utils.GetPods(clientset, nameSpace)
if err != nil {
return fmt.Errorf("getting pods failed: %w", err)
}

for _, object := range objects {
for _, pod := range podList.Items {
d := describe.PodDescriber{
Interface: clientset,
}

output, err := utils.RunCommandOnContainer("kubectl", "-n", nameSpace, "describe", objectType, object)
output, err := d.Describe(pod.Namespace, pod.Name, describe.DescriberSettings{
ShowEvents: true,
})
if err != nil {
return err
return fmt.Errorf("getting description failed: %w", err)
}

collector.data[nameSpace+"_"+objectType+"_"+object] = output
collector.data[pod.Namespace+"_"+objectType+"_"+pod.Name] = output
}
}

Expand Down
56 changes: 56 additions & 0 deletions pkg/collector/kubeobjects_collector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package collector

import (
"os"
"path"
"testing"

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

func TestNewKubeObjectsCollector(t *testing.T) {
tests := []struct {
name string
want int
wantErr bool
}{
{
name: "get kube objects logs",
want: 1,
wantErr: false,
},
}

dirname, err := os.UserHomeDir()
if err != nil {
t.Fatalf("Cannot get user home dir: %v", err)
}

master := ""
kubeconfig := path.Join(dirname, ".kube/config")
config, err := clientcmd.BuildConfigFromFlags(master, kubeconfig)
if err != nil {
t.Fatalf("Cannot load kube config: %v", err)
}

c := NewKubeObjectsCollector(config)

if err := os.Setenv("DIAGNOSTIC_KUBEOBJECTS_LIST", "kube-system/pod kube-system/service kube-system/deployment"); err != nil {
t.Fatalf("Setenv: %v", err)
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := c.Collect()

if (err != nil) != tt.wantErr {
t.Errorf("Collect() error = %v, wantErr %v", err, tt.wantErr)
}
raw := c.GetData()

if len(raw) < tt.want {
t.Errorf("len(GetData()) = %v, want %v", len(raw), tt.want)
}
})
}
}
18 changes: 2 additions & 16 deletions pkg/collector/pods_containerlogs_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"strings"
"time"

"github.com/Azure/aks-periscope/pkg/utils"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
)
Expand Down Expand Up @@ -55,7 +55,7 @@ func (collector *PodsContainerLogsCollector) Collect() error {

for _, namespace := range containerNamespaces {
// List the pods in the given namespace
podList, err := getPods(clientset, namespace)
podList, err := utils.GetPods(clientset, namespace)

if err != nil {
return fmt.Errorf("getting pods failed: %w", err)
Expand Down Expand Up @@ -116,20 +116,6 @@ func (collector *PodsContainerLogsCollector) GetData() map[string]string {
return collector.data
}

func getPods(clientset *kubernetes.Clientset, namespace string) (*v1.PodList, error) {
// Create a pod interface for the given namespace
podInterface := clientset.CoreV1().Pods(namespace)

// List the pods in the given namespace
podList, err := podInterface.List(context.TODO(), metav1.ListOptions{})

if err != nil {
return nil, fmt.Errorf("getting pods failed: %w", err)
}

return podList, nil
}

func getPodContainerLogs(
namespace string,
podName string,
Expand Down
19 changes: 19 additions & 0 deletions pkg/utils/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
Expand All @@ -13,6 +14,10 @@ import (
"strings"
"sync"
"time"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

const (
Expand Down Expand Up @@ -348,3 +353,17 @@ func ReadFileContent(filename string) (string, error) {

return string(b), nil
}

func GetPods(clientset *kubernetes.Clientset, namespace string) (*v1.PodList, error) {
// Create a pod interface for the given namespace
podInterface := clientset.CoreV1().Pods(namespace)

// List the pods in the given namespace
podList, err := podInterface.List(context.TODO(), metav1.ListOptions{})

if err != nil {
return nil, fmt.Errorf("getting pods failed: %w", err)
}

return podList, nil
}