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

Run in cli #50

Merged
merged 5 commits into from
Aug 15, 2019
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ run-preflight: preflight
./bin/preflight \
--image=localhost:32000/troubleshoot:alpha \
--pullpolicy=Always \
./config/samples/troubleshoot_v1beta1_preflight.yaml
./examples/preflight/sample-preflight.yaml

.PHONY: run-troubleshoot
run-troubleshoot: support-bundle
./bin/support-bundle \
--image=localhost:32000/troubleshoot:alpha \
--pullpolicy=Always \
./config/samples/troubleshoot_v1beta1_collector.yaml
./examples/troubleshoot/sample-troubleshoot.yaml
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ A support bundle is an archive that's created in-cluster, by collecting logs, cl
To collect a sample support bundle, [install the troubleshoot kubectl plugin](https://help.replicated.com/docs/troubleshoot/kubernetes/support-bundle/collecting/) and run:

```shell
kubectl troubleshoot https://troubleshoot.replicated.com
kubectl support-bundle https://troubleshoot.replicated.com
```
15 changes: 12 additions & 3 deletions cmd/collector/cli/run.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"fmt"
"io/ioutil"

"github.com/replicatedhq/troubleshoot/pkg/collect"
Expand All @@ -25,14 +26,22 @@ func Run() *cobra.Command {
return err
}

c, err := collect.ParseSpec(string(specContents))
if err != nil {
return err
}

collector := collect.Collector{
Spec: string(specContents),
Redact: v.GetBool("redact"),
Collect: c,
Redact: v.GetBool("redact"),
}
if err := collector.RunCollectorSync(); err != nil {
b, err := collector.RunCollectorSync()
if err != nil {
return err
}

fmt.Printf("%s", b)

return nil
},
}
Expand Down
180 changes: 14 additions & 166 deletions cmd/preflight/cli/run_nocrd.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package cli

import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
Expand All @@ -18,22 +15,11 @@ import (
"github.com/pkg/errors"
analyzerunner "github.com/replicatedhq/troubleshoot/pkg/analyze"
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
collectrunner "github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/replicatedhq/troubleshoot/pkg/collect"
"github.com/replicatedhq/troubleshoot/pkg/logger"
"github.com/spf13/viper"
"github.com/tj/go-spin"
"gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)

func runPreflightsNoCRD(v *viper.Viper, arg string) error {
Expand Down Expand Up @@ -143,174 +129,36 @@ func runPreflightsNoCRD(v *viper.Viper, arg string) error {
}

func runCollectors(v *viper.Viper, preflight troubleshootv1beta1.Preflight) (map[string][]byte, error) {
cfg, err := config.GetConfig()
if err != nil {
return nil, err
}

client, err := client.New(cfg, client.Options{})
if err != nil {
return nil, err
}
clientset, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, err
}
restClient := clientset.CoreV1().RESTClient()

serviceAccountName := v.GetString("serviceaccount")
if serviceAccountName == "" {
generatedServiceAccountName, err := createServiceAccount(preflight, v.GetString("namespace"), clientset)
if err != nil {
return nil, err
}
defer removeServiceAccount(generatedServiceAccountName, v.GetString("namespace"), clientset)

serviceAccountName = generatedServiceAccountName
}

// deploy an object that "owns" everything to aid in cleanup
configMapNamespacedName := types.NamespacedName{
Name: fmt.Sprintf("preflight-%s-owner", preflight.Name),
Namespace: v.GetString("namespace"),
}

foundConfigMap := &corev1.ConfigMap{}
err = client.Get(context.Background(), configMapNamespacedName, foundConfigMap)
if err == nil || !kuberneteserrors.IsNotFound(err) {
return nil, errors.Wrap(err, "failed to get existing config map")
}
owner := corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configMapNamespacedName.Name,
Namespace: configMapNamespacedName.Namespace,
},
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
Data: make(map[string]string),
}
if err := client.Create(context.Background(), &owner); err != nil {
return nil, errors.Wrap(err, "failed to create config map")
}
defer func() {
if err := client.Delete(context.Background(), &owner); err != nil {
fmt.Println("failed to clean up preflight.")
}
}()

