Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace the shell script to install the env test binaries by a go model in the tool #1300

Closed
camilamacedo86 opened this issue Dec 16, 2020 · 1 comment · Fixed by #1488
Closed

Comments

@camilamacedo86
Copy link
Member

camilamacedo86 commented Dec 16, 2020

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
}
@camilamacedo86
Copy link
Member Author

/breaking change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant