Skip to content

Commit 4fcf927

Browse files
authored
Merge pull request #4 from nginxinc/helm-client
Feat: add Cobra parameters and create supportpkg tarball
2 parents fe3e9c0 + 1cb8fa9 commit 4fcf927

File tree

6 files changed

+222
-96
lines changed

6 files changed

+222
-96
lines changed

cmd/kic-supportpkg.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"github.com/nginxinc/kubectl-kic-supportpkg/pkg/data_collector"
6+
"github.com/nginxinc/kubectl-kic-supportpkg/pkg/jobs"
7+
"github.com/spf13/cobra"
8+
"os"
9+
)
10+
11+
func Execute() {
12+
13+
var namespaces []string
14+
15+
var rootCmd = &cobra.Command{
16+
Use: "kic-supportpkg",
17+
Short: "kic-supportpkg - a tool to create Ingress Controller diagnostics package",
18+
Long: `kic-supportpkg - a tool to create Ingress Controller diagnostics package`,
19+
Run: func(cmd *cobra.Command, args []string) {
20+
21+
collector, err := data_collector.NewDataCollector(namespaces...)
22+
if err != nil {
23+
fmt.Println(fmt.Errorf("unable to start data collector: %s", err))
24+
os.Exit(1)
25+
}
26+
27+
for _, job := range jobs.JobList() {
28+
fmt.Printf("Running job %s...", job.Name)
29+
err = job.Collect(collector)
30+
if err != nil {
31+
fmt.Printf("Error: %s", err)
32+
} else {
33+
fmt.Print(" OK\n")
34+
}
35+
}
36+
37+
err = collector.WrapUp()
38+
if err != nil {
39+
fmt.Println(fmt.Errorf("error when wrapping up: %s", err))
40+
os.Exit(1)
41+
}
42+
},
43+
}
44+
45+
rootCmd.Flags().StringSliceVarP(&namespaces, "namespace", "n", []string{}, "comma-separated list of namespaces to collect information from")
46+
rootCmd.SetUsageTemplate("Usage: \n kic-supportpkg -n namespace1 -n namespace2 ...")
47+
48+
if err := rootCmd.Execute(); err != nil {
49+
fmt.Println(err)
50+
os.Exit(1)
51+
}
52+
}

internal/data_collector/data_collector.go

Lines changed: 0 additions & 49 deletions
This file was deleted.

main.go

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,9 @@
11
package main
22

33
import (
4-
"fmt"
5-
"github.com/nginxinc/kubectl-kic-supportpkg/internal/data_collector"
6-
"github.com/nginxinc/kubectl-kic-supportpkg/internal/jobs"
7-
"k8s.io/client-go/tools/clientcmd"
8-
"k8s.io/client-go/util/homedir"
9-
"path/filepath"
4+
"github.com/nginxinc/kubectl-kic-supportpkg/cmd"
105
)
116

127
func main() {
13-
14-
home := homedir.HomeDir()
15-
kubeConfig := filepath.Join(home, ".kube", "config")
16-
config, err := clientcmd.BuildConfigFromFlags("", kubeConfig)
17-
18-
namespaces := []string{"nginx-ingress-0", "observability"}
19-
20-
collector := data_collector.NewDataCollector(config, namespaces...)
21-
22-
if err != nil {
23-
panic(err.Error())
24-
}
25-
26-
for _, job := range jobs.JobList() {
27-
fmt.Printf("Running %s and collecting the output in %s...\n", job.Name, collector.BaseDir)
28-
job.Collect(collector)
29-
}
30-
31-
//collector.WrapUp()
32-
8+
cmd.Execute()
339
}

