1
1
package framework
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"fmt"
7
+ "io"
6
8
"os"
7
9
"os/exec"
8
10
"path/filepath"
9
11
"testing"
10
12
11
- goruntime "runtime"
12
-
13
13
"github.com/stretchr/testify/require"
14
14
"sigs.k8s.io/controller-runtime/pkg/envtest"
15
15
@@ -23,73 +23,96 @@ import (
23
23
)
24
24
25
25
const (
26
- openshiftConfigNamespace string = "openshift-config"
27
- kubebuilderPath string = "/tmp/kubebuilder"
28
- envTestPath string = kubebuilderPath + "/bin"
26
+ OpenshiftConfigNamespace string = "openshift-config"
29
27
30
28
// TODO: Figure out how to obtain this value programmatically so we don't
31
29
// have to remember to increment it.
32
30
k8sVersion string = "1.22.1"
33
31
)
34
32
35
- func fetchTools () error {
36
- if _ , ok := os .LookupEnv ("SKIP_FETCH_TOOLS" ); ok {
37
- fmt .Println ("SKIP_FETCH_TOOLS set, skipping!" )
38
- return nil
33
+ // This is needed because both setup-envtest and the kubebuilder tools assume
34
+ // that HOME is set to a writable value. While running locally, this is
35
+ // generally a given, it is not in OpenShift CI. OpenShift CI usually defaults
36
+ // to "/" as the HOME value, which is not writable.
37
+ //
38
+ // TODO: Pre-fetch the kubebuilder binaries as part of the build-root process
39
+ // so we only have to fetch the kubebuilder tools once.
40
+ func overrideHomeDir (t * testing.T ) (string , bool ) {
41
+ homeDir := os .Getenv ("HOME" )
42
+ if homeDir != "" && homeDir != "/" {
43
+ t .Logf ("HOME env var set to %s, will use as-is" , homeDir )
44
+ return "" , false
39
45
}
40
46
41
- toolsArchiveName := fmt .Sprintf ("kubebuilder-tools-%s-%s-%s.tar.gz" , k8sVersion , goruntime .GOOS , goruntime .GOARCH )
42
- downloadURL := fmt .Sprintf ("https://storage.googleapis.com/kubebuilder-tools/%s" , toolsArchiveName )
43
- toolsArchiveDownloadPath := filepath .Join ("/tmp/kubebuilder" , toolsArchiveName )
47
+ // For the purposes of this library, we will use the repo root
48
+ // (/go/src/github.com/openshift/machine-config-operator). This is so that we
49
+ // have a predictable HOME value which enables setup-envtest to reuse a
50
+ // kubebuilder tool package across multiple test suites (assuming they run in
51
+ // the same pod).
52
+ overrideHomeDir , err := os .Getwd ()
53
+ require .NoError (t , err )
44
54
45
- if err := os .MkdirAll (envTestPath , 0755 ); err != nil {
46
- return fmt .Errorf ("could not mkdir: %w" , err )
55
+ if homeDir == "/" {
56
+ t .Log ("HOME env var set to '/', overriding with" , overrideHomeDir )
57
+ return overrideHomeDir , true
47
58
}
48
59
49
- // Check if we have the archive on disk. If not, we should retrieve it.
50
- if _ , err := os .Stat (toolsArchiveDownloadPath ); os .IsNotExist (err ) {
51
- // While it is possible to write this and the tar extract below in pure Go, I
52
- // opted to shell out to preexisting tools for brevity.
53
- cmd := exec .Command ("curl" , "-fsL" , downloadURL , "-o" , toolsArchiveDownloadPath )
60
+ t .Log ("HOME env var not set, overriding with" , overrideHomeDir )
61
+ return overrideHomeDir , true
62
+ }
63
+
64
+ // Instead of using a couple of ad-hoc shell scripts, envtest helpfully
65
+ // includes a setup utility (setup-envtest) that will retrieve the appropriate
66
+ // version of the kubebuilder toolchain for a given GOOS / GOARCH and K8s
67
+ // version. setup-envtest can also allow the toolchain to be prefetched and
68
+ // will cache it. This way, if multiple envtest targets are running in the same
69
+ // CI test pod, it will only fetch kubebuilder for the first suite.
70
+ func setupEnvTest (t * testing.T ) (string , error ) {
71
+ setupEnvTestBinPath , err := exec .LookPath ("setup-envtest" )
72
+ if err != nil {
73
+ return "" , fmt .Errorf ("setup-envtest not installed, see installation instructions: https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest" )
74
+ }
54
75
55
- fmt . Println ( "Executing" , cmd )
76
+ homeDir , overrideHomeDir := overrideHomeDir ( t )
56
77
57
- if err := cmd .Run (); err != nil {
58
- return fmt .Errorf ("could not download tools archive: %w" , err )
59
- }
60
- } else {
61
- fmt .Println ("Found preexisting tools archive" , toolsArchiveDownloadPath )
78
+ if overrideHomeDir {
79
+ os .Setenv ("HOME" , homeDir )
62
80
}
63
81
64
- cmd := exec .Command ("tar" , "-zvxf" , toolsArchiveDownloadPath , "-C" , "/tmp/" )
82
+ cmd := exec .Command (setupEnvTestBinPath , "use" , k8sVersion , "-p" , "path" )
83
+ t .Log ("Setting up EnvTest: $" , cmd )
65
84
66
- fmt .Println ("Executing" , cmd )
85
+ // We want to consume the path of where setup-envtest installed the
86
+ // kubebuilder toolchain. So we capture stdout from setup-envtest (as well as
87
+ // write it to os.Stdout for debugging purposes).
88
+ pathBuffer := bytes .NewBuffer ([]byte {})
89
+ cmd .Stdout = io .MultiWriter (pathBuffer , os .Stdout )
90
+ cmd .Stderr = os .Stderr
67
91
68
92
if err := cmd .Run (); err != nil {
69
- return fmt .Errorf ("could not extract tools archive: %w" , err )
93
+ return "" , fmt .Errorf ("could not fetch envtest archive: %w" , err )
70
94
}
71
95
72
- return nil
73
- }
96
+ t .Log ("setup-envtest complete!" )
74
97
75
- func NewTestEnv () * envtest.Environment {
76
- if err := fetchTools (); err != nil {
77
- panic (err )
78
- }
98
+ return pathBuffer .String (), nil
99
+ }
79
100
80
- home := os .Getenv ("HOME" )
81
- if home == "/" || home == "" {
82
- os .Setenv ("HOME" , kubebuilderPath )
83
- }
101
+ func NewTestEnv (t * testing.T ) * envtest.Environment {
102
+ toolsPath , err := setupEnvTest (t )
103
+ require .NoError (t , err )
84
104
85
105
return & envtest.Environment {
86
- CRDDirectoryPaths : []string {
87
- filepath .Join (".." , ".." , "install" ),
88
- filepath .Join (".." , ".." , "manifests" , "controllerconfig.crd.yaml" ),
89
- filepath .Join (".." , ".." , "vendor" , "github.com" , "openshift" , "api" , "config" , "v1" ),
90
- filepath .Join (".." , ".." , "vendor" , "github.com" , "openshift" , "api" , "operator" , "v1alpha1" ),
106
+ CRDInstallOptions : envtest.CRDInstallOptions {
107
+ Paths : []string {
108
+ filepath .Join (".." , ".." , "install" ),
109
+ filepath .Join (".." , ".." , "manifests" , "controllerconfig.crd.yaml" ),
110
+ filepath .Join (".." , ".." , "vendor" , "github.com" , "openshift" , "api" , "config" , "v1" ),
111
+ filepath .Join (".." , ".." , "vendor" , "github.com" , "openshift" , "api" , "operator" , "v1alpha1" ),
112
+ },
113
+ CleanUpAfterUse : true ,
91
114
},
92
- BinaryAssetsDirectory : envTestPath ,
115
+ BinaryAssetsDirectory : toolsPath ,
93
116
}
94
117
}
95
118
@@ -132,6 +155,8 @@ func CheckCleanEnvironment(t *testing.T, clientSet *ClientSet) {
132
155
namespaceList , err := clientSet .Namespaces ().List (ctx , metav1.ListOptions {})
133
156
require .NoError (t , err )
134
157
158
+ // Iterate through each namespace for namespace-scoped objects so we can
159
+ // ensure they've been deleted.
135
160
for _ , namespace := range namespaceList .Items {
136
161
namespaceName := namespace .GetName ()
137
162
@@ -231,6 +256,8 @@ func CleanEnvironment(t *testing.T, clientSet *ClientSet) {
231
256
namespaceList , err := clientSet .Namespaces ().List (ctx , metav1.ListOptions {})
232
257
require .NoError (t , err )
233
258
259
+ // Iterate through each namespace for namespace-scoped objects so we can
260
+ // delete them from all known namespaces.
234
261
for _ , namespace := range namespaceList .Items {
235
262
namespaceName := namespace .GetName ()
236
263
@@ -293,7 +320,7 @@ func CreateObjects(t *testing.T, clientSet *ClientSet, objs ...runtime.Object) {
293
320
o := tObj .DeepCopy ()
294
321
o .Spec .PullSecret = & corev1.ObjectReference {
295
322
Name : "pull-secret" ,
296
- Namespace : openshiftConfigNamespace ,
323
+ Namespace : OpenshiftConfigNamespace ,
297
324
}
298
325
299
326
_ , err := clientSet .ControllerConfigs ().Create (ctx , o , metav1.CreateOptions {})
0 commit comments