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

[release-0.18] ✨ setup-envtest: download binaries from controller-tools releases #2837

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions tools/setup-envtest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ setup-envtest use -i --use-env

# sideload a pre-downloaded tarball as Kubernetes 1.16.2 into our store
setup-envtest sideload 1.16.2 < downloaded-envtest.tar.gz

# If --use-deprecated-gcs is set to false envtest binaries are downloaded from:
# https://raw.githubusercontent.com/kubernetes-sigs/controller-tools/master/envtest-releases.yaml
# To download from a custom index use the following:
# Note: In controller-runtime v0.19.0 --use-deprecated-gcs will default to false.
setup-envtest use --use-deprecated-gcs=false --index https://custom.com/envtest-releases.yaml

# To download from the kubebuilder-tools GCS bucket: (default behavior until v0.18)
# Note: This is a Google-owned bucket and it might be shutdown at any time
# see: https://github.com/kubernetes/k8s.io/issues/2647#event-12439345373
# Note: This flag will also be removed soon.
setup-envtest use --use-deprecated-gcs
```

## Where does it put all those binaries?
Expand All @@ -51,16 +63,16 @@ On Linux, this is `$XDG_DATA_HOME`; on Windows, `%LocalAppData`; and on
OSX, `~/Library/Application Support`.

There's an overall folder that holds all files, and inside that is
a folder for each version/platform pair. The exact directory structure is
not guarnateed, except that the leaf directory will contain the names
expected by envtest. You should always use `setup-envtest fetch` or
a folder for each version/platform pair. The exact directory structure is
not guaranteed, except that the leaf directory will contain the names
expected by envtest. You should always use `setup-envtest fetch` or
`setup-envtest switch` (generally with the `-p path` or `-p env` flags) to
get the directory that you should use.

## Why do I have to do that `source <(blah blah blah)` thing

This is a normal binary, not a shell script, so we can't set the parent
process's environment variables. If you use this by hand a lot and want
process's environment variables. If you use this by hand a lot and want
to save the typing, you could put something like the following in your
`~/.zshrc` (or similar for bash/fish/whatever, modified to those):

Expand All @@ -79,7 +91,7 @@ setup-envtest() {
There are a few options.

First, you'll probably want to set the `-i/--installed` flag. If you want
to avoid forgetting to set this flag, set the `ENVTEST_INSTALLED_ONLY`
to avoid forgetting to set this flag, set the `ENVTEST_INSTALLED_ONLY`
env variable, which will switch that flag on by default.

Then, you have a few options for managing your binaries:
Expand All @@ -98,13 +110,18 @@ Then, you have a few options for managing your binaries:
`--use-env` on by default.

- If you want to use this tool, but download your gziped tarballs
separately, you can use the `sideload` command. You'll need to use the
separately, you can use the `sideload` command. You'll need to use the
`-k/--version` flag to indicate which version you're sideloading.

After that, it'll be as if you'd installed the binaries with `use`.

- If you want to talk to some internal source, you can use the
`--remote-bucket` and `--remote-server` options. The former sets which
- If you want to talk to some internal source via HTTP, you can simply set `--index`
The index must contain references to envtest binary archives in the same format as:
https://raw.githubusercontent.com/kubernetes-sigs/controller-tools/master/envtest-releases.yaml

- If you want to talk to some internal source in a GCS "style", you can use the
`--remote-bucket` and `--remote-server` options together with `--use-deprecated-gcs`.
Note: This is deprecated and will be removed soon. The former sets which
GCS bucket to download from, and the latter sets the host to talk to as
if it were a GCS endpoint. Theoretically, you could use the latter
version to run an internal "mirror" -- the tool expects
Expand All @@ -114,7 +131,7 @@ Then, you have a few options for managing your binaries:
```json
{"items": [
{"name": "kubebuilder-tools-X.Y.Z-os-arch.tar.gz", "md5Hash": "<base-64-encoded-md5-hash>"},
{"name": "kubebuilder-tools-X.Y.Z-os-arch.tar.gz", "md5Hash": "<base-64-encoded-md5-hash>"},
{"name": "kubebuilder-tools-X.Y.Z-os-arch.tar.gz", "md5Hash": "<base-64-encoded-md5-hash>"}
]}
```

Expand Down
42 changes: 23 additions & 19 deletions tools/setup-envtest/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,28 @@ import (
// envtest binaries.
//
// In general, the methods will use the Exit{,Cause} functions from this package
// to indicate errors. Catch them with a `defer HandleExitWithCode()`.
// to indicate errors. Catch them with a `defer HandleExitWithCode()`.
type Env struct {
// the following *must* be set on input

// Platform is our current platform
Platform versions.PlatformItem

// VerifiySum indicates whether or not we should run checksums.
// VerifySum indicates whether we should run checksums.
VerifySum bool
// NoDownload forces us to not contact GCS, looking only
// at local files instead.
// NoDownload forces us to not contact remote services,
// looking only at local files instead.
NoDownload bool
// ForceDownload forces us to ignore local files and always
// contact GCS & re-download.
// contact remote services & re-download.
ForceDownload bool

// Client is our remote client for contacting GCS.
Client *remote.Client
// UseDeprecatedGCS signals if the GCS client is used.
// Note: This will be removed together with remote.GCSClient.
UseDeprecatedGCS bool

// Client is our remote client for contacting remote services.
Client remote.Client

// Log allows us to log.
Log logr.Logger
Expand Down Expand Up @@ -133,7 +137,7 @@ func (e *Env) ListVersions(ctx context.Context) {
}

// LatestVersion returns the latest version matching our version selector and
// platform from the remote server, with the correspoding checksum for later
// platform from the remote server, with the corresponding checksum for later
// use as well.
func (e *Env) LatestVersion(ctx context.Context) (versions.Concrete, versions.PlatformItem) {
vers, err := e.Client.ListVersions(ctx)
Expand Down Expand Up @@ -193,7 +197,7 @@ func (e *Env) ExistsAndValid() bool {
//
// If necessary, it will enumerate on-disk and remote versions to accomplish
// this, finding a version that matches our version selector and platform.
// It will always yield a concrete version, it *may* yield a concrete platorm
// It will always yield a concrete version, it *may* yield a concrete platform
// as well.
func (e *Env) EnsureVersionIsSet(ctx context.Context) {
if e.Version.AsConcrete() != nil {
Expand Down Expand Up @@ -247,13 +251,13 @@ func (e *Env) EnsureVersionIsSet(ctx context.Context) {

// if we're not forcing a download, and we have a newer local version, just use that
if !e.ForceDownload && localVer != nil && localVer.NewerThan(serverVer) {
e.Platform.Platform = localPlat // update our data with md5
e.Platform.Platform = localPlat // update our data with hash
e.Version.MakeConcrete(*localVer)
return
}

// otherwise, use the new version from the server
e.Platform = platform // update our data with md5
e.Platform = platform // update our data with hash
e.Version.MakeConcrete(serverVer)
}

Expand All @@ -266,13 +270,13 @@ func (e *Env) Fetch(ctx context.Context) {
log := e.Log.WithName("fetch")

// if we didn't just fetch it, grab the sum to verify
if e.VerifySum && e.Platform.MD5 == "" {
if e.VerifySum && e.Platform.Hash == nil {
if err := e.Client.FetchSum(ctx, *e.Version.AsConcrete(), &e.Platform); err != nil {
ExitCause(2, err, "unable to fetch checksum for requested version")
ExitCause(2, err, "unable to fetch hash for requested version")
}
}
if !e.VerifySum {
e.Platform.MD5 = "" // skip verification
e.Platform.Hash = nil // skip verification
}

var packedPath string
Expand All @@ -287,7 +291,7 @@ func (e *Env) Fetch(ctx context.Context) {
}
})

archiveOut, err := e.FS.TempFile("", "*-"+e.Platform.ArchiveName(*e.Version.AsConcrete()))
archiveOut, err := e.FS.TempFile("", "*-"+e.Platform.ArchiveName(e.UseDeprecatedGCS, *e.Version.AsConcrete()))
if err != nil {
ExitCause(2, err, "unable to open file to write downloaded archive to")
}
Expand Down Expand Up @@ -365,8 +369,8 @@ func (e *Env) PrintInfo(printFmt PrintFormat) {
case PrintOverview:
fmt.Fprintf(e.Out, "Version: %s\n", e.Version)
fmt.Fprintf(e.Out, "OS/Arch: %s\n", e.Platform)
if e.Platform.MD5 != "" {
fmt.Fprintf(e.Out, "md5: %s\n", e.Platform.MD5)
if e.Platform.Hash != nil {
fmt.Fprintf(e.Out, "%s: %s\n", e.Platform.Hash.Type, e.Platform.Hash.Value)
}
fmt.Fprintf(e.Out, "Path: %s\n", path)
case PrintPath:
Expand Down Expand Up @@ -409,7 +413,7 @@ func (e *Env) Sideload(ctx context.Context, input io.Reader) {
}

var (
// expectedExectuables are the executables that are checked in PathMatches
// expectedExecutables are the executables that are checked in PathMatches
// for non-store paths.
expectedExecutables = []string{
"kube-apiserver",
Expand Down Expand Up @@ -458,7 +462,7 @@ func (e *Env) PathMatches(value string) bool {
}

// versionFromPathName checks if the given path's last component looks like one
// of our versions, and, if so, what version it represents. If succesfull,
// of our versions, and, if so, what version it represents. If successful,
// it'll set version and platform, and return true. Otherwise it returns
// false.
func (e *Env) versionFromPathName(value string) bool {
Expand Down
26 changes: 14 additions & 12 deletions tools/setup-envtest/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@ module sigs.k8s.io/controller-runtime/tools/setup-envtest
go 1.22.0

require (
github.com/go-logr/logr v1.2.4
github.com/go-logr/zapr v1.2.4
github.com/onsi/ginkgo/v2 v2.12.1
github.com/onsi/gomega v1.27.10
github.com/go-logr/logr v1.4.1
github.com/go-logr/zapr v1.3.0
github.com/onsi/ginkgo/v2 v2.17.1
github.com/onsi/gomega v1.32.0
github.com/spf13/afero v1.6.0
github.com/spf13/pflag v1.0.5
go.uber.org/zap v1.26.0
k8s.io/apimachinery v0.0.0-20240424173219-03f2f3350dc5
sigs.k8s.io/yaml v1.3.0
)

require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/tools v0.12.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading