mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-02-14 18:29:53 +00:00
Merge pull request #53 from replicatedhq/divolgin/upload
Automatically upload generated support bundle file
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"github.com/ahmetalpbalkan/go-cursor"
|
||||
"github.com/fatih/color"
|
||||
"github.com/mholt/archiver"
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
"github.com/spf13/viper"
|
||||
@@ -32,25 +34,25 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
|
||||
|
||||
b, err := ioutil.ReadFile(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "read spec file")
|
||||
}
|
||||
|
||||
collectorContent = string(b)
|
||||
} else {
|
||||
req, err := http.NewRequest("GET", arg, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "make request")
|
||||
}
|
||||
req.Header.Set("User-Agent", "Replicated_Troubleshoot/v1beta1")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "read responce body")
|
||||
}
|
||||
|
||||
collectorContent = string(body)
|
||||
@@ -83,7 +85,7 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
|
||||
if currentDir == "" {
|
||||
fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s", cursor.ClearEntireLine(), s.Next())
|
||||
} else {
|
||||
fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s: %s", cursor.ClearEntireLine(), s.Next(), currentDir)
|
||||
fmt.Printf("\r%s \033[36mCollecting support bundle\033[m %s %s", cursor.ClearEntireLine(), s.Next(), currentDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,38 +96,55 @@ func runTroubleshootNoCRD(v *viper.Viper, arg string) error {
|
||||
|
||||
archivePath, err := runCollectors(v, collector, progressChan)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "run collectors")
|
||||
}
|
||||
|
||||
fmt.Printf("\r%s", cursor.ClearEntireLine())
|
||||
|
||||
msg := archivePath
|
||||
if appName := collector.Labels["applicationName"]; appName != "" {
|
||||
f := `A support bundle for %s has been created in this directory
|
||||
if len(collector.Spec.AfterCollection) == 0 {
|
||||
msg := archivePath
|
||||
if appName := collector.Labels["applicationName"]; appName != "" {
|
||||
f := `A support bundle for %s has been created in this directory
|
||||
named %s. Please upload it on the Troubleshoot page of
|
||||
the %s Admin Console to begin analysis.`
|
||||
msg = fmt.Sprintf(f, appName, archivePath, appName)
|
||||
msg = fmt.Sprintf(f, appName, archivePath, appName)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", msg)
|
||||
for _, ac := range collector.Spec.AfterCollection {
|
||||
if ac.UploadResultsTo != nil {
|
||||
if err := uploadSupportBundle(ac.UploadResultsTo, archivePath); err != nil {
|
||||
return errors.Wrap(err, "upload support bundle")
|
||||
}
|
||||
} else if ac.Callback != nil {
|
||||
if err := callbackSupportBundleAPI(ac.Callback, archivePath); err != nil {
|
||||
return errors.Wrap(err, "execute callback")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("A support bundle has been created in the current directory named %q\n", archivePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, progressChan chan interface{}) (string, error) {
|
||||
bundlePath, err := ioutil.TempDir("", "troubleshoot")
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "create temp dir")
|
||||
}
|
||||
defer os.RemoveAll(bundlePath)
|
||||
|
||||
versionFilename, err := writeVersionFile(bundlePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "write version file")
|
||||
}
|
||||
|
||||
desiredCollectors := make([]*troubleshootv1beta1.Collect, 0, 0)
|
||||
for _, definedCollector := range collector.Spec {
|
||||
for _, definedCollector := range collector.Spec.Collectors {
|
||||
desiredCollectors = append(desiredCollectors, definedCollector)
|
||||
}
|
||||
desiredCollectors = ensureCollectorInList(desiredCollectors, troubleshootv1beta1.Collect{ClusterInfo: &troubleshootv1beta1.ClusterInfo{}})
|
||||
@@ -175,7 +194,7 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog
|
||||
}
|
||||
|
||||
if err := tarGz.Archive(paths, "support-bundle.tar.gz"); err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "create archive")
|
||||
}
|
||||
|
||||
return "support-bundle.tar.gz", nil
|
||||
@@ -186,7 +205,7 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
|
||||
|
||||
input := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(output), &input); err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "unmarshal output")
|
||||
}
|
||||
|
||||
for filename, maybeContents := range input {
|
||||
@@ -195,33 +214,33 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
|
||||
dir = outPath
|
||||
|
||||
if err := os.MkdirAll(outPath, 0777); err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "create output file")
|
||||
}
|
||||
|
||||
switch maybeContents.(type) {
|
||||
case string:
|
||||
decoded, err := base64.StdEncoding.DecodeString(maybeContents.(string))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "decode collector output")
|
||||
}
|
||||
|
||||
if err := writeFile(filepath.Join(outPath, fileName), decoded); err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "write collector output")
|
||||
}
|
||||
|
||||
case map[string]interface{}:
|
||||
for k, v := range maybeContents.(map[string]interface{}) {
|
||||
s, _ := filepath.Split(filepath.Join(outPath, fileName, k))
|
||||
if err := os.MkdirAll(s, 0777); err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "write output directories")
|
||||
}
|
||||
|
||||
decoded, err := base64.StdEncoding.DecodeString(v.(string))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "decode output")
|
||||
}
|
||||
if err := writeFile(filepath.Join(outPath, fileName, k), decoded); err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "write output")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,3 +248,67 @@ func parseAndSaveCollectorOutput(output string, bundlePath string) (string, erro
|
||||
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func uploadSupportBundle(r *troubleshootv1beta1.ResultRequest, archivePath string) error {
|
||||
contentType := getExpectedContentType(r.URI)
|
||||
if contentType != "" && contentType != "application/tar+gzip" {
|
||||
return fmt.Errorf("cannot upload content type %s", contentType)
|
||||
}
|
||||
|
||||
f, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fileStat, err := f.Stat()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stat file")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(r.Method, r.URI, f)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create request")
|
||||
}
|
||||
req.ContentLength = fileStat.Size()
|
||||
if contentType != "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getExpectedContentType(uploadURL string) string {
|
||||
parsedURL, err := url.Parse(uploadURL)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return parsedURL.Query().Get("Content-Type")
|
||||
}
|
||||
|
||||
func callbackSupportBundleAPI(r *troubleshootv1beta1.ResultRequest, archivePath string) error {
|
||||
req, err := http.NewRequest(r.Method, r.URI, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "execute request")
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("unexpected status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -390,167 +390,195 @@ spec:
|
||||
type: string
|
||||
type: object
|
||||
spec:
|
||||
items:
|
||||
properties:
|
||||
clusterInfo:
|
||||
type: object
|
||||
clusterResources:
|
||||
type: object
|
||||
copy:
|
||||
properties:
|
||||
afterCollection:
|
||||
items:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
containerName:
|
||||
type: string
|
||||
containerPath:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- selector
|
||||
- namespace
|
||||
- containerPath
|
||||
type: object
|
||||
exec:
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
collectorName:
|
||||
type: string
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
containerName:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
required:
|
||||
- selector
|
||||
- namespace
|
||||
type: object
|
||||
http:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
get:
|
||||
callback:
|
||||
properties:
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
method:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
- uri
|
||||
- method
|
||||
type: object
|
||||
post:
|
||||
uploadResultsTo:
|
||||
properties:
|
||||
body:
|
||||
method:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
uri:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
- uri
|
||||
- method
|
||||
type: object
|
||||
put:
|
||||
type: object
|
||||
type: array
|
||||
collectors:
|
||||
items:
|
||||
properties:
|
||||
clusterInfo:
|
||||
type: object
|
||||
clusterResources:
|
||||
type: object
|
||||
copy:
|
||||
properties:
|
||||
body:
|
||||
collectorName:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
containerName:
|
||||
type: string
|
||||
containerPath:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: array
|
||||
required:
|
||||
- selector
|
||||
- namespace
|
||||
- containerPath
|
||||
type: object
|
||||
exec:
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
collectorName:
|
||||
type: string
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
containerName:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
- selector
|
||||
- namespace
|
||||
type: object
|
||||
type: object
|
||||
logs:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
limits:
|
||||
http:
|
||||
properties:
|
||||
maxAge:
|
||||
collectorName:
|
||||
type: string
|
||||
maxLines:
|
||||
format: int64
|
||||
type: integer
|
||||
get:
|
||||
properties:
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
post:
|
||||
properties:
|
||||
body:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
put:
|
||||
properties:
|
||||
body:
|
||||
type: string
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
type: boolean
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
type: object
|
||||
logs:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
limits:
|
||||
properties:
|
||||
maxAge:
|
||||
type: string
|
||||
maxLines:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- selector
|
||||
type: object
|
||||
run:
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
collectorName:
|
||||
type: string
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
image:
|
||||
type: string
|
||||
imagePullPolicy:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
timeout:
|
||||
type: string
|
||||
required:
|
||||
- namespace
|
||||
- image
|
||||
type: object
|
||||
secret:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
namespace:
|
||||
type: string
|
||||
selector:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- selector
|
||||
type: object
|
||||
run:
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
collectorName:
|
||||
type: string
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
image:
|
||||
type: string
|
||||
imagePullPolicy:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
timeout:
|
||||
type: string
|
||||
required:
|
||||
- namespace
|
||||
- image
|
||||
type: object
|
||||
secret:
|
||||
properties:
|
||||
collectorName:
|
||||
type: string
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
type: array
|
||||
type: object
|
||||
status:
|
||||
type: object
|
||||
type: object
|
||||
|
||||
@@ -8,6 +8,31 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AfterCollection) DeepCopyInto(out *AfterCollection) {
|
||||
*out = *in
|
||||
if in.UploadResultsTo != nil {
|
||||
in, out := &in.UploadResultsTo, &out.UploadResultsTo
|
||||
*out = new(ResultRequest)
|
||||
**out = **in
|
||||
}
|
||||
if in.Callback != nil {
|
||||
in, out := &in.Callback, &out.Callback
|
||||
*out = new(ResultRequest)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AfterCollection.
|
||||
func (in *AfterCollection) DeepCopy() *AfterCollection {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AfterCollection)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Analyze) DeepCopyInto(out *Analyze) {
|
||||
*out = *in
|
||||
@@ -390,17 +415,7 @@ func (in *Collector) DeepCopyInto(out *Collector) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.Spec != nil {
|
||||
in, out := &in.Spec, &out.Spec
|
||||
*out = make([]*Collect, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Collect)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
@@ -589,6 +604,43 @@ func (in *CollectorRef) DeepCopy() *CollectorRef {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CollectorSpec) DeepCopyInto(out *CollectorSpec) {
|
||||
*out = *in
|
||||
if in.Collectors != nil {
|
||||
in, out := &in.Collectors, &out.Collectors
|
||||
*out = make([]*Collect, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Collect)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.AfterCollection != nil {
|
||||
in, out := &in.AfterCollection, &out.AfterCollection
|
||||
*out = make([]*AfterCollection, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(AfterCollection)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectorSpec.
|
||||
func (in *CollectorSpec) DeepCopy() *CollectorSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CollectorSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CollectorStatus) DeepCopyInto(out *CollectorStatus) {
|
||||
*out = *in
|
||||
@@ -1151,6 +1203,21 @@ func (in *Put) DeepCopy() *Put {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResultRequest) DeepCopyInto(out *ResultRequest) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResultRequest.
|
||||
func (in *ResultRequest) DeepCopy() *ResultRequest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResultRequest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Run) DeepCopyInto(out *Run) {
|
||||
*out = *in
|
||||
|
||||
@@ -3,76 +3,77 @@ kind: Collector
|
||||
metadata:
|
||||
name: collector-sample
|
||||
spec:
|
||||
- clusterInfo: {}
|
||||
- clusterResources: {}
|
||||
# - secret:
|
||||
# name: illmannered-cricket-mysql
|
||||
# namespace: default
|
||||
# key: mysql-password
|
||||
# - logs:
|
||||
# selector:
|
||||
# - name=nginx-ingress-microk8s
|
||||
# namespace: default
|
||||
# limits:
|
||||
# maxAge: 30d
|
||||
# maxLines: 10000
|
||||
# - run:
|
||||
# collectorName: ping-google
|
||||
# namespace: default
|
||||
# image: flungo/netutils
|
||||
# command: ["ping"]
|
||||
# args: ["www.google.com"]
|
||||
# timeout: 5s
|
||||
- exec:
|
||||
collectorName: mysql-vars
|
||||
selector:
|
||||
- app=mysql
|
||||
namespace: default
|
||||
command: ["mysql"]
|
||||
args: ["-ureplicated", "-ppassword", "-e", "show processlist"]
|
||||
timeout: 60m
|
||||
- exec:
|
||||
collectorName: hosts
|
||||
selector:
|
||||
- app=graphql-api
|
||||
namespace: default
|
||||
command: ["cat"]
|
||||
args: ["/etc/hosts"]
|
||||
timeout: 60m
|
||||
- exec:
|
||||
collectorName: broken
|
||||
selector:
|
||||
- app=graphql-api
|
||||
namespace: default
|
||||
command: ["cat"]
|
||||
args: ["/etc/hostdasddsda"]
|
||||
timeout: 60m
|
||||
# - copy:
|
||||
# selector:
|
||||
# - app=illmannered-cricket-mysql
|
||||
# namespace: default
|
||||
# containerPath: /etc/hosts
|
||||
- http:
|
||||
collectorName: test-get
|
||||
get:
|
||||
url: https://api.staging.replicated.com/market/v1/echo/ip
|
||||
insecureSkipVerify: false
|
||||
headers: {}
|
||||
- http:
|
||||
collectorName: test-post
|
||||
post:
|
||||
url: http://httpbin.org/headers
|
||||
insecureSkipVerify: false
|
||||
headers:
|
||||
X-Custom-Header: "post-request"
|
||||
- http:
|
||||
collectorName: test-put
|
||||
put:
|
||||
url: http://httpbin.org/anything
|
||||
insecureSkipVerify: false
|
||||
headers:
|
||||
X-Custom-Header: "put-request"
|
||||
- http:
|
||||
collectorName: test-broken
|
||||
put:
|
||||
url: ""
|
||||
collectors:
|
||||
- clusterInfo: {}
|
||||
- clusterResources: {}
|
||||
# - secret:
|
||||
# name: illmannered-cricket-mysql
|
||||
# namespace: default
|
||||
# key: mysql-password
|
||||
# - logs:
|
||||
# selector:
|
||||
# - name=nginx-ingress-microk8s
|
||||
# namespace: default
|
||||
# limits:
|
||||
# maxAge: 30d
|
||||
# maxLines: 10000
|
||||
# - run:
|
||||
# collectorName: ping-google
|
||||
# namespace: default
|
||||
# image: flungo/netutils
|
||||
# command: ["ping"]
|
||||
# args: ["www.google.com"]
|
||||
# timeout: 5s
|
||||
- exec:
|
||||
collectorName: mysql-vars
|
||||
selector:
|
||||
- app=mysql
|
||||
namespace: default
|
||||
command: ["mysql"]
|
||||
args: ["-ureplicated", "-ppassword", "-e", "show processlist"]
|
||||
timeout: 60m
|
||||
- exec:
|
||||
collectorName: hosts
|
||||
selector:
|
||||
- app=graphql-api
|
||||
namespace: default
|
||||
command: ["cat"]
|
||||
args: ["/etc/hosts"]
|
||||
timeout: 60m
|
||||
- exec:
|
||||
collectorName: broken
|
||||
selector:
|
||||
- app=graphql-api
|
||||
namespace: default
|
||||
command: ["cat"]
|
||||
args: ["/etc/hostdasddsda"]
|
||||
timeout: 60m
|
||||
# - copy:
|
||||
# selector:
|
||||
# - app=illmannered-cricket-mysql
|
||||
# namespace: default
|
||||
# containerPath: /etc/hosts
|
||||
- http:
|
||||
collectorName: test-get
|
||||
get:
|
||||
url: https://api.staging.replicated.com/market/v1/echo/ip
|
||||
insecureSkipVerify: false
|
||||
headers: {}
|
||||
- http:
|
||||
collectorName: test-post
|
||||
post:
|
||||
url: http://httpbin.org/headers
|
||||
insecureSkipVerify: false
|
||||
headers:
|
||||
X-Custom-Header: "post-request"
|
||||
- http:
|
||||
collectorName: test-put
|
||||
put:
|
||||
url: http://httpbin.org/anything
|
||||
insecureSkipVerify: false
|
||||
headers:
|
||||
X-Custom-Header: "put-request"
|
||||
- http:
|
||||
collectorName: test-broken
|
||||
put:
|
||||
url: ""
|
||||
|
||||
@@ -3,26 +3,27 @@ kind: Collector
|
||||
metadata:
|
||||
name: collector-sample
|
||||
spec:
|
||||
- secret:
|
||||
name: myapp-postgres
|
||||
namespace: default
|
||||
key: uri
|
||||
includeValue: false
|
||||
- logs:
|
||||
selector:
|
||||
- name=cilium-operator
|
||||
namespace: kube-system
|
||||
limits:
|
||||
maxAge: 30d
|
||||
maxLines: 10000
|
||||
- run:
|
||||
collectorName: ping-google
|
||||
namespace: default
|
||||
image: flungo/netutils
|
||||
command: ["ping"]
|
||||
args: ["www.google.com"]
|
||||
timeout: 5s
|
||||
- http:
|
||||
collectorName: echo-ip
|
||||
get:
|
||||
url: https://api.replicated.com/market/v1/echo/ip
|
||||
collectors:
|
||||
- secret:
|
||||
name: myapp-postgres
|
||||
namespace: default
|
||||
key: uri
|
||||
includeValue: false
|
||||
- logs:
|
||||
selector:
|
||||
- name=cilium-operator
|
||||
namespace: kube-system
|
||||
limits:
|
||||
maxAge: 30d
|
||||
maxLines: 10000
|
||||
- run:
|
||||
collectorName: ping-google
|
||||
namespace: default
|
||||
image: flungo/netutils
|
||||
command: ["ping"]
|
||||
args: ["www.google.com"]
|
||||
timeout: 5s
|
||||
- http:
|
||||
collectorName: echo-ip
|
||||
get:
|
||||
url: https://api.replicated.com/market/v1/echo/ip
|
||||
|
||||
@@ -20,6 +20,22 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type ResultRequest struct {
|
||||
URI string `json:"uri" yaml:"uri"`
|
||||
Method string `json:"method" yaml:"method"`
|
||||
}
|
||||
|
||||
type AfterCollection struct {
|
||||
UploadResultsTo *ResultRequest `json:"uploadResultsTo,omitempty" yaml:"uploadResultsTo,omitempty"`
|
||||
Callback *ResultRequest `json:"callback,omitempty" yaml:"callback,omitempty"`
|
||||
}
|
||||
|
||||
// CollectorSpec defines the desired state of Collector
|
||||
type CollectorSpec struct {
|
||||
Collectors []*Collect `json:"collectors,omitempty" yaml:"collectors,omitempty"`
|
||||
AfterCollection []*AfterCollection `json:"afterCollection,omitempty" yaml:"afterCollection,omitempty"`
|
||||
}
|
||||
|
||||
// CollectorStatus defines the observed state of Collector
|
||||
type CollectorStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
@@ -35,7 +51,7 @@ type Collector struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
Spec []*Collect `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
Spec CollectorSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
Status CollectorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,31 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AfterCollection) DeepCopyInto(out *AfterCollection) {
|
||||
*out = *in
|
||||
if in.UploadResultsTo != nil {
|
||||
in, out := &in.UploadResultsTo, &out.UploadResultsTo
|
||||
*out = new(ResultRequest)
|
||||
**out = **in
|
||||
}
|
||||
if in.Callback != nil {
|
||||
in, out := &in.Callback, &out.Callback
|
||||
*out = new(ResultRequest)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AfterCollection.
|
||||
func (in *AfterCollection) DeepCopy() *AfterCollection {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AfterCollection)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Analyze) DeepCopyInto(out *Analyze) {
|
||||
*out = *in
|
||||
@@ -406,17 +431,7 @@ func (in *Collector) DeepCopyInto(out *Collector) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.Spec != nil {
|
||||
in, out := &in.Spec, &out.Spec
|
||||
*out = make([]*Collect, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Collect)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
@@ -605,6 +620,43 @@ func (in *CollectorRef) DeepCopy() *CollectorRef {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CollectorSpec) DeepCopyInto(out *CollectorSpec) {
|
||||
*out = *in
|
||||
if in.Collectors != nil {
|
||||
in, out := &in.Collectors, &out.Collectors
|
||||
*out = make([]*Collect, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Collect)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.AfterCollection != nil {
|
||||
in, out := &in.AfterCollection, &out.AfterCollection
|
||||
*out = make([]*AfterCollection, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(AfterCollection)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectorSpec.
|
||||
func (in *CollectorSpec) DeepCopy() *CollectorSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CollectorSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CollectorStatus) DeepCopyInto(out *CollectorStatus) {
|
||||
*out = *in
|
||||
@@ -1167,6 +1219,21 @@ func (in *Put) DeepCopy() *Put {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResultRequest) DeepCopyInto(out *ResultRequest) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResultRequest.
|
||||
func (in *ResultRequest) DeepCopy() *ResultRequest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResultRequest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Run) DeepCopyInto(out *Run) {
|
||||
*out = *in
|
||||
|
||||
@@ -137,7 +137,7 @@ func (r *ReconcileCollectorJob) Reconcile(request reconcile.Request) (reconcile.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
for _, collector := range collectorSpec.Spec {
|
||||
for _, collector := range collectorSpec.Spec.Collectors {
|
||||
if err := r.reconileOneCollectorJob(instance, collector); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user