Skip to content

Commit 3eefb51

Browse files
committed
use setup-envtest to download kubebuilder toolchain
1 parent 6d6cb5c commit 3eefb51

File tree

2 files changed

+77
-51
lines changed

2 files changed

+77
-51
lines changed

Diff for: test/e2e-bootstrap/bootstrap_test.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,9 @@ import (
3737
)
3838

3939
const (
40-
bootstrapTestName = "BootstrapTest"
41-
templatesDir = "../../templates"
42-
bootstrapTestDataDir = "../../pkg/controller/bootstrap/testdata/bootstrap"
43-
openshiftConfigNamespace = "openshift-config"
40+
bootstrapTestName = "BootstrapTest"
41+
templatesDir = "../../templates"
42+
bootstrapTestDataDir = "../../pkg/controller/bootstrap/testdata/bootstrap"
4443
)
4544

4645
var (
@@ -58,7 +57,7 @@ type fixture struct {
5857
func TestE2EBootstrap(t *testing.T) {
5958
ctx := context.Background()
6059

61-
testEnv := framework.NewTestEnv()
60+
testEnv := framework.NewTestEnv(t)
6261

6362
configv1.Install(scheme.Scheme)
6463
mcfgv1.Install(scheme.Scheme)
@@ -76,7 +75,7 @@ func TestE2EBootstrap(t *testing.T) {
7675

7776
_, err = clientSet.Namespaces().Create(ctx, &corev1.Namespace{
7877
ObjectMeta: metav1.ObjectMeta{
79-
Name: openshiftConfigNamespace,
78+
Name: framework.OpenshiftConfigNamespace,
8079
},
8180
}, metav1.CreateOptions{})
8281
require.NoError(t, err)

Diff for: test/framework/envtest.go

+72-45
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package framework
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
7+
"io"
68
"os"
79
"os/exec"
810
"path/filepath"
911
"testing"
1012

11-
goruntime "runtime"
12-
1313
"github.com/stretchr/testify/require"
1414
"sigs.k8s.io/controller-runtime/pkg/envtest"
1515

@@ -23,73 +23,96 @@ import (
2323
)
2424

2525
const (
26-
openshiftConfigNamespace string = "openshift-config"
27-
kubebuilderPath string = "/tmp/kubebuilder"
28-
envTestPath string = kubebuilderPath + "/bin"
26+
OpenshiftConfigNamespace string = "openshift-config"
2927

3028
// TODO: Figure out how to obtain this value programmatically so we don't
3129
// have to remember to increment it.
3230
k8sVersion string = "1.22.1"
3331
)
3432

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
3945
}
4046

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)
4454

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
4758
}
4859

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+
}
5475

55-
fmt.Println("Executing", cmd)
76+
homeDir, overrideHomeDir := overrideHomeDir(t)
5677

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)
6280
}
6381

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)
6584

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
6791

6892
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)
7094
}
7195

72-
return nil
73-
}
96+
t.Log("setup-envtest complete!")
7497

75-
func NewTestEnv() *envtest.Environment {
76-
if err := fetchTools(); err != nil {
77-
panic(err)
78-
}
98+
return pathBuffer.String(), nil
99+
}
79100

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)
84104

85105
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,
91114
},
92-
BinaryAssetsDirectory: envTestPath,
115+
BinaryAssetsDirectory: toolsPath,
93116
}
94117
}
95118

@@ -132,6 +155,8 @@ func CheckCleanEnvironment(t *testing.T, clientSet *ClientSet) {
132155
namespaceList, err := clientSet.Namespaces().List(ctx, metav1.ListOptions{})
133156
require.NoError(t, err)
134157

158+
// Iterate through each namespace for namespace-scoped objects so we can
159+
// ensure they've been deleted.
135160
for _, namespace := range namespaceList.Items {
136161
namespaceName := namespace.GetName()
137162

@@ -231,6 +256,8 @@ func CleanEnvironment(t *testing.T, clientSet *ClientSet) {
231256
namespaceList, err := clientSet.Namespaces().List(ctx, metav1.ListOptions{})
232257
require.NoError(t, err)
233258

259+
// Iterate through each namespace for namespace-scoped objects so we can
260+
// delete them from all known namespaces.
234261
for _, namespace := range namespaceList.Items {
235262
namespaceName := namespace.GetName()
236263

@@ -293,7 +320,7 @@ func CreateObjects(t *testing.T, clientSet *ClientSet, objs ...runtime.Object) {
293320
o := tObj.DeepCopy()
294321
o.Spec.PullSecret = &corev1.ObjectReference{
295322
Name: "pull-secret",
296-
Namespace: openshiftConfigNamespace,
323+
Namespace: OpenshiftConfigNamespace,
297324
}
298325

299326
_, err := clientSet.ControllerConfigs().Create(ctx, o, metav1.CreateOptions{})

0 commit comments

Comments
 (0)