mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-08-27 00:37:20 +00:00
feat: save YAML spec used to generate support bundle/preflight (#1713)
* save YAML spec of support bundle * save YAML spec of preflight * add unit test * redact TLS private key by default in output spec * update YAML path for HTTP TLS redactor
This commit is contained in:
@@ -11,6 +11,8 @@ const (
|
||||
DEFAULT_CLIENT_USER_AGENT = "ReplicatedTroubleshoot"
|
||||
// VERSION_FILENAME is the name of the file that contains the support bundle version.
|
||||
VERSION_FILENAME = "version.yaml"
|
||||
// SPEC_FILENAME is the name of the file that contains the support bundle/preflight spec.
|
||||
SPEC_FILENAME = "spec.yaml"
|
||||
// DEFAULT_LOGS_COLLECTOR_TIMEOUT is the default timeout for logs collector.
|
||||
DEFAULT_LOGS_COLLECTOR_TIMEOUT = 60 * time.Second
|
||||
// MAX_TIME_TO_WAIT_FOR_POD_DELETION is the maximum time to wait for pod deletion.
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/convert"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/loader"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/types"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/version"
|
||||
"github.com/spf13/viper"
|
||||
@@ -180,6 +181,13 @@ func RunPreflights(interactive bool, output string, format string, args []string
|
||||
return errors.Wrap(err, "failed to save version file")
|
||||
}
|
||||
|
||||
// save final preflight spec used to geneate the preflight checks
|
||||
err = savePreflightSpecToBundle(specs, collectorResults, bundlePath)
|
||||
if err != nil {
|
||||
// still allow the preflight to be created
|
||||
klog.Errorf("failed to save preflight YAML spec: %v", err)
|
||||
}
|
||||
|
||||
analyzeResults, err := analyzer.AnalyzeLocal(ctx, bundlePath, analyzers, hostAnalyzers)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to analyze support bundle")
|
||||
@@ -469,3 +477,24 @@ func parseTimeFlags(v *viper.Viper, collectors []*troubleshootv1beta2.Collect) e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func savePreflightSpecToBundle(specs *loader.TroubleshootKinds, result collect.CollectorResult, bundlePath string) error {
|
||||
yamlContent, err := specs.ToYaml()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert preflight specs to yaml")
|
||||
}
|
||||
err = result.SaveResult(bundlePath, constants.SPEC_FILENAME, bytes.NewBuffer([]byte(yamlContent)))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write preflight spec to bundle")
|
||||
}
|
||||
// redact the final YAML spec
|
||||
singleResult := map[string][]byte{
|
||||
constants.SPEC_FILENAME: []byte(yamlContent),
|
||||
}
|
||||
|
||||
err = collect.RedactResult(bundlePath, singleResult, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to redact final preflight yaml spec")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -470,6 +470,20 @@ func getRedactors(path string) ([]Redactor, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// redact final YAML spec used to generate the support bundle/preflight
|
||||
// redact TLS private key if any
|
||||
// todo: any other TLS keys to redact?
|
||||
tlsKeys := []string{"clientKey"}
|
||||
for _, key := range tlsKeys {
|
||||
yamlPaths := []string{
|
||||
fmt.Sprintf("spec.collectors.*.*.tls.%s", key), // Database collector
|
||||
fmt.Sprintf("spec.collectors.*.*.*.tls.%s", key), // HTTP collector
|
||||
}
|
||||
for _, yamlPath := range yamlPaths {
|
||||
redactors = append(redactors, NewYamlRedactor(yamlPath, constants.SPEC_FILENAME, "Redact TLS private key"))
|
||||
}
|
||||
}
|
||||
|
||||
return redactors, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/convert"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/loader"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/version"
|
||||
"go.opentelemetry.io/otel"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -165,6 +166,13 @@ func CollectSupportBundleFromSpec(
|
||||
return nil, errors.Wrap(err, "failed to write version")
|
||||
}
|
||||
|
||||
// save final YAML spec used to geneate the support bundle
|
||||
err = saveAndRedactFinalSpec(spec, &result, bundlePath, additionalRedactors)
|
||||
if err != nil {
|
||||
// still allow the support bundle to be created
|
||||
klog.Errorf("failed to save and redact final spec: %v", err)
|
||||
}
|
||||
|
||||
// Run Analyzers
|
||||
analyzeResults, err := AnalyzeSupportBundle(ctx, spec, bundlePath)
|
||||
if err != nil {
|
||||
@@ -312,3 +320,43 @@ func getNodeList(clientset kubernetes.Interface, opts SupportBundleCreateOpts) (
|
||||
|
||||
return &nodeList, nil
|
||||
}
|
||||
|
||||
func saveAndRedactFinalSpec(spec *troubleshootv1beta2.SupportBundleSpec, result *collect.CollectorResult, bundlePath string, additionalRedactors *troubleshootv1beta2.Redactor) error {
|
||||
// generate the final YAML spec
|
||||
k := loader.TroubleshootKinds{
|
||||
SupportBundlesV1Beta2: []troubleshootv1beta2.SupportBundle{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "troubleshoot.sh/v1beta2",
|
||||
Kind: "SupportBundle",
|
||||
},
|
||||
Spec: *spec,
|
||||
},
|
||||
},
|
||||
}
|
||||
yamlContent, err := k.ToYaml()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert final support bundle spec to yaml")
|
||||
}
|
||||
|
||||
err = result.SaveResult(bundlePath, constants.SPEC_FILENAME, bytes.NewBuffer([]byte(yamlContent)))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write final support bundle yaml spec")
|
||||
}
|
||||
|
||||
// redact the final YAML spec
|
||||
singleResult := map[string][]byte{
|
||||
constants.SPEC_FILENAME: []byte(yamlContent),
|
||||
}
|
||||
|
||||
var redactors []*troubleshootv1beta2.Redact
|
||||
if additionalRedactors != nil {
|
||||
redactors = additionalRedactors.Spec.Redactors
|
||||
}
|
||||
err = collect.RedactResult(bundlePath, singleResult, redactors)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to redact final support bundle yaml spec")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package supportbundle
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -114,3 +121,70 @@ func Test_getNodeList(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_saveAndRedactFinalSpec(t *testing.T) {
|
||||
spec := &troubleshootv1beta2.SupportBundleSpec{
|
||||
Collectors: []*troubleshootv1beta2.Collect{
|
||||
{
|
||||
ClusterInfo: &troubleshootv1beta2.ClusterInfo{},
|
||||
ClusterResources: &troubleshootv1beta2.ClusterResources{},
|
||||
Postgres: &troubleshootv1beta2.Database{
|
||||
URI: "postgresql://user:password@hostname:5432/defaultdb?sslmode=require",
|
||||
TLS: &troubleshootv1beta2.TLSParams{
|
||||
CACert: `CA CERT`,
|
||||
ClientCert: `CLIENT CERT`,
|
||||
ClientKey: `PRIVATE KEY`,
|
||||
},
|
||||
},
|
||||
HTTP: &troubleshootv1beta2.HTTP{
|
||||
Get: &troubleshootv1beta2.Get{
|
||||
URL: "http:api:3000/healthz",
|
||||
TLS: &troubleshootv1beta2.TLSParams{
|
||||
ClientKey: `PRIVATE KEY`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result := make(collect.CollectorResult)
|
||||
bundlePath := t.TempDir()
|
||||
expectedYAML := `
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
spec:
|
||||
collectors:
|
||||
- clusterInfo: {}
|
||||
clusterResources: {}
|
||||
postgres:
|
||||
uri: postgresql://***HIDDEN***:***HIDDEN***@***HIDDEN***:5432/***HIDDEN***
|
||||
tls:
|
||||
cacert: CA CERT
|
||||
clientCert: CLIENT CERT
|
||||
clientKey: "***HIDDEN***"
|
||||
http:
|
||||
get:
|
||||
url: http:api:3000/healthz
|
||||
tls:
|
||||
clientKey: "***HIDDEN***"
|
||||
status: {}
|
||||
`
|
||||
|
||||
err := saveAndRedactFinalSpec(spec, &result, bundlePath, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actualYAML, err := os.ReadFile(filepath.Join(bundlePath, constants.SPEC_FILENAME))
|
||||
require.NoError(t, err)
|
||||
|
||||
var expectedData, actualData interface{}
|
||||
err = yaml.Unmarshal([]byte(expectedYAML), &expectedData)
|
||||
require.NoError(t, err)
|
||||
err = yaml.Unmarshal(actualYAML, &actualData)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedData, actualData)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user