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

vendor paths are broken with go modules #152

Closed
mattmoor opened this issue Apr 29, 2020 · 5 comments · Fixed by #153 or albertomilan/ko#1
Closed

vendor paths are broken with go modules #152

mattmoor opened this issue Apr 29, 2020 · 5 comments · Fixed by #153 or albertomilan/ko#1

Comments

@mattmoor
Copy link
Collaborator

We've been talking about this a bit in Knative slack in #ko, but I wanted to track this here in an issue, which is more durable and searchable.

The gist is that there are a number of projects that vendor a binary and then embed the following in yaml to publish the vendored binary: github.com/foo/bar/vendor/github.com/baz/blah

I was under the mistaken impression that this worked fine because Tekton uses this for the gcs-fetcher image, but it turns out that isn't actually building from the local vendor tree, but the "latest" release of Tekton. We caught this on the Knative side because we're still tagging our releases as "pre-release" so Github's "latest" release voodoo doesn't mask the issue for us like it did for Tekton.

For Tekton, the following works for the same reason:

ko publish github.com/tektoncd/pipeline/vendor/github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher

However, a similar command in Knative Serving fails (due to the "no latest release" problem):

ko publish knative.dev/serving/vendor/github.com/tsenart/vegeta

Interestingly, when I adapt these both to relative paths, they BOTH fail, but for a different reason!

ko publish ./vendor/github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher
ko publish ./vendor/github.com/tsenart/vegeta

In this case they fail because qualifyLocalImport (due to packages.Load) returns the unqualified import path (e.g. github.com/baz/blah) , but prior to go modules it returned the fully-qualified path (e.g. github.com/foo/bar/vendor/github.com/baz/blah).

The nearest workaround I've been able to find thus far is to drop the condition around this call:
https://github.com/google/ko/blob/f45bc13ded83af4cfa337910d4ba892015f5d1dc/pkg/build/gobuild.go#L142-L150

... which would let us reference ko://github.com/baz/blah from within github.com/foo/bar and (I believe) have it respect the version of that dependency from go.mod 🤞