pkg/data_collector/data_collector.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package data_collector
2+
3+
import (
4+
"archive/tar"
5+
"compress/gzip"
6+
"fmt"
7+
helmClient "github.com/mittwald/go-helm-client"
8+
"io"
9+
crdClient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
10+
"k8s.io/client-go/kubernetes"
11+
"k8s.io/client-go/tools/clientcmd"
12+
"k8s.io/client-go/util/homedir"
13+
metricsClient "k8s.io/metrics/pkg/client/clientset/versioned"
14+
"os"
15+
"path/filepath"
16+
"strconv"
17+
"time"
18+
)
19+
20+
type DataCollector struct {
21+
BaseDir string
22+
Namespaces []string
23+
K8sCoreClientSet *kubernetes.Clientset
24+
K8sCrdClientSet *crdClient.Clientset
25+
K8sMetricsClientSet *metricsClient.Clientset
26+
K8sHelmClientSet map[string]helmClient.Client
27+
}
28+
29+
func NewDataCollector(namespaces ...string) (*DataCollector, error) {
30+
31+
tmpDir, err := os.MkdirTemp("", "kic-diag")
32+
33+
if err != nil {
34+
return nil, fmt.Errorf("unable to create temp directory: %s", err)
35+
}
36+
37+
// Find config
38+
home := homedir.HomeDir()
39+
kubeConfig := filepath.Join(home, ".kube", "config")
40+
config, err := clientcmd.BuildConfigFromFlags("", kubeConfig)
41+
42+
if err != nil {
43+
return nil, fmt.Errorf("unable to create k8s config: %s", err)
44+
}
45+
46+
dc := DataCollector{
47+
BaseDir: tmpDir,
48+
Namespaces: namespaces,
49+
K8sHelmClientSet: make(map[string]helmClient.Client),
50+
}
51+
52+
//Initialize clients
53+
dc.K8sCoreClientSet, _ = kubernetes.NewForConfig(config)
54+
dc.K8sCrdClientSet, _ = crdClient.NewForConfig(config)
55+
dc.K8sMetricsClientSet, _ = metricsClient.NewForConfig(config)
56+
for _, namespace := range dc.Namespaces {
57+
dc.K8sHelmClientSet[namespace], _ = helmClient.NewClientFromRestConf(&helmClient.RestConfClientOptions{
58+
Options: &helmClient.Options{Namespace: namespace},
59+
RestConfig: config,
60+
})
61+
}
62+
63+
return &dc, nil
64+
}
65+
66+
func (c *DataCollector) WrapUp() error {
67+
68+
// Create the tarball file
69+
//wd, _ := os.Getwd()
70+
unixTime := time.Now().Unix()
71+
unixTimeString := strconv.FormatInt(unixTime, 10)
72+
tarballName := fmt.Sprintf("kic-supportpkg-%s.tar.gz", unixTimeString)
73+
74+
file, err := os.Create(tarballName)
75+
if err != nil {
76+
return err
77+
}
78+
defer file.Close()
79+
80+
gw := gzip.NewWriter(file)
81+
defer gw.Close()
82+
83+
tw := tar.NewWriter(gw)
84+
defer tw.Close()
85+
86+
filepath.Walk(c.BaseDir, func(path string, info os.FileInfo, err error) error {
87+
if err != nil {
88+
return err
89+
}
90+
91+
header, err := tar.FileInfoHeader(info, "")
92+
if err != nil {
93+
return err
94+
}
95+
header.Name = path
96+
//TODO: correct this to relative path
97+
98+
if err := tw.WriteHeader(header); err != nil {
99+
return err
100+
}
101+
102+
if !info.Mode().IsRegular() {
103+
return nil
104+
}
105+
106+
file, err := os.Open(path)
107+
if err != nil {
108+
return err
109+
}
110+
defer file.Close()
111+
112+
_, err = io.Copy(tw, file)
113+
if err != nil {
114+
return err
115+
}
116+
117+
return nil
118+
})
119+
120+
fmt.Println("Tarball created successfully:", tarballName)
121+
os.RemoveAll(c.BaseDir)
122+
return nil
123+
}

internal/jobs/job.go renamed to pkg/jobs/job.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package jobs
22

