Skip to content

Commit

Permalink
✨ allow pass the assets path via the enviroment config
Browse files Browse the repository at this point in the history
  • Loading branch information
Camila Macedo committed Oct 17, 2020
1 parent bd97e08 commit 275d18a
Showing 1 changed file with 76 additions and 32 deletions.
108 changes: 76 additions & 32 deletions pkg/envtest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,56 @@ It's possible to override some defaults, by setting the following environment va
KUBEBUILDER_CONTROLPLANE_START_TIMEOUT (string supported by time.ParseDuration): timeout for test control plane to start. Defaults to 20s.
KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT (string supported by time.ParseDuration): timeout for test control plane to start. Defaults to 20s.
KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT (boolean): if set to true, the control plane's stdout and stderr are attached to os.Stdout and os.Stderr
*/
const (
envUseExistingCluster = "USE_EXISTING_CLUSTER"
envKubeAPIServerBin = "TEST_ASSET_KUBE_APISERVER"
envEtcdBin = "TEST_ASSET_ETCD"
envKubectlBin = "TEST_ASSET_KUBECTL"
envKubebuilderPath = "KUBEBUILDER_ASSETS"
envStartTimeout = "KUBEBUILDER_CONTROLPLANE_START_TIMEOUT"
envStopTimeout = "KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT"
envAttachOutput = "KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT"
defaultKubebuilderPath = "/usr/local/kubebuilder/bin"
StartTimeout = 60
StopTimeout = 60

envUseExistingClusterEnvVar = "USE_EXISTING_CLUSTER"
envKubeAPIServerBinEnvVar = "TEST_ASSET_KUBE_APISERVER"
envEtcdBinEnvVar = "TEST_ASSET_ETCD"
envKubectlBinEnvVar = "TEST_ASSET_KUBECTL"
envKubebuilderPathEnvVar = "KUBEBUILDER_ASSETS"
envStartTimeoutEnvVar = "KUBEBUILDER_CONTROLPLANE_START_TIMEOUT"
envStopTimeoutEnvVar = "KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT"
envAttachOutputEnvVar = "KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT"

// Default values
defaultKubebuilderPath = "/usr/local/kubebuilder/bin"
StartTimeout = 60
StopTimeout = 60
defaultKubebuilderControlPlaneStartTimeout = 20 * time.Second
defaultKubebuilderControlPlaneStopTimeout = 20 * time.Second

// required binaries to run env test
kubeApiserverBinName = "kube-apiserver"
etcdBinName = "etcd"
kubectlBinName = "kubectl"
)

