-
-
Notifications
You must be signed in to change notification settings - Fork 70
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
[bundle] Fix local module refs for multi-cluster #429
Conversation
This fix doesn't work if |
This bug is caused by the relationship between the following components: * The `func (b *BundleBuilder) InitWorkspace(workspace string, runtimeValues map[string]string) error` function in `internal/engine/bundle_builder.go` * The `BundleBuilder.files` field * The `BundleBuilder.mapSourceToOrigin` field * The `func (b *BundleBuilder) getInstanceUrl(v cue.Value) string` function in `internal/engine/bundle_builder.go` When called, the `InitWorkspace` goes through the list of files stored in `b.files`, parses them and writes the result in new files (let's call them "result files") located under the path indicated by `workspace`. In parallel, `b.mapSourceToOrigin` maps a "result file" path to the original file the result is based on. At the end of the function, the original list `b.files` is replaced with the list of "result files". The next invocation of `InitWorkspace` then uses `b.files` again, but this time it contains the previously computed "result files" paths. So, for a given: * `b.files == ["/path/to/a/bundle.cue"]` calling `InitWorkspace("/tmp/workspace1/")`, will yield: * `b.files == ["/tmp/workspace1/bundle.cue"]` * `b.mapSourceToOrigin["/tmp/workspace1/bundle.cue"]="/path/to/a/bundle.cue"` Then calling `InitWorkspace("/tmp/workspace2/")`, will yield: * `b.files == ["/tmp/workspace2/bundle.cue"]` * `b.mapSourceToOrigin["/tmp/workspace2/bundle.cue"]="/tmp/workspace1/bundle.cue"` The `getInstanceUrl` relies on the `mapSourceToOrigin` being accurate to propely resolve relative `file://` paths. When `getInstanceUrl()` is called for the first bundle, it will propely resolve `./examples/redis/` to `/path/to/a/examples/redis/`. When `getInstanceUrl()` is called for the second bundle, it will erroneously resolve `./examples/redis/` to `/tmp/workspace1/examples/redis/`. This commit fixes this. However it is worth noting that using a relative path for a `file://` URI feels strange. Should it be allowed in the first place?
This is how many tools work, for example Docker Compose, so I don't find it strange but actually useful. |
internal/engine/bundle_builder.go
Outdated
source = origin | ||
} | ||
url = apiv1.LocalPrefix + filepath.Clean(filepath.Join(filepath.Dir(source), path)) | ||
url = apiv1.LocalPrefix + filepath.Clean(filepath.Join(b.cwd, path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use CWD here, the relative path is to the bundle file (what v.Pos().Filename()
does) instead of the working dir of the CLI. You can see the e2e tests failing for:
timoni bundle build -f hack/tests/nginx_bundle.cue --runtime-from-env
ERR module not found at path /home/runner/work/blueprints/starter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use CWD here, the relative path is to the bundle file (what v.Pos().Filename() does) instead of the working dir of the CLI.
Ha ok, I understand the logic better now, thanks.
This raises the issue that when the bundle file comes from Stdin (-f -
), the v.Pos().Filename()
becomes the temporary directory of the file Stdin was written to. Which makes the getInstanceUrl
function fail again, since the path is now wrong.
I'm also unclear what will happen when someone specifies both a bundle via Stdin and a file (-f- -f bundle.cue
).
I'll look into that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can error out if the bundle comes from stdin and contains local refs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
I removed the cwd
code and added 4 new tests:
- bundle apply with file from stdin (
-f-
) andmodule: url: file://./relative/path/to/module
- bundle apply with file from stdin (
-f-
) andmodule: url: file:///absolute/path/to/module
- bundle apply with file from concrete file (
-f /path/to/bundle.cue
) andmodule: url: file://./relative/path/to/module
- bundle apply with file from concrete file (
-f /path/to/bundle.cue
) andmodule: url: file:///absolute/path/to/module
How's that?
edit: also fixed the RuntimeBuilder
. Happy to make a different PR if preferred.
135aa8c
to
c3e7bc7
Compare
To make it clear that there are multiple workspaces with multiple files.
The `RuntimeBuilder` has the same issue as the `BundleBuilder`, as seen in stefanprodan@a858e4e This commit fixes that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks @huguesalary 🥇
This bug is caused by the relationship between the following components:
func (b *BundleBuilder) InitWorkspace(workspace string, runtimeValues map[string]string) error
function ininternal/engine/bundle_builder.go
BundleBuilder.files
fieldBundleBuilder.mapSourceToOrigin
fieldfunc (b *BundleBuilder) getInstanceUrl(v cue.Value) string
function in
internal/engine/bundle_builder.go
When called, the
InitWorkspace
goes through the list of files storedin
b.files
, parses them and writes the result in new files (let's callthem "result files") located under the path indicated by
workspace
. Inparallel,
b.mapSourceToOrigin
maps a "result file" path to theoriginal file the result is based on.
At the end of the function, the original list
b.files
is replaced withthe list of "result files".
The next invocation of
InitWorkspace
then usesb.files
again, butthis time it contains the previously computed "result files" paths.
So, for a given:
b.files == ["/path/to/a/bundle.cue"]
calling
InitWorkspace("/tmp/workspace1/")
, will yield:b.files == ["/tmp/workspace1/bundle.cue"]
b.mapSourceToOrigin["/tmp/workspace1/bundle.cue"]="/path/to/a/bundle.cue"
Then calling
InitWorkspace("/tmp/workspace2/")
, will yield:b.files == ["/tmp/workspace2/bundle.cue"]
b.mapSourceToOrigin["/tmp/workspace2/bundle.cue"]="/tmp/workspace1/bundle.cue"
The
getInstanceUrl
relies on themapSourceToOrigin
being accurate topropely resolve relative
file://
paths.When
getInstanceUrl()
is called for the first bundle, it will propelyresolve
./examples/redis/
to/path/to/a/examples/redis/
.When
getInstanceUrl()
is called for the second bundle, it will erroneouslyresolve
./examples/redis/
to/tmp/workspace1/examples/redis/
.This commit fixes this.
However it is worth noting that using a relative path for a
file://
URI feels strange. Should it be allowed in the first place?
Fix #364