@@ -3,22 +3,34 @@ package e2e
33import  (
44	"context" 
55	"fmt" 
6+ 	"io" 
7+ 	"os" 
8+ 	"path/filepath" 
9+ 	"strings" 
610	"time" 
711
812	. "github.com/onsi/ginkgo/v2" 
913	. "github.com/onsi/gomega" 
1014	catalogd "github.com/operator-framework/catalogd/pkg/apis/core/v1beta1" 
1115	operatorv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" 
1216	rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" 
17+ 	"gopkg.in/yaml.v2" 
18+ 	appsv1 "k8s.io/api/apps/v1" 
19+ 	corev1 "k8s.io/api/core/v1" 
20+ 	v1 "k8s.io/api/core/v1" 
1321	apimeta "k8s.io/apimachinery/pkg/api/meta" 
1422	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 
1523	"k8s.io/apimachinery/pkg/types" 
1624	"k8s.io/apimachinery/pkg/util/rand" 
25+ 	kubeclient "k8s.io/client-go/kubernetes" 
26+ 	"k8s.io/utils/env" 
27+ 	"sigs.k8s.io/controller-runtime/pkg/client" 
1728)
1829
1930const  (
2031	defaultTimeout  =  30  *  time .Second 
2132	defaultPoll     =  1  *  time .Second 
33+ 	artifactName    =  "operator-controller-e2e" 
2234)
2335
2436var  _  =  Describe ("Operator Install" , func () {
@@ -104,10 +116,174 @@ var _ = Describe("Operator Install", func() {
104116
105117		})
106118		AfterEach (func () {
119+ 			if  basePath  :=  env .GetString ("ARTIFACT_PATH" , "" ); basePath  !=  ""  &&  CurrentSpecReport ().Failed () {
120+ 				// get all the artifacts from the test run and save them to the artifact path 
121+ 				getArtifactsOutput (ctx , basePath )
122+ 			}
107123			err  :=  c .Delete (ctx , operatorCatalog )
108124			Expect (err ).ToNot (HaveOccurred ())
109125			err  =  c .Delete (ctx , operator )
110126			Expect (err ).ToNot (HaveOccurred ())
111127		})
112128	})
113129})
130+ 
131+ // getArtifactsOutput gets all the artifacts from the test run and saves them to the artifact path. 
132+ // right now it will save: 
133+ // - operators 
134+ // - pods logs 
135+ // - deployments 
136+ // - bundle 
137+ // - bundledeployments 
138+ // - catalogsources 
139+ 
140+ func  getArtifactsOutput (ctx  context.Context , basePath  string ) {
141+ 	kubeClient , err  :=  kubeclient .NewForConfig (cfg )
142+ 	Expect (err ).To (Not (HaveOccurred ()))
143+ 
144+ 	// sanitize the artifact name for use as a directory name 
145+ 	testName  :=  strings .ReplaceAll (strings .ToLower (CurrentSpecReport ().LeafNodeText ), " " , "-" )
146+ 	// Get the test description and sanitize it for use as a directory name 
147+ 	artifactPath  :=  filepath .Join (basePath , artifactName , fmt .Sprint (time .Now ().UnixNano ()), testName )
148+ 
149+ 	// Create the full artifact path 
150+ 	err  =  os .MkdirAll (artifactPath , 0755 )
151+ 	Expect (err ).To (Not (HaveOccurred ()))
152+ 
153+ 	// Get all namespaces 
154+ 	namespaces  :=  corev1.NamespaceList {}
155+ 	if  err  :=  c .List (ctx , & namespaces ); err  !=  nil  {
156+ 		GinkgoWriter .Printf ("Failed to list namespaces %w" , err )
157+ 	}
158+ 
159+ 	// get all operators save them to the artifact path. 
160+ 	operators  :=  operatorv1alpha1.OperatorList {}
161+ 	if  err  :=  c .List (ctx , & operators , client .InNamespace ("" )); err  !=  nil  {
162+ 		GinkgoWriter .Printf ("Failed to list operators %w" , err )
163+ 	}
164+ 	for  _ , operator  :=  range  operators .Items  {
165+ 		// Save operator to artifact path 
166+ 		operatorYaml , err  :=  yaml .Marshal (operator )
167+ 		if  err  !=  nil  {
168+ 			GinkgoWriter .Printf ("Failed to marshal operator %w" , err )
169+ 			continue 
170+ 		}
171+ 		if  err  :=  os .WriteFile (filepath .Join (artifactPath , operator .Name + "-operator.yaml" ), operatorYaml , 0644 ); err  !=  nil  {
172+ 			GinkgoWriter .Printf ("Failed to write operator to file %w" , err )
173+ 		}
174+ 	}
175+ 
176+ 	// get all catalogsources save them to the artifact path. 
177+ 	catalogsources  :=  catalogd.CatalogList {}
178+ 	if  err  :=  c .List (ctx , & catalogsources , client .InNamespace ("" )); err  !=  nil  {
179+ 		GinkgoWriter .Printf ("Failed to list catalogsources %w" , err )
180+ 	}
181+ 	for  _ , catalogsource  :=  range  catalogsources .Items  {
182+ 		// Save catalogsource to artifact path 
183+ 		catalogsourceYaml , err  :=  yaml .Marshal (catalogsource )
184+ 		if  err  !=  nil  {
185+ 			GinkgoWriter .Printf ("Failed to marshal catalogsource %w" , err )
186+ 			continue 
187+ 		}
188+ 		if  err  :=  os .WriteFile (filepath .Join (artifactPath , catalogsource .Name + "-catalogsource.yaml" ), catalogsourceYaml , 0644 ); err  !=  nil  {
189+ 			GinkgoWriter .Printf ("Failed to write catalogsource to file %w" , err )
190+ 		}
191+ 	}
192+ 
193+ 	// Get all Bundles in the namespace and save them to the artifact path. 
194+ 	bundles  :=  rukpakv1alpha1.BundleList {}
195+ 	if  err  :=  c .List (ctx , & bundles , client .InNamespace ("" )); err  !=  nil  {
196+ 		GinkgoWriter .Printf ("Failed to list bundles %w" , err )
197+ 	}
198+ 	for  _ , bundle  :=  range  bundles .Items  {
199+ 		// Save bundle to artifact path 
200+ 		bundleYaml , err  :=  yaml .Marshal (bundle )
201+ 		if  err  !=  nil  {
202+ 			GinkgoWriter .Printf ("Failed to marshal bundle %w" , err )
203+ 			continue 
204+ 		}
205+ 		if  err  :=  os .WriteFile (filepath .Join (artifactPath , bundle .Name + "-bundle.yaml" ), bundleYaml , 0644 ); err  !=  nil  {
206+ 			GinkgoWriter .Printf ("Failed to write bundle to file %w" , err )
207+ 		}
208+ 	}
209+ 
210+ 	// Get all BundleDeployments in the namespace and save them to the artifact path. 
211+ 	bundleDeployments  :=  rukpakv1alpha1.BundleDeploymentList {}
212+ 	if  err  :=  c .List (ctx , & bundleDeployments , client .InNamespace ("" )); err  !=  nil  {
213+ 		GinkgoWriter .Printf ("Failed to list bundleDeployments %w" , err )
214+ 	}
215+ 	for  _ , bundleDeployment  :=  range  bundleDeployments .Items  {
216+ 		// Save bundleDeployment to artifact path 
217+ 		bundleDeploymentYaml , err  :=  yaml .Marshal (bundleDeployment )
218+ 		if  err  !=  nil  {
219+ 			GinkgoWriter .Printf ("Failed to marshal bundleDeployment %w" , err )
220+ 			continue 
221+ 		}
222+ 		if  err  :=  os .WriteFile (filepath .Join (artifactPath , bundleDeployment .Name + "-bundleDeployment.yaml" ), bundleDeploymentYaml , 0644 ); err  !=  nil  {
223+ 			GinkgoWriter .Printf ("Failed to write bundleDeployment to file %w" , err )
224+ 		}
225+ 	}
226+ 
227+ 	for  _ , namespace  :=  range  namespaces .Items  {
228+ 		// let's ignore kube-* namespaces. 
229+ 		if  strings .Contains (namespace .Name , "kube-" ) {
230+ 			continue 
231+ 		}
232+ 
233+ 		namespacedArtifactPath  :=  filepath .Join (artifactPath , namespace .Name )
234+ 		if  err  :=  os .Mkdir (namespacedArtifactPath , 0755 ); err  !=  nil  {
235+ 			GinkgoWriter .Printf ("Failed to create namespaced artifact path %w" , err )
236+ 			continue 
237+ 		}
238+ 
239+ 		// get all deployments in the namespace and save them to the artifact path. 
240+ 		deployments  :=  appsv1.DeploymentList {}
241+ 		if  err  :=  c .List (ctx , & deployments , client .InNamespace (namespace .Name )); err  !=  nil  {
242+ 			GinkgoWriter .Printf ("Failed to list deployments %w in namespace: %q" , err , namespace .Name )
243+ 			continue 
244+ 		}
245+ 
246+ 		for  _ , deployment  :=  range  deployments .Items  {
247+ 			// Save deployment to artifact path 
248+ 			deploymentYaml , err  :=  yaml .Marshal (deployment )
249+ 			if  err  !=  nil  {
250+ 				GinkgoWriter .Printf ("Failed to marshal deployment %w" , err )
251+ 				continue 
252+ 			}
253+ 			if  err  :=  os .WriteFile (filepath .Join (namespacedArtifactPath , deployment .Name + "-deployment.yaml" ), deploymentYaml , 0644 ); err  !=  nil  {
254+ 				GinkgoWriter .Printf ("Failed to write deployment to file %w" , err )
255+ 			}
256+ 		}
257+ 
258+ 		// Get logs from all pods in all namespaces 
259+ 		pods  :=  corev1.PodList {}
260+ 		if  err  :=  c .List (ctx , & pods , client .InNamespace (namespace .Name )); err  !=  nil  {
261+ 			GinkgoWriter .Printf ("Failed to list pods %w in namespace: %q" , err , namespace .Name )
262+ 		}
263+ 		for  _ , pod  :=  range  pods .Items  {
264+ 			if  pod .Status .Phase  !=  v1 .PodRunning  &&  pod .Status .Phase  !=  v1 .PodSucceeded  &&  pod .Status .Phase  !=  v1 .PodFailed  {
265+ 				continue 
266+ 			}
267+ 			for  _ , container  :=  range  pod .Spec .Containers  {
268+ 				logs , err  :=  kubeClient .CoreV1 ().Pods (namespace .Name ).GetLogs (pod .Name , & v1.PodLogOptions {Container : container .Name }).Stream (ctx )
269+ 				if  err  !=  nil  {
270+ 					GinkgoWriter .Printf ("Failed to get logs for pod %q in namespace %q: %w" , pod .Name , namespace .Name , err )
271+ 					continue 
272+ 				}
273+ 				defer  logs .Close ()
274+ 
275+ 				outFile , err  :=  os .Create (filepath .Join (namespacedArtifactPath , pod .Name + "-" + container .Name + "-logs.txt" ))
276+ 				if  err  !=  nil  {
277+ 					GinkgoWriter .Printf ("Failed to create file for pod %q in namespace %q: %w" , pod .Name , namespace .Name , err )
278+ 					continue 
279+ 				}
280+ 				defer  outFile .Close ()
281+ 
282+ 				if  _ , err  :=  io .Copy (outFile , logs ); err  !=  nil  {
283+ 					GinkgoWriter .Printf ("Failed to copy logs for pod %q in namespace %q: %w" , pod .Name , namespace .Name , err )
284+ 					continue 
285+ 				}
286+ 			}
287+ 		}
288+ 	}
289+ }
0 commit comments