Skip to content

Fix blind replacement of paths in Heat template referencing other files#2815

Merged
mandre merged 6 commits intogophercloud:masterfrom
dverbeir:fix_file_refs
Oct 22, 2023
Merged

Fix blind replacement of paths in Heat template referencing other files#2815
mandre merged 6 commits intogophercloud:masterfrom
dverbeir:fix_file_refs

Conversation

@dverbeir
Copy link
Copy Markdown
Contributor

This change fixes an issue in the handling of Heat templates that reference other files (child templates or files included by means of get_file:) and that also contain, in some other context, the same string as the relative path being referenced (that must indeed be substituted for the absolute local path).

The existing fixFileRefs() does a simple blind string replacement inside the referencing template, regardless of the context. This is not appropriate as the same string as the path being replaced could possibly appear outside of the valid template/file reference cases (type: ... and get_file: ...), as in the below example:

  init-cmd:
    type: OS::Heat::CloudConfig
    properties:
      cloud_config:
        write_files:
          - path: /etc/somefile
            content: { get_file: somefile }

Here "somefile" in "{ get_file: somefile }" should be replaced by the absolute local path to 'somefile', but the "path: /etc/somefile" part should not be modified as that path refers here to the target destination in a completely different context (in this example, a cloud-init target path on a to-be-created VM).

The change also fixes another issue when using go v1.20 where the usage of filepath.Dir() on a URL removes any duplicate path separator when they should in fact be preserved (in "file:///some_abs_path/here", the "///" must remain).

Finally, the stack template tests have been slightly cleaned up (removing duplications, more concise code).

@github-actions github-actions bot added the semver:patch No API change label Oct 17, 2023
@coveralls
Copy link
Copy Markdown

Coverage Status

coverage: 77.359% (-0.1%) from 77.458% when pulling 538518e on dverbeir:fix_file_refs into c6bd7d9 on gophercloud:master.

@dverbeir dverbeir changed the title Fixes blind replacement of paths in Heat template referencing other files Fix blind replacement of paths in Heat template referencing other files Oct 17, 2023
@mandre
Copy link
Copy Markdown
Contributor

mandre commented Oct 19, 2023

Thanks for the PR @dverbeir. I'll look at your changes today.

You just made us realize we were skipping these tests in CI because they're not in the testing package. That's something else we'll have to fix.

Running the test locally indeed shows the failure:

❯ go test -tags 'fixtures' ./openstack/orchestration/v1/...
?       github.com/gophercloud/gophercloud/openstack/orchestration/v1/apiversions       [no test files]
?       github.com/gophercloud/gophercloud/openstack/orchestration/v1/buildinfo [no test files]
?       github.com/gophercloud/gophercloud/openstack/orchestration/v1/resourcetypes     [no test files]
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/apiversions/testing       (cached)
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/buildinfo/testing (cached)
?       github.com/gophercloud/gophercloud/openstack/orchestration/v1/stackevents       [no test files]
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/resourcetypes/testing     (cached)
?       github.com/gophercloud/gophercloud/openstack/orchestration/v1/stackresources    [no test files]
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/stackevents/testing       (cached)
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/stackresources/testing    (cached)
?       github.com/gophercloud/gophercloud/openstack/orchestration/v1/stacktemplates    [no test files]
--- FAIL: TestGetFileContentsComposeRelativePath (0.00s)
    convenience.go:36: Failure in template_test.go, line 269: unexpected error "error fetching file:/home/martin/go/src/github.com/gophercloud/gophercloud/openstack/orchestration/v1/stacks/templates/my_nova.yaml: 404 Not Found"
FAIL
FAIL    github.com/gophercloud/gophercloud/openstack/orchestration/v1/stacks    0.012s
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/stacks/testing    (cached)
ok      github.com/gophercloud/gophercloud/openstack/orchestration/v1/stacktemplates/testing    (cached)
FAIL

Copy link
Copy Markdown
Contributor

@mandre mandre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for breaking your work in multiple commits, this makes it easier to review. I just have a simple question, otherwise lgtm.

if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
return nil, err
}
opts.TemplateOpts.fixFileRefs()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was that the only call to fixFileRefs() that was problematic, or should we drop more of them?
A quick grep shows more occurrences in the same file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I had looked into that at some point but because I didn't know what kind of manipulation was expected on the Environment part (just a few lines below, and where getRRFileContents() is used instead of getFileContents()), I decided to only touch the Template part that I was interested in and understood.
But I missed the fact that Adopt, Update and Preview also call fixFileRefs() for their template parts (after doing getFileContents()). I have now removed the calls from those other operations so they will also benefit from the fix.

Looking into getRRFileContents(), I saw it also uses getFileContents() but simply with a different filter function (ignoreIfEnvironment()). Hence, it is in fact already affected by my change since some of the files it loads could be re-generated with full paths expanded, as now done by getFileContents() without the need for fixFileRefs().
So I went ahead and made a separate commit that completes similar changes for the env part and completely removes fixFileRefs(). I have however not tested this part other than with the included unit tests and am somewhat unsure as to whether it's okay to re-generate env content from the parsed structure as the code is now doing. Note that this was already the case with the previous commit (templates), just not for the top-level env content. I hope my explanation is not too unclear....

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your explanation is perfectly clear, and I believe it is fine. It looks like a bug that was never noticed.

@mandre mandre added the backport-v1 This PR will be backported to v1 label Oct 20, 2023
@EmilienM
Copy link
Copy Markdown
Contributor

please rebase

@github-actions github-actions bot added semver:minor Backwards-compatible change and removed semver:patch No API change labels Oct 20, 2023
Applying filepath.Dir() to a URL used to give the expected result in
go1.18. But with more recent versions, the library function cleans the
provided path and removes any duplicate path separator.
As a result, filepath.Dir() applied to "file:///some_abs_path/here" will
give "file:/some_abs_path" instead of "file:///some_abs_path".

This commit ensures filepath.Dir() is only applied to the Path element
of the URL by first Parse()ing the URL.

Signed-off-by: David Verbeiren <david.verbeiren@tessares.net>
Refactor getFileContents() into smaller functions to make it easier to
modify in a follow-up commit that will replace fixFileRefs() by
something more appropriate for replacing child-template paths.

Signed-off-by: David Verbeiren <david.verbeiren@tessares.net>
Simple cleanup of the stack template tests:
* Move long duplicated template into a constant
* Move function invocations into their AssertNoErr() when
  the resulting line is not too long (reduces number of lines
  for the tests, making their flow and intent more visible)

Signed-off-by: David Verbeiren <david.verbeiren@tessares.net>
Reduce duplication and make tests shorter by consolidating all
Mux.HandleFunc(...) invocations into a serveFile() convenience function.

Signed-off-by: David Verbeiren <david.verbeiren@tessares.net>
Existing fixFileRefs() does a simple string replacement regardless of
context. This is not appropriate as the same keyord could appear outside
of the valid template/file reference cases ('type: ...' and
'get_file: ...').

Example:

  init-cmd:
    type: OS::Heat::CloudConfig
    properties:
      cloud_config:
        write_files:
          - path: /etc/somefile
            content: { get_file: somefile }

Here "somefile" in "{ get_file: somefile }" should be replaced by the
absolute path to somefile, but the "path: /etc/somefile" part should not
be modified as that path refers here to the target destination in a
completely different context (in this example, a cloud-init target path
on a to-be-created VM).

Signed-off-by: David Verbeiren <david.verbeiren@tessares.net>
An earlier commit removed the usage of fixFileRefs() for templates, by
having the getFileContents() do the replacement directly on the parsed
data structure as it goes through it and gathers referenced files.

This commit does the same for environment files that also ultimately use
the now improved getFileContents() function. As the fixFileRefs() was
not used anywhere else, it has been removed, together with its test.

Signed-off-by: David Verbeiren <david.verbeiren@tessares.net>
@github-actions github-actions bot added semver:minor Backwards-compatible change and removed semver:minor Backwards-compatible change labels Oct 20, 2023
@dverbeir
Copy link
Copy Markdown
Contributor Author

Rebased to have the tests run on the modified code.

Copy link
Copy Markdown
Contributor

@mandre mandre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good work, thanks a lot.

@mandre mandre merged commit a40a5fd into gophercloud:master Oct 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-v1 This PR will be backported to v1 semver:minor Backwards-compatible change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants