diff --git a/config/crds/troubleshoot.sh_collectors.yaml b/config/crds/troubleshoot.sh_collectors.yaml index 1de5d2e2a..e1da94e70 100644 --- a/config/crds/troubleshoot.sh_collectors.yaml +++ b/config/crds/troubleshoot.sh_collectors.yaml @@ -17077,6 +17077,8 @@ spec: type: string exclude: type: BoolString + includeAllData: + type: boolean includeValue: type: boolean key: diff --git a/config/crds/troubleshoot.sh_preflights.yaml b/config/crds/troubleshoot.sh_preflights.yaml index a75cb2f9e..bc0878f72 100644 --- a/config/crds/troubleshoot.sh_preflights.yaml +++ b/config/crds/troubleshoot.sh_preflights.yaml @@ -18897,6 +18897,8 @@ spec: type: string exclude: type: BoolString + includeAllData: + type: boolean includeValue: type: boolean key: diff --git a/config/crds/troubleshoot.sh_supportbundles.yaml b/config/crds/troubleshoot.sh_supportbundles.yaml index e2263d86f..7f77f8228 100644 --- a/config/crds/troubleshoot.sh_supportbundles.yaml +++ b/config/crds/troubleshoot.sh_supportbundles.yaml @@ -18928,6 +18928,8 @@ spec: type: string exclude: type: BoolString + includeAllData: + type: boolean includeValue: type: boolean key: diff --git a/examples/support-bundle/secret-collectors.yaml b/examples/support-bundle/secret-collectors.yaml new file mode 100644 index 000000000..f76b07c56 --- /dev/null +++ b/examples/support-bundle/secret-collectors.yaml @@ -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 diff --git a/pkg/apis/troubleshoot/v1beta2/collector_shared.go b/pkg/apis/troubleshoot/v1beta2/collector_shared.go index 8c2286904..8d9118116 100644 --- a/pkg/apis/troubleshoot/v1beta2/collector_shared.go +++ b/pkg/apis/troubleshoot/v1beta2/collector_shared.go @@ -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 { diff --git a/pkg/collect/secret.go b/pkg/collect/secret.go index 7dc139954..7fb9ca76a 100644 --- a/pkg/collect/secret.go +++ b/pkg/collect/secret.go @@ -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...)) diff --git a/pkg/collect/secret_test.go b/pkg/collect/secret_test.go index ef4ee3ea0..b3ecdff10 100644 --- a/pkg/collect/secret_test.go +++ b/pkg/collect/secret_test.go @@ -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) { diff --git a/schemas/collector-troubleshoot-v1beta2.json b/schemas/collector-troubleshoot-v1beta2.json index b86c986d8..cb78a82ce 100644 --- a/schemas/collector-troubleshoot-v1beta2.json +++ b/schemas/collector-troubleshoot-v1beta2.json @@ -14527,6 +14527,9 @@ "exclude": { "oneOf": [{"type": "string"},{"type": "boolean"}] }, + "includeAllData": { + "type": "boolean" + }, "includeValue": { "type": "boolean" }, diff --git a/schemas/preflight-troubleshoot-v1beta2.json b/schemas/preflight-troubleshoot-v1beta2.json index 2c7e3d96f..8d58e8834 100644 --- a/schemas/preflight-troubleshoot-v1beta2.json +++ b/schemas/preflight-troubleshoot-v1beta2.json @@ -17313,6 +17313,9 @@ "exclude": { "oneOf": [{"type": "string"},{"type": "boolean"}] }, + "includeAllData": { + "type": "boolean" + }, "includeValue": { "type": "boolean" }, diff --git a/schemas/supportbundle-troubleshoot-v1beta2.json b/schemas/supportbundle-troubleshoot-v1beta2.json index 3d44d0690..2923c1249 100644 --- a/schemas/supportbundle-troubleshoot-v1beta2.json +++ b/schemas/supportbundle-troubleshoot-v1beta2.json @@ -17359,6 +17359,9 @@ "exclude": { "oneOf": [{"type": "string"},{"type": "boolean"}] }, + "includeAllData": { + "type": "boolean" + }, "includeValue": { "type": "boolean" },