@@ -17,8 +17,12 @@ limitations under the License.
1717package validators
1818
1919import (
20+ "bytes"
2021 "context"
2122 "fmt"
23+ "os"
24+ "os/exec"
25+ "path/filepath"
2226 "strings"
2327 "time"
2428
@@ -186,6 +190,8 @@ func (h *ValidatorHarness) TestNamespace() string {
186190 h .testNamespace = ns
187191
188192 h .t .Cleanup (func () {
193+ h .dumpNamespaceResources (ns )
194+
189195 h .Logf ("Deleting test namespace %q" , ns )
190196 ctx := context .WithoutCancel (h .Context ())
191197 err := h .DynamicClient ().Resource (namespaceGVR ).Delete (ctx , ns , metav1.DeleteOptions {})
@@ -204,3 +210,58 @@ func (h *ValidatorHarness) ApplyManifest(namespace string, manifestPath string)
204210 h .Logf ("Applying manifest %q to namespace %q" , manifestPath , namespace )
205211 h .ShellExec (fmt .Sprintf ("kubectl apply -n %s -f %s" , namespace , manifestPath ))
206212}
213+
214+ // dumpNamespaceResources dumps key resources from the namespace to the artifacts directory for debugging.
215+ func (h * ValidatorHarness ) dumpNamespaceResources (ns string ) {
216+ artifactsDir := os .Getenv ("ARTIFACTS" )
217+ if artifactsDir == "" {
218+ artifactsDir = "_artifacts"
219+ }
220+
221+ testName := strings .ReplaceAll (h .t .Name (), "/" , "_" )
222+ clusterInfoDir := filepath .Join (artifactsDir , "per-test" , testName , "cluster-info" , ns )
223+ if err := os .MkdirAll (clusterInfoDir , 0o755 ); err != nil {
224+ h .Logf ("failed to create cluster-info directory: %v" , err )
225+ return
226+ }
227+
228+ resourceTypes := []string {
229+ "pods" ,
230+ "jobs" ,
231+ "deployments" ,
232+ "statefulsets" ,
233+ "services" ,
234+ "events" ,
235+ }
236+
237+ for _ , resourceType := range resourceTypes {
238+ if err := h .dumpResource (ns , resourceType , filepath .Join (clusterInfoDir , resourceType + ".yaml" )); err != nil {
239+ h .Logf ("failed to dump resource %s: %v" , resourceType , err )
240+ }
241+ }
242+ }
243+
244+ // dumpResource runs kubectl get for a resource type and writes the output to a file.
245+ // Errors are logged but do not fail the test.
246+ func (h * ValidatorHarness ) dumpResource (ns string , resourceType string , outputPath string ) error {
247+ args := []string {"get" , resourceType }
248+ if ns != "" {
249+ args = append (args , "-n" , ns )
250+ }
251+ args = append (args , "-o" , "yaml" )
252+ cmd := exec .CommandContext (context .WithoutCancel (h .Context ()), "kubectl" , args ... )
253+ var stdout bytes.Buffer
254+ var stderr bytes.Buffer
255+ cmd .Stdout = & stdout
256+ cmd .Stderr = & stderr
257+
258+ if err := cmd .Run (); err != nil {
259+ return fmt .Errorf ("failed to dump %s in namespace %s: %v (stderr: %s)" , resourceType , ns , err , stderr .String ())
260+ }
261+
262+ if err := os .WriteFile (outputPath , stdout .Bytes (), 0o644 ); err != nil {
263+ return fmt .Errorf ("failed to write %s dump to %s: %w" , resourceType , outputPath , err )
264+ }
265+
266+ return nil
267+ }
0 commit comments