// deploy all collectors
desiredCollectors := make([]*troubleshootv1beta1.Collect, 0, 0)
for _, definedCollector := range preflight.Spec.Collectors {
desiredCollectors = append(desiredCollectors, definedCollector)
}
desiredCollectors = ensureCollectorInList(desiredCollectors, troubleshootv1beta1.Collect{ClusterInfo: &troubleshootv1beta1.ClusterInfo{}})
desiredCollectors = ensureCollectorInList(desiredCollectors, troubleshootv1beta1.Collect{ClusterResources: &troubleshootv1beta1.ClusterResources{}})

podsCreated := make([]*corev1.Pod, 0, 0)
podsDeleted := make([]*corev1.Pod, 0, 0)
allCollectedData := make(map[string][]byte)

resyncPeriod := time.Second
ctx := context.Background()
watchList := cache.NewListWatchFromClient(restClient, "pods", "", fields.Everything())
_, controller := cache.NewInformer(watchList, &corev1.Pod{}, resyncPeriod,
cache.ResourceEventHandlerFuncs{
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
newPod, ok := newObj.(*corev1.Pod)
if !ok {
return
}
oldPod, ok := oldObj.(*corev1.Pod)
if !ok {
return
}
labels := newPod.Labels
troubleshootRole, ok := labels["troubleshoot-role"]
if !ok || troubleshootRole != "preflight" {
return
}
preflightName, ok := labels["preflight"]
if !ok || preflightName != preflight.Name {
return
}

if oldPod.Status.Phase == newPod.Status.Phase {
return
}

if newPod.Status.Phase == corev1.PodFailed {
podsDeleted = append(podsDeleted, newPod)
return
}

if newPod.Status.Phase != corev1.PodSucceeded {
return
}

podLogOpts := corev1.PodLogOptions{}

req := clientset.CoreV1().Pods(newPod.Namespace).GetLogs(newPod.Name, &podLogOpts)
podLogs, err := req.Stream()
if err != nil {
fmt.Println("get stream")
return
}
defer podLogs.Close()

buf := new(bytes.Buffer)
_, err = io.Copy(buf, podLogs)
if err != nil {
fmt.Println("copy logs")
return
}

collectedData, err := parseCollectorOutput(buf.String())
if err != nil {
logger.Printf("parse collected data: %v\n", err)
return
}
for k, v := range collectedData {
allCollectedData[k] = v
}

if err := client.Delete(context.Background(), newPod); err != nil {
fmt.Println("delete pod")
}
podsDeleted = append(podsDeleted, newPod)
},
})
go func() {
controller.Run(ctx.Done())
}()
// Run preflights collectors synchronously
for _, desiredCollector := range desiredCollectors {
collector := collect.Collector{
Redact: true,
Collect: desiredCollector,
}

s := runtime.NewScheme()
s.AddKnownTypes(schema.GroupVersion{Group: "", Version: "v1"}, &corev1.ConfigMap{})
for _, collector := range desiredCollectors {
_, pod, err := collectrunner.CreateCollector(client, s, &owner, preflight.Name, v.GetString("namespace"), serviceAccountName, "preflight", collector, v.GetString("image"), v.GetString("pullpolicy"))
result, err := collector.RunCollectorSync()
if err != nil {
return nil, errors.Wrap(err, "failed to create collector")
return nil, errors.Wrap(err, "failed to run collector")
}
podsCreated = append(podsCreated, pod)
}

start := time.Now()
for {
if start.Add(time.Second * 30).Before(time.Now()) {
fmt.Println("timeout running preflight")
return nil, err
output, err := parseCollectorOutput(string(result))
if err != nil {
return nil, errors.Wrap(err, "failed to parse collector output")
}

if len(podsDeleted) == len(podsCreated) {
break
for k, v := range output {
allCollectedData[k] = v
}

time.Sleep(time.Millisecond * 200)
}

ctx.Done()

return allCollectedData, nil
}

Expand Down
5 changes: 4 additions & 1 deletion cmd/preflight/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package main

import "github.com/replicatedhq/troubleshoot/cmd/preflight/cli"
import (
"github.com/replicatedhq/troubleshoot/cmd/preflight/cli"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

func main() {
cli.InitAndExecute()
Expand Down
Loading