Description
Feature Request
Describe the problem you need a feature to resolve.
Currently, in Kubebuilder where the binaries are used we have :
# Run tests
ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
test: generate fmt vet manifests
mkdir -p ${ENVTEST_ASSETS_DIR}
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/{{ .ControllerRuntimeVersion }}/hack/setup-envtest.sh
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out
Note that it is NOT intuitive for the users. As I user of Kubebuilder, I'd expected that the tool provides a much more readable, intuitive and understandable code to reduce the learning curve and keep its maintainability such as:
# Run tests
test: generate fmt vet manifests setup
go test ./... -coverprofile cover.out
# Setup the envtest setup local envinroment
setup:
sigs.k8s.io/controller-tools@versio; go run envtest_setup.go
However, since was decide that the tool/module should be in the controller-runtime and not Kubebuilder then, it means that the script /hack/setup-envtest.sh
would need to be replaced by a go module maybe from its /hack/tools
.
Describe the solution you'd like.
Note that here we also might nat to consider address together the requirements described in #1234. However, in order to help who will work on this task, following the module that was done in the PR: kubernetes-sigs/kubebuilder#1711. It is very closer to the code that should be done here.
package main
import (
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"k8s.io/klog"
)
const (
// defaultKubebuilderPath is the fixed value defined in the controller-runtime to looking for the
// binaries.
defaultKubebuilderPath = "/usr/local/kubebuilder/bin" // see that needs to be changed https://github.com/kubernetes-sigs/controller-runtime/issues/1234
// kubernetesVersion defines the version used to download the binaries
kubernetesVersion = "1.16.4"
)
func main() {
klog.Info("Checking EnvTest binaries")
assetsEnv := os.Getenv("KUBEBUILDER_ASSETS")
if strings.TrimSpace(assetsEnv) != "" {
klog.Infof("EnvTest binaries configured via KUBEBUILDER_ASSETS: %s", assetsEnv)
os.Exit(0)
}
binPath := filepath.Join("..", "bin")
if hasBinaries(binPath) {
klog.Info("EnvTest binaries found in bin/")
os.Exit(0)
}
klog.Infof("Downloading EnvTest tools")
envtest_tools_archive_name := getEnvToolsArchiveName()
envtest_tools_download_url := "https://storage.googleapis.com/kubebuilder-tools/" + envtest_tools_archive_name
err := downloadFile(envtest_tools_archive_name, envtest_tools_download_url)
if err != nil {
klog.Fatalf("unable to download the file (%v) from (%v): %v", envtest_tools_archive_name, envtest_tools_download_url, err)
}
if _, err := os.Stat(binPath); os.IsNotExist(err) {
klog.Infof("Creating bin/ directory")
err = os.Mkdir(binPath, 0755)
if err != nil {
klog.Fatalf("error to create the bin/ directory : %s", err)
}
}
cmd := exec.Command("tar", "-C", binPath, "--strip-components=2", "-zvxf", envtest_tools_archive_name)
if err := cmd.Run(); err != nil {
klog.Fatalf("error to untar bin %v: %v", filepath.Join(binPath, envtest_tools_archive_name), err)
}
cmd = exec.Command("rm", "-rf", envtest_tools_archive_name)
if err := cmd.Run(); err != nil {
klog.Fatal(err)
}
klog.Infof("EnvTest binaries are in the directory %v", binPath)
}
// getEnvToolsArchiveName will return the name of the env tools archive based or the arch and so
func getEnvToolsArchiveName() string {
cmd := exec.Command("go", "env", "GOARCH")
goarch, err := cmd.CombinedOutput()
if err != nil {
klog.Fatal(err)
}
cmd = exec.Command("go", "env", "GOOS")
goos, err := cmd.CombinedOutput()
if err != nil {
klog.Fatal(err)
}
return fmt.Sprintf("kubebuilder-tools-%s-%s-%s.tar.gz", kubernetesVersion, strings.TrimSpace(string(goos)), strings.TrimSpace(string(goarch)))
}
// hasBinaries will return true when the envtest binaries are found
func hasBinaries(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
if _, err := os.Stat(filepath.Join(path, "etcd")); os.IsNotExist(err) {
return false
}
if _, err := os.Stat(filepath.Join(path, "kube-apiserver")); os.IsNotExist(err) {
return false
}
if _, err := os.Stat(filepath.Join(path, "kubectl")); os.IsNotExist(err) {
return false
}
return true
}
// downloadFile will download a url to a local file.
func downloadFile(filepath string, url string) error {
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Write the body to file
_, err = io.Copy(out, resp.Body)
return err
}