Skip to content

Commit c19de65

Browse files
committed
Expose logs/resources after test run
Signed-off-by: Joaquim Moreno Prusi <joaquim@redhat.com>
1 parent d6aa5e9 commit c19de65

File tree

5 files changed

+156
-8
lines changed

5 files changed

+156
-8
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export RUKPAK_VERSION=$(shell go list -mod=mod -m -f "{{.Version}}" github.com/o
1212
export WAIT_TIMEOUT ?= 60s
1313
IMG?=$(IMAGE_REPO):$(IMAGE_TAG)
1414

15+
# ARTIFACT_PATH is the absolute path to the directory where the operator-controller e2e tests will store the artifacts
16+
# for example: ARTIFACT_PATH=/tmp/artifacts make test
17+
export ARTIFACT_PATH ?=
18+
1519
OPERATOR_CONTROLLER_NAMESPACE ?= operator-controller-system
1620
KIND_CLUSTER_NAME ?= operator-controller
1721

go.mod

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ require (
1717
sigs.k8s.io/controller-runtime v0.14.4
1818
)
1919

20+
require github.com/sirupsen/logrus v1.9.0 // indirect
21+
2022
require (
2123
github.com/beorn7/perks v1.0.1 // indirect
2224
github.com/cespare/xxhash/v2 v2.1.2 // indirect
@@ -48,13 +50,12 @@ require (
4850
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4951
github.com/modern-go/reflect2 v1.0.2 // indirect
5052
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
51-
github.com/operator-framework/api v0.17.3 // indirect
53+
github.com/operator-framework/api v0.17.6 // indirect
5254
github.com/pkg/errors v0.9.1 // indirect
5355
github.com/prometheus/client_golang v1.14.0 // indirect
5456
github.com/prometheus/client_model v0.3.0 // indirect
5557
github.com/prometheus/common v0.37.0 // indirect
5658
github.com/prometheus/procfs v0.8.0 // indirect
57-
github.com/sirupsen/logrus v1.9.0 // indirect
5859
github.com/spf13/pflag v1.0.5 // indirect
5960
go.uber.org/atomic v1.7.0 // indirect
6061
go.uber.org/multierr v1.6.0 // indirect
@@ -69,9 +70,9 @@ require (
6970
google.golang.org/appengine v1.6.7 // indirect
7071
google.golang.org/protobuf v1.28.1 // indirect
7172
gopkg.in/inf.v0 v0.9.1 // indirect
72-
gopkg.in/yaml.v2 v2.4.0 // indirect
73+
gopkg.in/yaml.v2 v2.4.0
7374
gopkg.in/yaml.v3 v3.0.1 // indirect
74-
k8s.io/api v0.26.1 // indirect
75+
k8s.io/api v0.26.1
7576
k8s.io/apiextensions-apiserver v0.26.1 // indirect
7677
k8s.io/apiserver v0.26.1 // indirect
7778
k8s.io/component-base v0.26.1 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ github.com/onsi/ginkgo/v2 v2.8.3 h1:RpbK1G8nWPNaCVFBWsOGnEQQGgASi6b8fxcWBvDYjxQ=
236236
github.com/onsi/ginkgo/v2 v2.8.3/go.mod h1:6OaUA8BCi0aZfmzYT/q9AacwTzDpNbxILUT+TlBq6MY=
237237
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
238238
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
239-
github.com/operator-framework/api v0.17.3 h1:wddE1SLKTNiIzwt28DbBIO+vPG2GOV6dkB9xBkDfT3o=
240-
github.com/operator-framework/api v0.17.3/go.mod h1:34tb98EwTN5SZLkgoxwvRkhMJKLHUWHOrrcv1ZwvEeA=
239+
github.com/operator-framework/api v0.17.6 h1:E6+vlvYUKafvoXYtCuHlDZrXX4vl8AT+r93OxNlzjpU=
240+
github.com/operator-framework/api v0.17.6/go.mod h1:l/cuwtPxkVUY7fzYgdust2m9tlmb8I4pOvbsUufRb24=
241241
github.com/operator-framework/catalogd v0.1.3 h1:prQNmmQw2FEWO4631aSvTGMrFm1/pH9x+lM9f7KU6VE=
242242
github.com/operator-framework/catalogd v0.1.3/go.mod h1:CPnh6GWNwX5OTTeqnqjHFDXBGx1ZKmQ2v/4Q3bXN2qo=
243243
github.com/operator-framework/deppy v0.0.0-20230125110717-dc02e928470f h1:YxUZyQjF2kT2hli9ceBkuK7Mmiln0lV2RV38rzBObBI=

test/e2e/e2e_suite_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
. "github.com/onsi/ginkgo/v2"
88
. "github.com/onsi/gomega"
9+
appsv1 "k8s.io/api/apps/v1"
10+
corev1 "k8s.io/api/core/v1"
911
"k8s.io/apimachinery/pkg/runtime"
1012
"k8s.io/client-go/rest"
1113
ctrl "sigs.k8s.io/controller-runtime"
@@ -40,6 +42,13 @@ var _ = BeforeSuite(func() {
4042

4143
err = catalogd.AddToScheme(scheme)
4244
Expect(err).ToNot(HaveOccurred())
45+
46+
err = appsv1.AddToScheme(scheme)
47+
Expect(err).ToNot(HaveOccurred())
48+
49+
err = corev1.AddToScheme(scheme)
50+
Expect(err).ToNot(HaveOccurred())
51+
4352
c, err = client.New(cfg, client.Options{Scheme: scheme})
4453
Expect(err).To(Not(HaveOccurred()))
4554
})

test/e2e/install_test.go

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,34 @@ package e2e
33
import (
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

1930
const (
20-
defaultTimeout = 30 * time.Second
21-
defaultPoll = 1 * time.Second
31+
defaultTimeout = 30 * time.Second
32+
defaultPoll = 1 * time.Second
33+
artifactTestName = "operator-controller-e2e"
2234
)
2335

2436
var _ = Describe("Operator Install", func() {
@@ -99,10 +111,132 @@ var _ = Describe("Operator Install", func() {
99111

100112
})
101113
AfterEach(func() {
114+
if basePath := env.GetString("ARTIFACT_PATH", ""); basePath != "" {
115+
// get all the artifacts from the test run and save them to the artifact path
116+
getArtifactsOutput(ctx, basePath)
117+
}
102118
err := c.Delete(ctx, operatorCatalog)
103119
Expect(err).ToNot(HaveOccurred())
104120
err = c.Delete(ctx, operator)
105121
Expect(err).ToNot(HaveOccurred())
106122
})
107123
})
108124
})
125+
126+
// getArtifactsOutput gets all the artifacts from the test run and saves them to the artifact path.
127+
// right now it will save:
128+
// - operators
129+
// - pods logs
130+
// - deployments
131+
// - bundle
132+
// - bundledeployments
133+
// - catalogsources
134+
135+
func getArtifactsOutput(ctx context.Context, basePath string) {
136+
kubeClient, err := kubeclient.NewForConfig(cfg)
137+
Expect(err).To(Not(HaveOccurred()))
138+
139+
artifactPath := filepath.Join(basePath, artifactTestName, fmt.Sprint(time.Now().UnixNano()))
140+
141+
// Create the full artifact path
142+
err = os.MkdirAll(artifactPath, 0755)
143+
Expect(err).To(Not(HaveOccurred()))
144+
145+
// Get all namespaces
146+
namespaces := corev1.NamespaceList{}
147+
err = c.List(ctx, &namespaces)
148+
Expect(err).To(Not(HaveOccurred()))
149+
150+
// get all operators save them to the artifact path.
151+
operators := operatorv1alpha1.OperatorList{}
152+
err = c.List(ctx, &operators, client.InNamespace(""))
153+
Expect(err).To(Not(HaveOccurred()))
154+
for _, operator := range operators.Items {
155+
// Save operator to artifact path
156+
operatorYaml, err := yaml.Marshal(operator)
157+
Expect(err).To(Not(HaveOccurred()))
158+
err = os.WriteFile(filepath.Join(artifactPath, operator.Name+"-operator.yaml"), operatorYaml, 0644)
159+
Expect(err).To(Not(HaveOccurred()))
160+
}
161+
162+
// get all catalogsources save them to the artifact path.
163+
catalogsources := catalogd.CatalogSourceList{}
164+
err = c.List(ctx, &catalogsources, client.InNamespace(""))
165+
Expect(err).To(Not(HaveOccurred()))
166+
for _, catalogsource := range catalogsources.Items {
167+
// Save catalogsource to artifact path
168+
catalogsourceYaml, err := yaml.Marshal(catalogsource)
169+
Expect(err).To(Not(HaveOccurred()))
170+
err = os.WriteFile(filepath.Join(artifactPath, catalogsource.Name+"-catalogsource.yaml"), catalogsourceYaml, 0644)
171+
Expect(err).To(Not(HaveOccurred()))
172+
}
173+
174+
// Get all Bundles in the namespace and save them to the artifact path.
175+
bundles := rukpakv1alpha1.BundleList{}
176+
err = c.List(ctx, &bundles, client.InNamespace(""))
177+
Expect(err).To(Not(HaveOccurred()))
178+
for _, bundle := range bundles.Items {
179+
// Save bundle to artifact path
180+
bundleYaml, err := yaml.Marshal(bundle)
181+
Expect(err).To(Not(HaveOccurred()))
182+
err = os.WriteFile(filepath.Join(artifactPath, bundle.Name+"-bundle.yaml"), bundleYaml, 0644)
183+
Expect(err).To(Not(HaveOccurred()))
184+
}
185+
186+
// Get all BundleDeployments in the namespace and save them to the artifact path.
187+
bundleDeployments := rukpakv1alpha1.BundleDeploymentList{}
188+
err = c.List(ctx, &bundleDeployments, client.InNamespace(""))
189+
Expect(err).To(Not(HaveOccurred()))
190+
for _, bundleDeployment := range bundleDeployments.Items {
191+
// Save bundleDeployment to artifact path
192+
bundleDeploymentYaml, err := yaml.Marshal(bundleDeployment)
193+
Expect(err).To(Not(HaveOccurred()))
194+
err = os.WriteFile(filepath.Join(artifactPath, bundleDeployment.Name+"-bundleDeployment.yaml"), bundleDeploymentYaml, 0644)
195+
Expect(err).To(Not(HaveOccurred()))
196+
}
197+
198+
for _, namespace := range namespaces.Items {
199+
// let's ignore kube-* namespaces.
200+
if strings.Contains(namespace.Name, "kube-") {
201+
continue
202+
}
203+
204+
namespaceArtifactPath := filepath.Join(artifactPath, namespace.Name)
205+
err = os.Mkdir(namespaceArtifactPath, 0755)
206+
Expect(err).To(Not(HaveOccurred()))
207+
208+
// get all deployments in the namespace and save them to the artifact path.
209+
deployments := appsv1.DeploymentList{}
210+
err = c.List(ctx, &deployments, client.InNamespace(namespace.Name))
211+
Expect(err).To(Not(HaveOccurred()))
212+
for _, deployment := range deployments.Items {
213+
// Save deployment to artifact path
214+
deploymentYaml, err := yaml.Marshal(deployment)
215+
Expect(err).To(Not(HaveOccurred()))
216+
err = os.WriteFile(filepath.Join(namespaceArtifactPath, deployment.Name+"-deployment.yaml"), deploymentYaml, 0644)
217+
Expect(err).To(Not(HaveOccurred()))
218+
}
219+
220+
// Get logs from all pods in all namespaces
221+
pods := corev1.PodList{}
222+
err = c.List(ctx, &pods, client.InNamespace(namespace.Name))
223+
Expect(err).To(Not(HaveOccurred()))
224+
for _, pod := range pods.Items {
225+
if pod.Status.Phase != v1.PodRunning && pod.Status.Phase != v1.PodSucceeded && pod.Status.Phase != v1.PodFailed {
226+
continue
227+
}
228+
for _, container := range pod.Spec.Containers {
229+
logs, err := kubeClient.CoreV1().Pods(namespace.Name).GetLogs(pod.Name, &v1.PodLogOptions{Container: container.Name}).Stream(ctx)
230+
Expect(err).To(Not(HaveOccurred()))
231+
defer logs.Close()
232+
233+
outFile, err := os.Create(filepath.Join(namespaceArtifactPath, pod.Name+"-"+container.Name+"-logs.txt"))
234+
Expect(err).To(Not(HaveOccurred()))
235+
defer outFile.Close()
236+
237+
_, err = io.Copy(outFile, logs)
238+
Expect(err).To(Not(HaveOccurred()))
239+
}
240+
}
241+
}
242+
}

0 commit comments

Comments
 (0)