The main thing that gives me pause here is that the PR (#60) that introduced go mod support referenced this as a pretty important performance optimization 😬

I'm hoping that either @imjasonh or @jonjohnsonjr has some insights here.

@mattmoor
Copy link
Collaborator Author

Not that for Serving, I have been poking at this in the context of: knative/serving#7734, which as of now has not yet landed.

@wlynch
Copy link

wlynch commented Apr 29, 2020

Tekton should be building from the vendor, as long as the -mod=vendor flag is passed in. In the case of gcs-fetcher, we define a tools.go that lists gcs-fetcher as a dependency to vendor it.

I was able to build the sample Knative image successfully:

knative.dev/serving ‹master›$ ko publish knative.dev/serving/vendor/github.com/tsenart/vegeta

2020/04/29 09:46:23 Using base ubuntu:latest for knative.dev/serving/vendor/github.com/tsenart/vegeta
2020/04/29 09:46:24 Building knative.dev/serving/vendor/github.com/tsenart/vegeta
2020/04/29 09:46:37 Publishing gcr.io/wlynch-test/vegeta-31e77f8dd4f501e53916e376997a166c:latest
2020/04/29 09:46:41 Published gcr.io/wlynch-test/vegeta-31e77f8dd4f501e53916e376997a166c@sha256:ba7090437a3f9b81ba9437d1ef3aa44bc5946ce49f1f17fe512032f73eaab6cb
gcr.io/wlynch-test/vegeta-31e77f8dd4f501e53916e376997a166c@sha256:ba7090437a3f9b81ba9437d1ef3aa44bc5946ce49f1f17fe512032f73eaab6cb
knative.dev/serving ‹master›$ go version
go version go1.14.2 darwin/amd64
knative.dev/serving ‹master›$ ko version
v0.4.0

Out of curiosity, what versions of go/ko are you using, and does it work for you if you run GOFLAGS="-mod=vendor" ko publish knative.dev/serving/vendor/github.com/tsenart/vegeta? I'm curious if this is related to #69. This would also explain why it worked for me since as of Go 1.14 the go tool will default to -mod=vendor if the top level vendor directory exists.

@mattmoor
Copy link
Collaborator Author

I tried that:

GOFLAGS=-mod=vendor ko publish knative.dev/serving/vendor/github.com/tsenart/vegeta
2020/04/29 07:07:51 failed to publish images: importpath "knative.dev/serving/vendor/github.com/tsenart/vegeta" is not supported

I am building ko at HEAD with Go 1.13, I'll try switching to Go 1.14 today.

The problem may not just be my version of Go, but also the version of Go that ko was built with 😞

@mattmoor
Copy link
Collaborator Author

Oh... You were on master, which still works. Yeah the go mod change hasn't landed (though it should soon). I was hoping you pulled my PR in 😬

Updating to 1.14 doesn't fix anything for me. I will add back some instrumentation to confirm my statement above about Tekton and the gcs-builder.

@mattmoor
Copy link
Collaborator Author

Strangely package.Load returns different PkgPath for ./vendor/.../gcs-fetcher and the fully qualified form:

2020/04/29 08:56:20 package: &packages.Package{ID:"github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher", Name:"main", PkgPath:"github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher", Errors:[]packages.Error(nil), GoFiles:[]string{"/Users/mattmoor/go/pkg/mod/github.com/!google!cloud!platform/cloud-builders/gcs-fetcher@v0.0.0-20191203181535-308b93ad1f39/cmd/gcs-fetcher/main.go"}, CompiledGoFiles:[]string(nil), OtherFiles:[]string(nil), ExportFile:"", Imports:map[string]*packages.Package(nil), Types:(*types.Package)(nil), Fset:(*token.FileSet)(nil), IllTyped:false, Syntax:[]*ast.File(nil), TypesInfo:(*types.Info)(nil), TypesSizes:types.Sizes(nil), forTest:""}

^-> PkgPath: github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher

2020/04/29 08:56:05 package: &packages.Package{ID:"github.com/tektoncd/pipeline/vendor/github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher", Name:"main", PkgPath:"github.com/tektoncd/pipeline/vendor/github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher", Errors:[]packages.Error(nil), GoFiles:[]string{"/Users/mattmoor/go/src/github.com/tektoncd/pipeline/vendor/github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher/main.go"}, CompiledGoFiles:[]string(nil), OtherFiles:[]string(nil), ExportFile:"", Imports:map[string]*packages.Package(nil), Types:(*types.Package)(nil), Fset:(*token.FileSet)(nil), IllTyped:false, Syntax:[]*ast.File(nil), TypesInfo:(*types.Info)(nil), TypesSizes:types.Sizes(nil), forTest:""}

^-> PkgPath: github.com/tektoncd/pipeline/vendor/github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher/cmd/gcs-fetcher

I think the relative path problems with publish are red herring, so time to dig more.

mattmoor added a commit to mattmoor/ko that referenced this issue Apr 29, 2020
This change more or less completely changes how `ko://` is handled internally to `ko`, but the user-facing changes should only be net-positive.  `ko://` was previously stripped at the highest level, and the build logic was unaware, which had some undesirable diagnostic/functional implications that are collectively addressed in this change.

With this change, the `ko://` prefix is preserved and passed to the build logic, which internally parses a new `reference` type (this was useful to have Go's type checker find all of the places that needed fixing).  The main functional differences are:
1. If a reference is prefixed with `ko://` we will now fail fast in `IsSupportedReference` regardless of whether `--strict` is passed.
2. If a reference is prefixed with `ko://` it will bypass the prefix check, which allows the use of `ko://github.com/another/repo` that references a vendored binary package.

For `2.` the absence of the module prefix causes the filtering logic Jon introduced to avoid the reference.  This was critical for efficiency when `ko://` isn't around because we feed every string in the yaml through it, but when the user has explicitly decorated things it's the perfect thing to be sensitive to.

Fixes: ko-build#146
Fixes: ko-build#152
mattmoor added a commit that referenced this issue Apr 30, 2020
This change more or less completely changes how `ko://` is handled internally to `ko`, but the user-facing changes should only be net-positive.  `ko://` was previously stripped at the highest level, and the build logic was unaware, which had some undesirable diagnostic/functional implications that are collectively addressed in this change.

With this change, the `ko://` prefix is preserved and passed to the build logic, which internally parses a new `reference` type (this was useful to have Go's type checker find all of the places that needed fixing).  The main functional differences are:
1. If a reference is prefixed with `ko://` we will now fail fast in `IsSupportedReference` regardless of whether `--strict` is passed.
2. If a reference is prefixed with `ko://` it will bypass the prefix check, which allows the use of `ko://github.com/another/repo` that references a vendored binary package.

For `2.` the absence of the module prefix causes the filtering logic Jon introduced to avoid the reference.  This was critical for efficiency when `ko://` isn't around because we feed every string in the yaml through it, but when the user has explicitly decorated things it's the perfect thing to be sensitive to.

Fixes: #146
Fixes: #152
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants