Skip to content
This repository has been archived by the owner on Sep 18, 2020. It is now read-only.

torcx/perform: support squashfs archives #96

Merged
merged 12 commits into from
May 15, 2018
Merged

torcx/perform: support squashfs archives #96

merged 12 commits into from
May 15, 2018

Conversation

euank
Copy link
Contributor

@euank euank commented Feb 16, 2018

Fixes #62 (see discussion there)

This change was largely for my own edification, though I think it does work (tested with the overlay and scripts changes in the 'torcx-gourd' branches on my forks).

Note: This change adds squashfs support for stores, irrespective of any changes in profiles or other version bumps.
Documentation-wise, I've called it out in the v1 profile only, but in reality the code operates after versions have been normalized already and so happily will handle a v0 profile with a squashfs addon.
I'm fine accepting this behavior, but I would like to call it out.

If both tgz and squashfs addons are available, it will take the first one lexicographically, but it's documented as being arbitrary in case we wis hto change that.
In practice, users should avoid having multiple different formats available for the same addon reference.

squashfs addons do support a loopback device, and those are a limited resource. I think the typical user will have few enough addons that it won't be an issue, but it's worth noting.

@euank euank force-pushed the gourd branch 2 times, most recently from 6e1614f to 6c54f40 Compare February 16, 2018 07:55
@euank euank changed the title [WIP] torcx/perform: support squashfs archives torcx/perform: support squashfs archives Feb 16, 2018
@euank
Copy link
Contributor Author

euank commented Mar 9, 2018

Rebased, it's now at a much more manageable diff size with #103 already being merged

scripts/build.sh Outdated
@@ -35,7 +35,7 @@ if [ -n "${BUILDTAGS}" ]; then
fi

export GOARCH="${ARCH}"
export CGO_ENABLED=0
export CGO_ENABLED=1
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not strictly necessary, however it's nice to be able to share the cgo consts in the loopback code, which is what this allows

Copy link
Contributor

Choose a reason for hiding this comment

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

If it is only for constants sharing, I'd pretty much prefer sticking to the current pure-go binary. However I fear we may need the C part for some of the ioctl() wrappers, but I didn't dig deeper.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did manage to implement it without cgo; I can switch back and just be a little unhappy about the consts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the cgo dependency. I'm happy to squash idown those commits, but they're kept separate for now.

ftests/rkt.go Outdated

// binLibs is a helper that prints libraries a given binary is dynamically
// linked against, including recursive dependencies of those libraries.
func binLibs(binPath string) ([]string, error) {
Copy link
Contributor Author

@euank euank Mar 9, 2018

Choose a reason for hiding this comment

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

This bit is a quite icky hack. It may be more desirable to rework the ftest code to use an environment similar to CL (and probably something other than rkt) to run dynamically linked binaries rather than take this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you thinking about something like downloading a CL image and running tests in there via systemd-nspawn?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Something like that would be nice. If we wanted to use docker, there's also a friendly user who packaged the dev container up that way

@lucab
Copy link
Contributor

lucab commented Mar 26, 2018

Sorry for the radio silence. I took a deep dive into squashfs and I see the merit of using it instead of the current tmpfs+tgz approach. I'm introducing a new profile manifest revision in #105, so I'm bundling a new format field in there for non-tgz addon images.

Referenced image must be available in the storepath, as a file name `${image}:${reference}.torcx.tgz`.
Referenced image must be available in the storepath, as a file name `${image}:${reference}.torcx.${format}`
- value/images/#/format : string, either "tgz" or "squashfs" to indicate the image is stored as either a gzipped tarball or squashfs archive.
For backwards compatibility reasons, format will default to "tgz", but "squashfs" should be preferred for new images.
Copy link
Contributor

Choose a reason for hiding this comment

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

squashfs supports had a few (deprecated) major versions and it also supports multiple compression versions, which we should probably specifiy here. I'm mostly concerned with the latter.

Would you prefer to pick a specific compression algorithm, or to have multiple formats with compression identifiers (i.e. sqsh.gz)? I'd lean toward the former.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I also lean towards the former. I can rebase on #105 and indicate the single supported version+compression algorithm.

@squeed
Copy link
Collaborator

squeed commented Mar 27, 2018

I don't think the image format should be part of the profile. Rather, profiles are intended to be a list of name + version pairs. Then, the install resolution logic is responsible for turning that in to a path on disk to install.

So, Format shouldn't be part of the Image type, but rather the Archive type.

@lucab
Copy link
Contributor

lucab commented Mar 27, 2018

I think both approaches are feasible, it's just a matter of being on the explicit or on the implicit side.

If we make this implicit, detection will happen when populating the store metadata cache (via the Archive above). We'll need to tie-break if there are multiple images with different formats in stores. At the same time it will hide away some complexity from the user.

Making this explicit will allow remotes to provide multiple format via a single manifest, so that client can fetch the relevant one for their profile.

I'm generally in favor of the explicit approach, and I think it will make transition and future tooling a bit simpler, but I don't have a strong opinion. @squeed except for code architecture, do you have any specific concern with sourcing the format information from user-provided metadata?

@squeed
Copy link
Collaborator

squeed commented Mar 27, 2018

From a more abstract perspective, I think it's a cleaner architecture for the profile to be divorced from the store as much as possible. Not doing so means that tooling like tectonic-torcx now needs to be rewritten to update profiles between OS versions.

Perhaps more unfriendly from a user perspective, is that an administrator who wishes to use a profile that includes one or more vendor-provided packages (i.e. reference com.coreos.cl) now needs to check each OS store to see which packaging format is in use. This makes me feel like we haven't quite got the right level of abstraction.

@lucab
Copy link
Contributor

lucab commented May 7, 2018

@euank ping, I'd like to hear your feedback on this.

As stated, I don't have strong opinions here but I see that @squeed has a point wrt. the admin having to know in advance about the whole versions/images/formats matrix.
As such, perhaps we can handle this all internally in torcx without exposing it in the profile?

@euank
Copy link
Contributor Author

euank commented May 8, 2018

After thinking about it more, I agree with @squeed that it's a little nicer to tie it to Archive rather than Image in torcx's internal representation.

I still don't quite like that it's now implicitly determined from what files do exist rather than explicitly.

That being said, I think it's still a better option given what we have now.

I've started refactoring the code in that direction, but that's still WIP for the moment.
I do think the documentation portion has been updated appropriately already, so review of that is welcome.

@euank
Copy link
Contributor Author

euank commented May 9, 2018

I've noticed that the proposed torcx-remote-contents-v1 manifest also includes a format field. I think that's an argument in favour of dropping it from the profile manifest since the distributor of the file will have already specified the format explicitly once.

I'm also marking this as blocked on #105 since I wish to build this on the v1 profile rather than modify the v0 one as it currently does.

@lucab
Copy link
Contributor

lucab commented May 9, 2018

@euank I was actually wondering if the descriptors there should expose the format field, and it seems that indeed it would make sense.

@euank euank force-pushed the gourd branch 2 times, most recently from 5bc38a8 to 1a7c9c2 Compare May 9, 2018 22:51
@euank
Copy link
Contributor Author

euank commented May 9, 2018

I think this is ready for review now!

I've added a functional test for mounting a squashfs addon with torcx-generator, and it seems to work as I'd expect. It does require a loopback device to be available, but it also frees it afterwards (when rkt unmount's the container's rootfs it gets the loopback mount too conveniently) and seems like it should work on most systems.

This implementation doesn't tie squashfs support to any particular profile version, other than only documenting it for the newer version. I'm okay with that, but it differs from what I commented above so I'd like to call it out.
If it's desirable that it be more explicit, it could be, though I think the code would be a bit more complicated and I don't see all that much benefit.

lucab
lucab previously requested changes May 11, 2018
@@ -18,7 +18,7 @@ These are the non-goals and out-of-scope topics that `torcx` wants to avoid:
1. full packaging system: it should not be involved into complex upgrade paths
1. upgrading and downgrading packages at runtime: profile activation is an atomic operation performed at-most-once at boot-time
1. pre-removal and post-installation custom logic: changes performed by torcx are (mainly) volatile and are meant to only last for a single boot
1. defining a custom package format: torcx just handles tgz rootfs archives
1. defining a custom package format: torcx just handles squashfs rootfs archives
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can simply drop this line. Initially we wanted to just re-use all of OCI specs/toolings, but in the end it was not feasible.

@@ -3,7 +3,7 @@
## Concepts

* *torcx*: a CLI tool organized in subcommand
* *archive*: an torcx.tgz archive containing addon binaries and assets
* *archive*: an torcx.squashfs archive containing addon binaries and assets
Copy link
Contributor

Choose a reason for hiding this comment

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

I would just say "a compressed archive ...".


// FileSuffix returns the file extension this archive format must have.
func (arf ArchiveFormat) FileSuffix() string {
return fmt.Sprintf(".torcx.%s", arf)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we default the zero value to tgz in here? Or take care of it in some other ways?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The intent is that the zero value is never used, so I'd rather either ignore it here or panic here.

Defaulting to tgz should happen a layer higher. Are you okay with it just being the caller's responsibility, or would you like me to panic / return an error / handle it here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it's a matter of taste then, so I won't insist. I slightly prefer returning a string+error tuple, but I'm also fine with leaving it to the caller (as is).

Such archives are typically custom-built and tailored for torcx.

A torcx squashfs archive *MUST* be a [version 4.0](https://github.com/torvalds/linux/blob/v4.16/Documentation/filesystems/squashfs.txt) squashfs filesystem archive. It *MUST* be compressed using either gzip or lz4.
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for reference, are gzip+lz4 chosen because of current ContainerLinux kconfig or for any other specific reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I arbitrarily picked from those supported by the current squashfs tools we have.
We must choose to only support a subset of them to be forwards compatible with newer squashfs tools which may add more formats, and for simplicity I thought picking those two options would cover common needs (the default of gzip and one which has very fast performance but lower compression).

Referenced image will be locally looked up as a file named `${name}:${reference}.torcx.tgz`.
Referenced image will be locally looked up as a file named
`${name}:${reference}.torcx.${format}` where `format` may be either `tgz` or
`squashfs`. If both exist, either may arbitrarily be chosen.
Copy link
Contributor

Choose a reason for hiding this comment

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

IMHO the last sentence is somehow problematic. Shouldn't we prefer "deterministically" and "squashfs"?
This would also be reflected in ArchiveFor logic.

@lucab
Copy link
Contributor

lucab commented May 11, 2018

Thanks, I think it is pretty much in great shape.

I only have one real concern about deterministic ordering and preferences, rest of comments are mostly cosmetic.

ftests/rkt.go Outdated
@@ -87,3 +89,24 @@ func RunTestInContainer(t *testing.T, cfg RktConfig) {
t.Error(string(bytes))
}
}

func loopbackMonuts(t *testing.T) []string {
Copy link
Collaborator

Choose a reason for hiding this comment

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

typo (monuts)

@@ -0,0 +1,4 @@
Code in this directory was imported from the docker projcet, under the Apache
Copy link
Collaborator

Choose a reason for hiding this comment

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

typo (projcet)

}
defer loopDev.Close()

if err := unix.Mount(loopDev.Name(), topDir, "squashfs", unix.MS_RDONLY, ""); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should make sure that /run is mounted shared-recursive, in case anyone wants to bind-mount it in to a container.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nevermind - this runs so early on, it doesn't really matter.

case ArchiveFormatSquashfs:
imageRoot, err = mountSquashfs(applyCfg, archive.Filepath, im.Name)
default:
logrus.WithFields(logFields).Error("unrecognized format for archive: ", archive)
Copy link
Collaborator

@squeed squeed May 11, 2018

Choose a reason for hiding this comment

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

does it make sense to set err here so we track failed images? (this is very hypothetical)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it does make sense, though realistically this code is unreachable so could also panic (since ArchiveFor several lines up can only return a tgz or squashfs).

updated to add to failed images so it will fail more noisily if the code changes or I'm missing something.

@squeed
Copy link
Collaborator

squeed commented May 11, 2018

A few tiny things, but LGTM otherwise.

@euank
Copy link
Contributor Author

euank commented May 15, 2018

I believe I addressed all present comments.Note, the torcx/perform: err on unknown image formats more and torcx/store: deterministically prefer squashfs are behavioural changes, but the others changes since last time are a few typo fixes and the like.

@euank
Copy link
Contributor Author

euank commented May 15, 2018

I went ahead and made sure an image with the current set of torcx changes + squashfs docker addon still boots correctly. I uplaoded the qemu image here if you'd like to poke around at anything.

I built it with current master + these scripts changes, overlay changes, and a cros_workon for torcx.

@lucab
Copy link
Contributor

lucab commented May 15, 2018

LGTM (I haven't tested your image at this point).

euank and others added 12 commits May 15, 2018 10:30
And improve naming for our intended use of it
These values should be constant across all modern linuxes, so it should
be fine to simply hardcode them without going through cgo.
This tests the generator mounting a tgz and a squashfs addon.

It verifies the contents of the 'unpack' directory matches the contents
used to create the addons.

Propogation can also be tested fairly easily, but to keep this a bit
smaller I'm punting on that for the moment.
This defines behavior that was previously omitted to try and simplify
the implementation.

In reality, the simplication is minor to none and it's much nicer to
define these semantics.
The code already printed out an error if an image format was
unrecognized that late (which shouldn't in practice happen).

This ensures it also later fails the operation by considering that image
failed too.
@euank
Copy link
Contributor Author

euank commented May 15, 2018

Did a trivial rebase and tests are still green. Merging..

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

Successfully merging this pull request may close these issues.

3 participants