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

lxc: Check the image really exists on the remote before exporting it #13161

Merged
merged 2 commits into from
Mar 19, 2024

Conversation

gabrielmougard
Copy link
Contributor

closes #12725

When doing a lxc image export .., dereferencing the provided image name either returns a fingerprint or a human readable alias. Both forms can be fine. However, since this dereferenceAlias operation is not really checking if the image associated with this alias exists on the remote, we were creating a local target based on the same string that a user entered. Most of the time, this targetMeta string was resolved to a fingerprint (e.g, /var/lib/snapd/hostfs/home/gab/d2a43fade9d0055e454a091b2e9bd819f7eb715a3d4d46667644a5784d40172) and this was fine because there is only the fingerprint file created and no intermediate directories.

Anyway, I think it is safer to systematically check for the image existence prior to creating any file resources. This way we avoid changing the filesystem write logic that could annoy exsting users and break their export image pipeline:

target := "."
targetMeta := fingerprint
if len(args) > 1 {
	target = args[1]
	if shared.IsDir(shared.HostPathFollow(args[1])) {
		targetMeta = filepath.Join(args[1], targetMeta)
	} else {
		targetMeta = args[1]
	}
}
targetMeta = shared.HostPathFollow(targetMeta)

Copy link
Member

@tomponline tomponline left a comment

Choose a reason for hiding this comment

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

Which call was actually trying to access the local filesystem?

This seems like a sticking plaster rather than fixing the call that tried to access the filesystem incorrectly? I may be misunderstanding.

@gabrielmougard
Copy link
Contributor Author

gabrielmougard commented Mar 15, 2024

Which call was actually trying to access the local filesystem?

This seems like a sticking plaster rather than fixing the call that tried to access the filesystem incorrectly? I may be misunderstanding.

  • Initially, when calling fingerprint := c.image.dereferenceAlias(remoteServer, imageType, name), we end up having fingerprint = name (let say that name = ubuntu/foo to take @simondeziel original example) because no fingerprint could be solved as this remote has an incorrect streams/v1/index.json

  • Then, when targetMeta := shared.HostPathFollow(fingerprint) is called, we end up having targetMeta = /var/lib/snapd/hostfs/home/gab/ubuntu/foo (because ubuntu/foo does not exist on the remote, it has not been replaced by a fingerprint) instead of /var/lib/snapd/hostfs/home/gab/d2a43fade9d0055e454a091b2e9bd819f7eb715a3d4d46667644a5784d40172f. This, eventually makes the client fail at dest, err := os.Create(targetMeta) because we'd need to first create the folder ubuntu in order to create foo in it.

  • Now, I realize that, indeed this PR is not complete and we need to deal with this intermediady folder situation (when the user do not provide an explicit output dir param in the args). Should we then create the missing directory path before calling dest, err := os.Create(targetMeta) ? But I was first asking myself why we weren't checking the remote for image existence first before doing all this (because c.image.dereferenceAlias won't return an explicit error), so that's why I added this remoteServer.GetImage(fingerprint) before.

I don't know if this explanation makes sense :)

@tomponline
Copy link
Member

Yes this makes sense now thanks.

So my question now is whether we should change dereferenceAlias to return the same values as GetImage i.e (image *api.Image, ETag string, err error) and then do a call to GetImage inside dereferenceAlias and return an error if the image cannot be dereferenced. This would make all calls to dereferenceAlias safer, and avoid in several cases the caller having to do the GetImage call themselves next anyway.

I'm not too happy to see the errors being ignored in dereferenceAlias as this can have unexpected consequences, such as this.

What do you think?

@gabrielmougard
Copy link
Contributor Author

Yes this makes sense now thanks.

So my question now is whether we should change dereferenceAlias to return the same values as GetImage i.e (image *api.Image, ETag string, err error) and then do a call to GetImage inside dereferenceAlias and return an error if the image cannot be dereferenced. This would make all calls to dereferenceAlias safer, and avoid in several cases the caller having to do the GetImage call themselves next anyway.

I'm not too happy to see the errors being ignored in dereferenceAlias as this can have unexpected consequences, such as this.

What do you think?

I like this solution. Let's do that.

@gabrielmougard gabrielmougard force-pushed the fix/bogus-simplestream branch 5 times, most recently from 05ce438 to 2c35ef7 Compare March 18, 2024 11:22
lxc/image.go Outdated Show resolved Hide resolved
lxc/image.go Outdated Show resolved Hide resolved
Copy link
Member

@tomponline tomponline left a comment

Choose a reason for hiding this comment

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

Hi

Thanks, but please see #13161 (comment) as we agreed that dereferenceAlias would return the equivalent of GetImage by calling it inside once it had resolved the alias.

Then we would remove extra unnecessary calls to GetImage that occur after it.

@gabrielmougard gabrielmougard force-pushed the fix/bogus-simplestream branch 2 times, most recently from 270ddf2 to 2438684 Compare March 19, 2024 09:12
@gabrielmougard
Copy link
Contributor Author

Hi

Thanks, but please see #13161 (comment) as we agreed that dereferenceAlias would return the equivalent of GetImage by calling it inside once it had resolved the alias.

Then we would remove extra unnecessary calls to GetImage that occur after it.

Should be updated

lxc/image.go Outdated Show resolved Hide resolved
lxc/image.go Outdated Show resolved Hide resolved
lxc/image.go Outdated Show resolved Hide resolved
Copy link
Member

@tomponline tomponline left a comment

Choose a reason for hiding this comment

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

This is looking a lot clearer thanks

Signed-off-by: Gabriel Mougard <gabriel.mougard@canonical.com>
Signed-off-by: Gabriel Mougard <gabriel.mougard@canonical.com>
Copy link
Member

@tomponline tomponline left a comment

Choose a reason for hiding this comment

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

Thanks!

@tomponline tomponline merged commit 997e481 into canonical:main Mar 19, 2024
27 checks passed
@simondeziel
Copy link
Member

Awesome, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pulling from bogus simplestream server cause lxc to try an read from the hostfs
3 participants