controller-tools: controller-gen doesn't accept -mod=vendor, downloads source if it can't find the module cache

I’ve been trying to vendor a project using kube-builder and controller-gen and build it in our CI system.

However I noticed a pretty significant increase in build-time and when I investigated I discovered that each time I exec controller-gen in a container, if it can’t find a populated go package source cache it fetches every dependency from the go.mod / go.sum.

There doesn’t appear to be any way to tell controller-gen to use the vendor folder, unless I’ve missed something?

This seems to hold true for: controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./api/... and controller-gen rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases

Which correspond to the generate and manifests targets in the kube-builder Makefile respectively.

For example, inside a docker container:

# du -h /go/pkg/
4.0K    /go/pkg
# controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./api/...
# du -sh /go/pkg/
196M    /go/pkg/

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 18 (4 by maintainers)

Most upvoted comments

I can confirm that this is still an issue. We used kubebuilder to seed our controller as well, and we use vendored builds, too. Running controller-gen inside an environment without internet access fails because it cannot gather information about dependencies.

As deep as we were able to dig in, the LoadRoots and LoadRootsWithConfig functions in the pkg/loader package (specifically this tools API call here are responsible for the failure to obtain information without internet access. We’re on controller-gen v0.2.5, but the code in question has not changed much since that tag.

Possible Fix

We posit that controller-gen should have a way of specifying vendor mode (and any other build options that need to be passed on to go tools by the controller-gen user).

That could be in the form of a separate command-line argument (e.g. +buildArgs:=[]string) or as an option on the +paths arg (e.g. +paths="-mod=vendor; ./..."), and if present, can be passed to the packages.Load (and any other tools API calls) as (*pacakges.Config).BuildFlags field. But more discussion needs to take place on if/how exactly to handle that.

Workaround

However, if and until that happens, there is an easy workaround. There is currently an environment variable GOFLAGS that can contain anything extra that needs to be passed to all go tools. The current go/x/tools APIs honor that variable. (Someone else may be able to comment on compatibility with past versions).

We worked around our issue like:

$ GOFLAGS="-mod=vendor" controller-gen ...

but it can also be set in the Makefile, or anything else that would make that environment variable available to controller-gen when it executes.

We are running our Go builds in airtight build environment which has vendored dependencies and controller-gen fails as it tries to retrieve dependencies from the network which is locked down.

[WARN] [19] Error: go [list -e -json -compiled=true -test=false -export=false -deps=true -find=false -tags ignore_autogenerated -- ./...]: exit status 1: go: github.com/Azure/azure-pipeline-go@v0.2.2: Get https://proxy.golang.org/github.com/%21azure/azure-pipeline-go/@v/v0.2.2.mod: dial tcp: lookup proxy.golang.org: no such host

controller-gen should have an option to run go list and other Go commands with -mod=vendor