Skip to content

Commit

Permalink
Merge pull request #2811 from sbueringer/pr-setup-envtest-ct-rel
Browse files Browse the repository at this point in the history
✨ setup-envtest: download binaries from controller-tools releases
  • Loading branch information
k8s-ci-robot committed May 22, 2024
2 parents fbb7d37 + d950bb9 commit 2e9781e
Show file tree
Hide file tree
Showing 15 changed files with 1,270 additions and 655 deletions.
34 changes: 25 additions & 9 deletions tools/setup-envtest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ 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

# Per default 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:
setup-envtest use --index https://custom.com/envtest-releases.yaml

# To download from the kubebuilder-tools GCS bucket: (default behavior before 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 +62,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 +90,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 +109,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 +130,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

0 comments on commit 2e9781e

Please sign in to comment.