@@ -3,20 +3,38 @@ package e2e
33import (
44 "context"
55 "fmt"
6+ "io"
7+ "os"
8+ "path/filepath"
9+ "strings"
610
711 . "github.com/onsi/ginkgo/v2"
812 . "github.com/onsi/gomega"
9-
13+ catalogd "github.com/operator-framework/catalogd/pkg/apis/core/v1beta1"
14+ operatorv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
15+ rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
16+ "gopkg.in/yaml.v2"
17+ appsv1 "k8s.io/api/apps/v1"
18+ corev1 "k8s.io/api/core/v1"
19+ v1 "k8s.io/api/core/v1"
1020 "k8s.io/apimachinery/pkg/api/errors"
1121 apimeta "k8s.io/apimachinery/pkg/api/meta"
1222 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1323 "k8s.io/apimachinery/pkg/types"
1424 "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"
1528
1629 catalogd "github.com/operator-framework/catalogd/api/core/v1alpha1"
1730 rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
1831
19- operatorv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
32+ const (
33+ defaultTimeout = 30 * time .Second
34+ defaultPoll = 1 * time .Second
35+ testCatalogRef = "localhost/testdata/catalogs/test-catalog:e2e"
36+ testCatalogName = "test-catalog"
37+ artifactName = "operator-controller-e2e"
2038)
2139
2240var _ = Describe ("Operator Install" , func () {
@@ -213,6 +231,10 @@ var _ = Describe("Operator Install", func() {
213231 })
214232
215233 AfterEach (func () {
234+ if basePath := env .GetString ("ARTIFACT_PATH" , "" ); basePath != "" {
235+ // get all the artifacts from the test run and save them to the artifact path
236+ getArtifactsOutput (ctx , basePath )
237+ }
216238 Expect (c .Delete (ctx , operator )).To (Succeed ())
217239 Eventually (func (g Gomega ) {
218240 err := c .Get (ctx , types.NamespacedName {Name : operator .Name }, & operatorv1alpha1.Operator {})
@@ -222,3 +244,163 @@ var _ = Describe("Operator Install", func() {
222244
223245 })
224246})
247+
248+ // getArtifactsOutput gets all the artifacts from the test run and saves them to the artifact path.
249+ // right now it will save:
250+ // - operators
251+ // - pods logs
252+ // - deployments
253+ // - bundle
254+ // - bundledeployments
255+ // - catalogsources
256+
257+ func getArtifactsOutput (ctx context.Context , basePath string ) {
258+ kubeClient , err := kubeclient .NewForConfig (cfg )
259+ Expect (err ).To (Not (HaveOccurred ()))
260+
261+ // sanitize the artifact name for use as a directory name
262+ testName := strings .ReplaceAll (strings .ToLower (CurrentSpecReport ().LeafNodeText ), " " , "-" )
263+ // Get the test description and sanitize it for use as a directory name
264+ artifactPath := filepath .Join (basePath , artifactName , fmt .Sprint (time .Now ().UnixNano ()), testName )
265+
266+ // Create the full artifact path
267+ err = os .MkdirAll (artifactPath , 0755 )
268+ Expect (err ).To (Not (HaveOccurred ()))
269+
270+ // Get all namespaces
271+ namespaces := corev1.NamespaceList {}
272+ if err := c .List (ctx , & namespaces ); err != nil {
273+ GinkgoWriter .Printf ("Failed to list namespaces %w" , err )
274+ }
275+
276+ // get all operators save them to the artifact path.
277+ operators := operatorv1alpha1.OperatorList {}
278+ if err := c .List (ctx , & operators , client .InNamespace ("" )); err != nil {
279+ GinkgoWriter .Printf ("Failed to list operators %w" , err )
280+ }
281+ for _ , operator := range operators .Items {
282+ // Save operator to artifact path
283+ operatorYaml , err := yaml .Marshal (operator )
284+ if err != nil {
285+ GinkgoWriter .Printf ("Failed to marshal operator %w" , err )
286+ continue
287+ }
288+ if err := os .WriteFile (filepath .Join (artifactPath , operator .Name + "-operator.yaml" ), operatorYaml , 0644 ); err != nil {
289+ GinkgoWriter .Printf ("Failed to write operator to file %w" , err )
290+ }
291+ }
292+
293+ // get all catalogsources save them to the artifact path.
294+ catalogsources := catalogd.CatalogList {}
295+ if err := c .List (ctx , & catalogsources , client .InNamespace ("" )); err != nil {
296+ GinkgoWriter .Printf ("Failed to list catalogsources %w" , err )
297+ }
298+ for _ , catalogsource := range catalogsources .Items {
299+ // Save catalogsource to artifact path
300+ catalogsourceYaml , err := yaml .Marshal (catalogsource )
301+ if err != nil {
302+ GinkgoWriter .Printf ("Failed to marshal catalogsource %w" , err )
303+ continue
304+ }
305+ if err := os .WriteFile (filepath .Join (artifactPath , catalogsource .Name + "-catalogsource.yaml" ), catalogsourceYaml , 0644 ); err != nil {
306+ GinkgoWriter .Printf ("Failed to write catalogsource to file %w" , err )
307+ }
308+ }
309+
310+ // Get all Bundles in the namespace and save them to the artifact path.
311+ bundles := rukpakv1alpha1.BundleList {}
312+ if err := c .List (ctx , & bundles , client .InNamespace ("" )); err != nil {
313+ GinkgoWriter .Printf ("Failed to list bundles %w" , err )
314+ }
315+ for _ , bundle := range bundles .Items {
316+ // Save bundle to artifact path
317+ bundleYaml , err := yaml .Marshal (bundle )
318+ if err != nil {
319+ GinkgoWriter .Printf ("Failed to marshal bundle %w" , err )
320+ continue
321+ }
322+ if err := os .WriteFile (filepath .Join (artifactPath , bundle .Name + "-bundle.yaml" ), bundleYaml , 0644 ); err != nil {
323+ GinkgoWriter .Printf ("Failed to write bundle to file %w" , err )
324+ }
325+ }
326+
327+ // Get all BundleDeployments in the namespace and save them to the artifact path.
328+ bundleDeployments := rukpakv1alpha1.BundleDeploymentList {}
329+ if err := c .List (ctx , & bundleDeployments , client .InNamespace ("" )); err != nil {
330+ GinkgoWriter .Printf ("Failed to list bundleDeployments %w" , err )
331+ }
332+ for _ , bundleDeployment := range bundleDeployments .Items {
333+ // Save bundleDeployment to artifact path
334+ bundleDeploymentYaml , err := yaml .Marshal (bundleDeployment )
335+ if err != nil {
336+ GinkgoWriter .Printf ("Failed to marshal bundleDeployment %w" , err )
337+ continue
338+ }
339+ if err := os .WriteFile (filepath .Join (artifactPath , bundleDeployment .Name + "-bundleDeployment.yaml" ), bundleDeploymentYaml , 0644 ); err != nil {
340+ GinkgoWriter .Printf ("Failed to write bundleDeployment to file %w" , err )
341+ }
342+ }
343+
344+ for _ , namespace := range namespaces .Items {
345+ // let's ignore kube-* namespaces.
346+ if strings .Contains (namespace .Name , "kube-" ) {
347+ continue
348+ }
349+
350+ namespacedArtifactPath := filepath .Join (artifactPath , namespace .Name )
351+ if err := os .Mkdir (namespacedArtifactPath , 0755 ); err != nil {
352+ GinkgoWriter .Printf ("Failed to create namespaced artifact path %w" , err )
353+ continue
354+ }
355+
356+ // get all deployments in the namespace and save them to the artifact path.
357+ deployments := appsv1.DeploymentList {}
358+ if err := c .List (ctx , & deployments , client .InNamespace (namespace .Name )); err != nil {
359+ GinkgoWriter .Printf ("Failed to list deployments %w in namespace: %q" , err , namespace .Name )
360+ continue
361+ }
362+
363+ for _ , deployment := range deployments .Items {
364+ // Save deployment to artifact path
365+ deploymentYaml , err := yaml .Marshal (deployment )
366+ if err != nil {
367+ GinkgoWriter .Printf ("Failed to marshal deployment %w" , err )
368+ continue
369+ }
370+ if err := os .WriteFile (filepath .Join (namespacedArtifactPath , deployment .Name + "-deployment.yaml" ), deploymentYaml , 0644 ); err != nil {
371+ GinkgoWriter .Printf ("Failed to write deployment to file %w" , err )
372+ }
373+ }
374+
375+ // Get logs from all pods in all namespaces
376+ pods := corev1.PodList {}
377+ if err := c .List (ctx , & pods , client .InNamespace (namespace .Name )); err != nil {
378+ GinkgoWriter .Printf ("Failed to list pods %w in namespace: %q" , err , namespace .Name )
379+ }
380+ for _ , pod := range pods .Items {
381+ if pod .Status .Phase != v1 .PodRunning && pod .Status .Phase != v1 .PodSucceeded && pod .Status .Phase != v1 .PodFailed {
382+ continue
383+ }
384+ for _ , container := range pod .Spec .Containers {
385+ logs , err := kubeClient .CoreV1 ().Pods (namespace .Name ).GetLogs (pod .Name , & v1.PodLogOptions {Container : container .Name }).Stream (ctx )
386+ if err != nil {
387+ GinkgoWriter .Printf ("Failed to get logs for pod %q in namespace %q: %w" , pod .Name , namespace .Name , err )
388+ continue
389+ }
390+ defer logs .Close ()
391+
392+ outFile , err := os .Create (filepath .Join (namespacedArtifactPath , pod .Name + "-" + container .Name + "-logs.txt" ))
393+ if err != nil {
394+ GinkgoWriter .Printf ("Failed to create file for pod %q in namespace %q: %w" , pod .Name , namespace .Name , err )
395+ continue
396+ }
397+ defer outFile .Close ()
398+
399+ if _ , err := io .Copy (outFile , logs ); err != nil {
400+ GinkgoWriter .Printf ("Failed to copy logs for pod %q in namespace %q: %w" , pod .Name , namespace .Name , err )
401+ continue
402+ }
403+ }
404+ }
405+ }
406+ }
0 commit comments