mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-09-03 00:47:17 +00:00
feat: allow secrets collector to retreive all key data if specified (#1801)
* allow secrets collector retreival all key data if specified * add new line * remove unneeded comments
This commit is contained in:
@@ -17077,6 +17077,8 @@ spec:
|
||||
type: string
|
||||
exclude:
|
||||
type: BoolString
|
||||
includeAllData:
|
||||
type: boolean
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
|
||||
@@ -18897,6 +18897,8 @@ spec:
|
||||
type: string
|
||||
exclude:
|
||||
type: BoolString
|
||||
includeAllData:
|
||||
type: boolean
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
|
||||
@@ -18928,6 +18928,8 @@ spec:
|
||||
type: string
|
||||
exclude:
|
||||
type: BoolString
|
||||
includeAllData:
|
||||
type: boolean
|
||||
includeValue:
|
||||
type: boolean
|
||||
key:
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: troubleshoot.sh/v1beta2
|
||||
kind: SupportBundle
|
||||
metadata:
|
||||
name: secret-collector-examples
|
||||
spec:
|
||||
collectors:
|
||||
# Basic secret collection (no key-value data included)
|
||||
- secret:
|
||||
collectorName: basic-secret
|
||||
name: my-app-config
|
||||
namespace: default
|
||||
|
||||
# Collect specific key with value
|
||||
- secret:
|
||||
collectorName: specific-key-with-value
|
||||
name: my-app-config
|
||||
namespace: default
|
||||
key: database-password
|
||||
includeValue: true
|
||||
|
||||
# NEW: Collect all key-value pairs from a secret
|
||||
- secret:
|
||||
collectorName: all-secret-data
|
||||
name: my-app-config
|
||||
namespace: default
|
||||
includeAllData: true
|
||||
|
||||
# NEW: Collect all key-value pairs AND a specific key (combined approach)
|
||||
- secret:
|
||||
collectorName: combined-collection
|
||||
name: my-app-config
|
||||
namespace: default
|
||||
key: database-password
|
||||
includeValue: true
|
||||
includeAllData: true
|
||||
|
||||
# NEW: Collect all secrets matching a selector with all their data
|
||||
- secret:
|
||||
collectorName: secrets-by-selector-all-data
|
||||
namespace: default
|
||||
selector:
|
||||
- app=my-app
|
||||
includeAllData: true
|
||||
|
||||
# Collect secrets by selector (traditional approach)
|
||||
- secret:
|
||||
collectorName: secrets-by-selector-basic
|
||||
namespace: default
|
||||
selector:
|
||||
- app=my-app
|
||||
@@ -51,12 +51,13 @@ type NodeMetrics struct {
|
||||
}
|
||||
|
||||
type Secret struct {
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Selector []string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
IncludeValue bool `json:"includeValue,omitempty" yaml:"includeValue,omitempty"`
|
||||
CollectorMeta `json:",inline" yaml:",inline"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Selector []string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
IncludeValue bool `json:"includeValue,omitempty" yaml:"includeValue,omitempty"`
|
||||
IncludeAllData bool `json:"includeAllData,omitempty" yaml:"includeAllData,omitempty"`
|
||||
}
|
||||
|
||||
type ConfigMap struct {
|
||||
|
||||
+18
-9
@@ -18,12 +18,13 @@ import (
|
||||
)
|
||||
|
||||
type SecretOutput struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
SecretExists bool `json:"secretExists"`
|
||||
KeyExists bool `json:"keyExists"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Namespace string `json:"namespace"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
SecretExists bool `json:"secretExists"`
|
||||
KeyExists bool `json:"keyExists"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Data map[string]string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type CollectSecret struct {
|
||||
@@ -93,7 +94,13 @@ func secretToOutput(secretCollector *troubleshootv1beta2.Secret, secret *corev1.
|
||||
|
||||
if secret != nil {
|
||||
foundSecret.SecretExists = true
|
||||
if secretCollector.Key != "" {
|
||||
|
||||
if secretCollector.IncludeAllData {
|
||||
foundSecret.Data = make(map[string]string)
|
||||
for k, v := range secret.Data {
|
||||
foundSecret.Data[k] = string(v)
|
||||
}
|
||||
} else if secretCollector.Key != "" {
|
||||
if val, ok := secret.Data[secretCollector.Key]; ok {
|
||||
foundSecret.KeyExists = true
|
||||
if secretCollector.IncludeValue {
|
||||
@@ -134,7 +141,8 @@ func marshalSecretOutput(secretCollector *troubleshootv1beta2.Secret, secret Sec
|
||||
|
||||
func GetSecretFileName(secretCollector *troubleshootv1beta2.Secret, name string) string {
|
||||
parts := []string{"secrets", secretCollector.Namespace, name}
|
||||
if secretCollector.Key != "" {
|
||||
// Only include key in filename when doing key-specific processing
|
||||
if secretCollector.Key != "" && !secretCollector.IncludeAllData {
|
||||
parts = append(parts, secretCollector.Key)
|
||||
}
|
||||
return fmt.Sprintf("%s.json", filepath.Join(parts...))
|
||||
@@ -147,7 +155,8 @@ func GetSecretErrorsFileName(secretCollector *troubleshootv1beta2.Secret) string
|
||||
} else {
|
||||
parts = append(parts, selectorToString(secretCollector.Selector))
|
||||
}
|
||||
if secretCollector.Key != "" {
|
||||
// Only include key in filename when doing key-specific processing
|
||||
if secretCollector.Key != "" && !secretCollector.IncludeAllData {
|
||||
parts = append(parts, secretCollector.Key)
|
||||
}
|
||||
return fmt.Sprintf("%s.json", filepath.Join(parts...))
|
||||
|
||||
@@ -209,6 +209,148 @@ func TestSecret(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with includeAllData",
|
||||
secretCollector: &troubleshootv1beta2.Secret{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
IncludeAllData: true,
|
||||
},
|
||||
mockSecrets: []corev1.Secret{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: "test-namespace",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"database-password": []byte("secret123"),
|
||||
"api-key": []byte("abc123xyz"),
|
||||
"jwt-secret": []byte("mysupersecret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: CollectorResult{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: true,
|
||||
Data: map[string]string{
|
||||
"database-password": "secret123",
|
||||
"api-key": "abc123xyz",
|
||||
"jwt-secret": "mysupersecret",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with includeAllData and specific key",
|
||||
secretCollector: &troubleshootv1beta2.Secret{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
Key: "database-password",
|
||||
IncludeValue: true,
|
||||
IncludeAllData: true,
|
||||
},
|
||||
mockSecrets: []corev1.Secret{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: "test-namespace",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"database-password": []byte("secret123"),
|
||||
"api-key": []byte("abc123xyz"),
|
||||
"jwt-secret": []byte("mysupersecret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: CollectorResult{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
Key: "database-password",
|
||||
SecretExists: true,
|
||||
Data: map[string]string{
|
||||
"database-password": "secret123",
|
||||
"api-key": "abc123xyz",
|
||||
"jwt-secret": "mysupersecret",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with includeAllData secret not found",
|
||||
secretCollector: &troubleshootv1beta2.Secret{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
IncludeAllData: true,
|
||||
},
|
||||
mockSecrets: []corev1.Secret{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "other-secret",
|
||||
Namespace: "test-namespace",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"test-key": []byte("test-value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: CollectorResult{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: false,
|
||||
}),
|
||||
"secrets-errors/test-namespace/test-secret.json": mustJSONMarshalIndent(t, []string{
|
||||
`secrets "test-secret" not found`,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with includeAllData by selector",
|
||||
secretCollector: &troubleshootv1beta2.Secret{
|
||||
Namespace: "test-namespace",
|
||||
Selector: []string{
|
||||
"app=my-app",
|
||||
},
|
||||
IncludeAllData: true,
|
||||
},
|
||||
mockSecrets: []corev1.Secret{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-secret",
|
||||
Namespace: "test-namespace",
|
||||
Labels: map[string]string{"app": "my-app"},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"database-password": []byte("secret123"),
|
||||
"api-key": []byte("abc123xyz"),
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "other-secret",
|
||||
Namespace: "test-namespace",
|
||||
Labels: map[string]string{"app": "not-my-app"},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"test-key": []byte("test-value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: CollectorResult{
|
||||
"secrets/test-namespace/test-secret.json": mustJSONMarshalIndent(t, SecretOutput{
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-secret",
|
||||
SecretExists: true,
|
||||
Data: map[string]string{
|
||||
"database-password": "secret123",
|
||||
"api-key": "abc123xyz",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -14527,6 +14527,9 @@
|
||||
"exclude": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
},
|
||||
"includeAllData": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"includeValue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -17313,6 +17313,9 @@
|
||||
"exclude": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
},
|
||||
"includeAllData": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"includeValue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -17359,6 +17359,9 @@
|
||||
"exclude": {
|
||||
"oneOf": [{"type": "string"},{"type": "boolean"}]
|
||||
},
|
||||
"includeAllData": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"includeValue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user