// Default binary path for test framework
func defaultAssetPath(binary string) string {
assetPath := os.Getenv(envKubebuilderPath)
if assetPath == "" {
assetPath = defaultKubebuilderPath
// getBinAssetPath will return the path for the binary informed or an error if not be possible.
// to fid the bin. It will try first check if the bin exists in the path informed then if not,
// it will be looking for to try find the bin in the other config options as in the default path.
func (te *Environment) getBinAssetPath(binary, path string) (string, error) {
// If found the bin in the path informed return this path
if strings.TrimSpace(path) != "" && hasBinary(binary, path) {
return filepath.Join(path, binary), nil
}
return filepath.Join(assetPath, binary)

// If a Binary directory as informed in the EnvTest setup try to get the bin from it
if strings.TrimSpace(te.BinaryDirectoryPath) != "" && hasBinary(binary, te.BinaryDirectoryPath) {
return filepath.Join(te.BinaryDirectoryPath, binary), nil
}

// If envKubebuilderPathEnvVar was set via ENV VAR then check if the bin can be found there
valueFromEnvVar := os.Getenv(envKubebuilderPathEnvVar)
if strings.TrimSpace(valueFromEnvVar) != "" && hasBinary(binary, valueFromEnvVar) {
return filepath.Join(valueFromEnvVar, binary), nil
}

// Check if the bin can be found in the default path
if hasBinary(binary, defaultKubebuilderPath) {
return filepath.Join(defaultKubebuilderPath, binary), nil
}

return "", fmt.Errorf("unable to found the required binary %v", binary)
}

// ControlPlane is the re-exported ControlPlane type from the internal integration package
Expand Down Expand Up @@ -113,6 +136,10 @@ type Environment struct {
// values are merged.
CRDDirectoryPaths []string

// BinaryDirectoryPath is the path where the binaries required for the envtest are
// locate in the environment
BinaryDirectoryPath string

// UseExisting indicates that this environments should use an
// existing kubeconfig, instead of trying to stand up a new control plane.
// This is useful in cases that need aggregated API servers and the like.
Expand Down Expand Up @@ -200,7 +227,7 @@ func (te *Environment) Start() (*rest.Config, error) {
te.ControlPlane.Etcd = &integration.Etcd{}
}

if os.Getenv(envAttachOutput) == "true" {
if os.Getenv(envAttachOutputEnvVar) == "true" {
te.AttachControlPlaneOutput = true
}
if te.ControlPlane.APIServer.Out == nil && te.AttachControlPlaneOutput {
Expand All @@ -216,17 +243,26 @@ func (te *Environment) Start() (*rest.Config, error) {
te.ControlPlane.Etcd.Err = os.Stderr
}

if os.Getenv(envKubeAPIServerBin) == "" {
te.ControlPlane.APIServer.Path = defaultAssetPath("kube-apiserver")
// set binaries location and then, if the bin not found throw issue
path, err := te.getBinAssetPath(kubeApiserverBinName, os.Getenv(envKubeAPIServerBinEnvVar))
if err != nil {
return nil, err
}
te.ControlPlane.APIServer.Path = path

path, err = te.getBinAssetPath(etcdBinName, os.Getenv(envEtcdBinEnvVar))
if err != nil {
return nil, err
}
if os.Getenv(envEtcdBin) == "" {
te.ControlPlane.Etcd.Path = defaultAssetPath("etcd")
te.ControlPlane.Etcd.Path = path

path, err = te.getBinAssetPath(kubectlBinName, os.Getenv(envKubectlBinEnvVar))
if err != nil {
return nil, err
}
if os.Getenv(envKubectlBin) == "" {
// we can't just set the path manually (it's behind a function), so set the environment variable instead
if err := os.Setenv(envKubectlBin, defaultAssetPath("kubectl")); err != nil {
return nil, err
}
// we can't just set the path manually (it's behind a function), so set the environment variable instead
if err := os.Setenv(envKubectlBinEnvVar, path); err != nil {
return nil, err
}

if err := te.defaultTimeouts(); err != nil {
Expand Down Expand Up @@ -267,6 +303,14 @@ func (te *Environment) Start() (*rest.Config, error) {
return te.Config, err
}

// hasBinary will return true when the binary was found in the path
func hasBinary(bin, path string) bool {
if _, err := os.Stat(filepath.Join(path, bin)); os.IsNotExist(err) {
return false
}
return true
}

func (te *Environment) startControlPlane() error {
numTries, maxRetries := 0, 5
var err error
Expand All @@ -287,7 +331,7 @@ func (te *Environment) startControlPlane() error {
func (te *Environment) defaultTimeouts() error {
var err error
if te.ControlPlaneStartTimeout == 0 {
if envVal := os.Getenv(envStartTimeout); envVal != "" {
if envVal := os.Getenv(envStartTimeoutEnvVar); envVal != "" {
te.ControlPlaneStartTimeout, err = time.ParseDuration(envVal)
if err != nil {
return err
Expand All @@ -298,7 +342,7 @@ func (te *Environment) defaultTimeouts() error {
}

if te.ControlPlaneStopTimeout == 0 {
if envVal := os.Getenv(envStopTimeout); envVal != "" {
if envVal := os.Getenv(envStopTimeoutEnvVar); envVal != "" {
te.ControlPlaneStopTimeout, err = time.ParseDuration(envVal)
if err != nil {
return err
Expand All @@ -312,7 +356,7 @@ func (te *Environment) defaultTimeouts() error {

func (te *Environment) useExistingCluster() bool {
if te.UseExistingCluster == nil {
return strings.ToLower(os.Getenv(envUseExistingCluster)) == "true"
return strings.ToLower(os.Getenv(envUseExistingClusterEnvVar)) == "true"
}
return *te.UseExistingCluster
}
Expand Down

0 comments on commit 275d18a

Please sign in to comment.