33
import (
44
"context"
5-
"github.com/nginxinc/kubectl-kic-supportpkg/internal/data_collector"
5+
"github.com/nginxinc/kubectl-kic-supportpkg/pkg/data_collector"
66
"os"
77
"path"
88
"time"
@@ -12,18 +12,26 @@ type Job struct {
1212
Name string
1313
Global bool
1414
Execute func(dc *data_collector.DataCollector, ctx context.Context) map[string][]byte
15+
//TODO: execute function must return an error
1516
}
1617

17-
func (j Job) Collect(dc *data_collector.DataCollector) {
18+
func (j Job) Collect(dc *data_collector.DataCollector) error {
1819
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
1920
defer cancel()
2021

2122
jobResults := j.Execute(dc, ctx)
2223

2324
for fileName, fileValue := range jobResults {
24-
os.MkdirAll(path.Dir(fileName), os.ModePerm)
25+
err := os.MkdirAll(path.Dir(fileName), os.ModePerm)
26+
if err != nil {
27+
return err
28+
}
2529
file, _ := os.Create(fileName)
26-
_, _ = file.Write(fileValue)
27-
file.Close()
30+
_, err = file.Write(fileValue)
31+
if err != nil {
32+
return err
33+
}
34+
_ = file.Close()
2835
}
36+
return nil
2937
}

internal/jobs/job_list.go renamed to pkg/jobs/job_list.go

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import (
44
"bytes"
55
"context"
66
"encoding/json"
7-
"github.com/nginxinc/kubectl-kic-supportpkg/internal/data_collector"
7+
"fmt"
8+
"github.com/nginxinc/kubectl-kic-supportpkg/pkg/data_collector"
89
"io"
910
corev1 "k8s.io/api/core/v1"
1011
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -34,18 +35,20 @@ func JobList() []Job {
3435
Execute: func(dc *data_collector.DataCollector, ctx context.Context) map[string][]byte {
3536
results := make(map[string][]byte)
3637
for _, namespace := range dc.Namespaces {
37-
pods, _ := dc.K8sCoreClientSet.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{FieldSelector: "name"})
38+
pods, _ := dc.K8sCoreClientSet.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
3839
for _, pod := range pods.Items {
39-
logFileName := path.Join(dc.BaseDir, namespace, "logs", pod.Name+".txt")
40-
bufferedLogs := dc.K8sCoreClientSet.CoreV1().Pods(namespace).GetLogs(pod.Name, &corev1.PodLogOptions{})
41-
podLogs, err := bufferedLogs.Stream(context.TODO())
42-
if err != nil {
43-
log.Fatal("error in opening stream")
40+
for _, container := range pod.Spec.Containers {
41+
logFileName := path.Join(dc.BaseDir, namespace, "logs", fmt.Sprintf("%s__%s.txt", pod.Name, container.Name))
42+
bufferedLogs := dc.K8sCoreClientSet.CoreV1().Pods(namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Container: container.Name})
43+
podLogs, err := bufferedLogs.Stream(context.TODO())
44+
if err != nil {
45+
log.Fatal("error in opening stream")
46+
}
47+
buf := new(bytes.Buffer)
48+
_, _ = io.Copy(buf, podLogs)
49+
podLogs.Close()
50+
results[logFileName] = buf.Bytes()
4451
}
45-
buf := new(bytes.Buffer)
46-
_, _ = io.Copy(buf, podLogs)
47-
podLogs.Close()
48-
results[logFileName] = buf.Bytes()
4952
}
5053
}
5154
return results
@@ -185,16 +188,29 @@ func JobList() []Job {
185188
},
186189
},
187190
{
188-
Name: "helm-information",
191+
Name: "helm-info",
189192
Global: true,
190193
Execute: func(dc *data_collector.DataCollector, ctx context.Context) map[string][]byte {
191194
jobResults := make(map[string][]byte)
192-
settings := dc.K8sHelmClientSet.GetSettings()
195+
settings := dc.K8sHelmClientSet[dc.Namespaces[0]].GetSettings()
193196
jsonSettings, _ := json.MarshalIndent(settings, "", " ")
194197
jobResults[path.Join(dc.BaseDir, "helm", "settings.json")] = jsonSettings
195-
releases, _ := dc.K8sHelmClientSet.ListDeployedReleases()
196-
jsonReleases, _ := json.MarshalIndent(releases, "", " ")
197-
jobResults[path.Join(dc.BaseDir, "helm", "releases.json")] = jsonReleases
198+
return jobResults
199+
},
200+
},
201+
{
202+
Name: "helm-deployments",
203+
Global: false,
204+
Execute: func(dc *data_collector.DataCollector, ctx context.Context) map[string][]byte {
205+
jobResults := make(map[string][]byte)
206+
for _, namespace := range dc.Namespaces {
207+
releases, _ := dc.K8sHelmClientSet[namespace].ListDeployedReleases()
208+
for _, release := range releases {
209+
jsonRelease, _ := json.MarshalIndent(release, "", " ")
210+
jobResults[path.Join(dc.BaseDir, "helm", namespace, release.Name+"_release.json")] = jsonRelease
211+
jobResults[path.Join(dc.BaseDir, "helm", namespace, release.Name+"_manifest.txt")] = []byte(release.Manifest)
212+
}
213+
}
198214
return jobResults
199215
},
200216
},

0 commit comments

Comments
 (0)