mbox series

[bug#56677,0/2] environment: Add --emulate-fhs option.

Message ID 1LCXD7_zuGflSFovh_mKvhdayNcoWp8ALeguq3i2-XWwWHgzZuPak2gSBN91VLNJ84lubuFAt1dPB282Zy0pBmh_zbiI2qI-7n0LP9F03u4=@protonmail.com
Headers show
Series environment: Add --emulate-fhs option. | expand

Message

John Kehayias July 21, 2022, 4:14 a.m. UTC
Hello Guix,

As discussed on guix-devel here (please see for more detailed discussion and design aims): https://lists.gnu.org/r/guix-devel/2022-07/msg00161.html this is a patch to add an FHS (Filesystem Hierarchy Standard) emulation option for environments.

The overall goal is to mimic typical GNU/Linux distributions in following FHS (/bin, /etc, and /usr in particular) as well as a glibc that reads a global /etc/ld.so.cache and PATH with /bin, and so on. The idea is that following instructions for setting up a development environment, building software, running something, and so on in "typical" Linux environments, should "just work" with 'guix shell --container --emulate-fhs ...', provided the right inputs and other options are set.

For testers, this can be used by using pre-inst-env (outside of the pure shell used to build a local guix) to run guix shell with this patch. Please see the mailing list discussion for particular examples as well.

For review, in particular:

1. On the mailing list there was discussion about the necessity or not of glibc-for-fhs (added in the first patch). I find this useful and a big piece of making this FHS option work, but open to discussion or if it should be a further option.

2. Right now I used a script written to the containers /tmp/fhs.sh to generate the ld cache, supplement $PATH (somewhat optional, but I found useful for less tinkering), and finally launch the given command or shell. I found that when not providing a command the prompt for /bin/sh is not the same as when not using --emulate-fhs. So I'm not sure if this is the correct way to launch the default /bin/sh if no command is given. Open to ideas of a better way to implement these actions for a container start up as well.

3. This is my first time touching a guix script and the documentation, so please do check the commit message and guix.texi.

4. I decided to link the second level FHS directories, like /usr/bin, as well as optional ones like /lib64 (or /lib32), to the top level /bin, /lib, and so on. These could just be bind mounted to profile/bin and so on as well, but again tried to mimic an FHS distribution like Arch where the files only live in one place. While perhaps making the code a little more involved, I hope this makes the container look tidier.

I may be forgetting other elements in the implementation decisions I made, but I have been testing these patches along the way and have gotten good usage of them. Please test further too!

Thanks,
John

Comments

Ludovic Courtès Aug. 4, 2022, 10:36 a.m. UTC | #1
Hello,

John Kehayias <john.kehayias@protonmail.com> skribis:

> As discussed on guix-devel here (please see for more detailed discussion and design aims): https://lists.gnu.org/r/guix-devel/2022-07/msg00161.html this is a patch to add an FHS (Filesystem Hierarchy Standard) emulation option for environments.

Wo0t!

> 1. On the mailing list there was discussion about the necessity or not of glibc-for-fhs (added in the first patch). I find this useful and a big piece of making this FHS option work, but open to discussion or if it should be a further option.

I would prefer to keep complexity as low as possible, and thus not have
this glibc variant.

Now, I don’t know for this use case how much it matters that libc honors
/etc/ld.so.cache.  Intuitively, like I wrote on guix-devel, I’d think
ld.so.cache doesn’t matter, but you encountered counterexamples.

So I guess that if in practice presence of /etc/ld.so.cache *and* having
glibc honor it is necessary often enough, we can do that.

It seems that ‘glibc-for-fhs’ is merely added to the environment though,
and not actually used?

+                                      ;; For an FHS-container, add the
+                                      ;; (hidden) package glibc-for-fhs which
+                                      ;; uses the global cache at
+                                      ;; /etc/ld.so.cache.
+                                      (if emulate-fhs?
+                                          (alist-cons 'expression
+                                                      '(ad-hoc-package
+                                                        "(@@ (gnu packages base) glibc-for-fhs)")
+                                                      opts)
+                                          opts)))

Or rather it’s only used when running ‘ldconfig’, right?

> 2. Right now I used a script written to the containers /tmp/fhs.sh to generate the ld cache, supplement $PATH (somewhat optional, but I found useful for less tinkering), and finally launch the given command or shell. I found that when not providing a command the prompt for /bin/sh is not the same as when not using --emulate-fhs. So I'm not sure if this is the correct way to launch the default /bin/sh if no command is given. Open to ideas of a better way to implement these actions for a container start up as well.
>
> 3. This is my first time touching a guix script and the documentation, so please do check the commit message and guix.texi.
>
> 4. I decided to link the second level FHS directories, like /usr/bin, as well as optional ones like /lib64 (or /lib32), to the top level /bin, /lib, and so on. These could just be bind mounted to profile/bin and so on as well, but again tried to mimic an FHS distribution like Arch where the files only live in one place. While perhaps making the code a little more involved, I hope this makes the container look tidier.
>
> I may be forgetting other elements in the implementation decisions I made, but I have been testing these patches along the way and have gotten good usage of them. Please test further too!
 
At first sight, I find it pretty cool!  I would have two grievances:

  1. Can we make the implementation more orthogonal and less entangled
     in the already-long ‘launch-environment/container’?

     Maybe that can be accomplished by moving all the code conditional
     on ‘emulate-fhs?’ out of the way in a separate procedure, and
     possibly by adding a generic hook in ‘launch-environment/container’
     that would call said procedure.

  2. Please add tests.  You can probably augment
     ‘tests/guix-environment-container.sh’ for that.  Let us know if
     you’re not sure how to do that.

Thanks for all the work, and sorry for the delay: it seems to be summer
time for many of us.  :-)

Ludo’.
John Kehayias Aug. 17, 2022, 9:43 p.m. UTC | #2
Hello,

Took me a while to respond as well, summer meaning more time to hack on things and then also let them get away...

------- Original Message -------
On Thursday, August 4th, 2022 at 6:36 AM, Ludovic Courtès <ludo@gnu.org> wrote:
> 
> Hello,
> 
> John Kehayias john.kehayias@protonmail.com skribis:
> 
> > As discussed on guix-devel here (please see for more detailed discussion and design aims): https://lists.gnu.org/r/guix-devel/2022-07/msg00161.html this is a patch to add an FHS (Filesystem Hierarchy Standard) emulation option for environments.
> 
> Wo0t!
> 
> > 1. On the mailing list there was discussion about the necessity or not of glibc-for-fhs (added in the first patch). I find this useful and a big piece of making this FHS option work, but open to discussion or if it should be a further option.
> 
> I would prefer to keep complexity as low as possible, and thus not have
> this glibc variant.
> 
> Now, I don’t know for this use case how much it matters that libc honors
> /etc/ld.so.cache. Intuitively, like I wrote on guix-devel, I’d think
> ld.so.cache doesn’t matter, but you encountered counterexamples.
> 
> So I guess that if in practice presence of /etc/ld.so.cache and having
> glibc honor it is necessary often enough, we can do that.
> 

Right, though as I said, happy to hear of alternatives or what other use cases come up. This seems rather robust to any "usual" assumptions though.

> It seems that ‘glibc-for-fhs’ is merely added to the environment though,
> and not actually used?
> 

Well, it is added to the environment which here means the glibc-for-fhs lib directory ends up in the container's global /lib. This may be useful for anything expecting a more "typical" glibc to be found in the typical location. I can't say I know the particulars here, other than binaries and an example of other nested containers (used in non-free software, but the containers are bwrap and friends) expecting glibc to default to a global ld cache. Again, there may be other workarounds or ways to reduce this, but for now I followed the "emulate" part of the flag :)

> + ;; For an FHS-container, add the
> + ;; (hidden) package glibc-for-fhs which
> + ;; uses the global cache at
> + ;; /etc/ld.so.cache.
> + (if emulate-fhs?
> + (alist-cons 'expression
> + '(ad-hoc-package
> + "(@@ (gnu packages base) glibc-for-fhs)")
> + opts)
> + opts)))
> 
> Or rather it’s only used when running ‘ldconfig’, right?
> 

Yes, since that is the glibc in the container. Though actually generating a cache shouldn't matter, right? Guix's glibc will do that as well, as the only patch removed is the one that changed where glibc reads the ld cache from. So the cache could be generated with Guix's glibc, but then likely won't be read otherwise? Sorry, a bit out of what I know for all the details; I'm mostly at "this is what is often expected" and "this makes it work."

> > 2. Right now I used a script written to the containers /tmp/fhs.sh to generate the ld cache, supplement $PATH (somewhat optional, but I found useful for less tinkering), and finally launch the given command or shell. I found that when not providing a command the prompt for /bin/sh is not the same as when not using --emulate-fhs. So I'm not sure if this is the correct way to launch the default /bin/sh if no command is given. Open to ideas of a better way to implement these actions for a container start up as well.
> > 
> > 3. This is my first time touching a guix script and the documentation, so please do check the commit message and guix.texi.
> > 
> > 4. I decided to link the second level FHS directories, like /usr/bin, as well as optional ones like /lib64 (or /lib32), to the top level /bin, /lib, and so on. These could just be bind mounted to profile/bin and so on as well, but again tried to mimic an FHS distribution like Arch where the files only live in one place. While perhaps making the code a little more involved, I hope this makes the container look tidier.
> > 
> > I may be forgetting other elements in the implementation decisions I made, but I have been testing these patches along the way and have gotten good usage of them. Please test further too!
> 
> At first sight, I find it pretty cool! I would have two grievances:
> 

Thanks! It is serving me in some day-to-day work nicely.

> 1. Can we make the implementation more orthogonal and less entangled
> in the already-long ‘launch-environment/container’?
> 
> Maybe that can be accomplished by moving all the code conditional
> on ‘emulate-fhs?’ out of the way in a separate procedure, and
> possibly by adding a generic hook in ‘launch-environment/container’
> that would call said procedure.
> 

Sure, this sounds like a good idea. I can certainly separate out the FHS setup to a separate function and call it. But I'm not sure what you mean by a "generic hook" here. Do you mean that launch-environment/container would have as an argument say a list of functions it would call?

> 2. Please add tests. You can probably augment
> ‘tests/guix-environment-container.sh’ for that. Let us know if
> you’re not sure how to do that.
> 

Thanks, definitely forgot about that. In looking at that, I've just ran it with "./pre-inst-env sh tests/guix-environment-container.sh" and see that the exit code is 0. Is that the correct way to run these?

Secondly, I'm trying to think of what tests to add. I could of course run the same tests already, but with the --emulate-fhs option, to check that there are no regressions. Other than that, maybe checking that e.g. there's /etc/ld.so.cache, /lib, and so on?

> Thanks for all the work, and sorry for the delay: it seems to be summer
> time for many of us. :-)
> 
> Ludo’.

No worries, summer is a good time to get away, or dig in :)

John
Ludovic Courtès Sept. 8, 2022, 8:58 p.m. UTC | #3
Howdy,

John Kehayias <john.kehayias@protonmail.com> skribis:

>> I would prefer to keep complexity as low as possible, and thus not have
>> this glibc variant.
>> 
>> Now, I don’t know for this use case how much it matters that libc honors
>> /etc/ld.so.cache. Intuitively, like I wrote on guix-devel, I’d think
>> ld.so.cache doesn’t matter, but you encountered counterexamples.
>> 
>> So I guess that if in practice presence of /etc/ld.so.cache and having
>> glibc honor it is necessary often enough, we can do that.
>> 
>
> Right, though as I said, happy to hear of alternatives or what other use cases come up. This seems rather robust to any "usual" assumptions though.
>
>> It seems that ‘glibc-for-fhs’ is merely added to the environment though,
>> and not actually used?
>> 
>
> Well, it is added to the environment which here means the glibc-for-fhs lib directory ends up in the container's global /lib. This may be useful for anything expecting a more "typical" glibc to be found in the typical location. I can't say I know the particulars here, other than binaries and an example of other nested containers (used in non-free software, but the containers are bwrap and friends) expecting glibc to default to a global ld cache. Again, there may be other workarounds or ways to reduce this, but for now I followed the "emulate" part of the flag :)

Oh I got it; that /lib/libc.so *is* used, but only by binaries that were
built on an FHS distro and that you’d bring in (that’s the whole point,
I guess).  It’s not used by Guix packages.

>> 1. Can we make the implementation more orthogonal and less entangled
>> in the already-long ‘launch-environment/container’?
>> 
>> Maybe that can be accomplished by moving all the code conditional
>> on ‘emulate-fhs?’ out of the way in a separate procedure, and
>> possibly by adding a generic hook in ‘launch-environment/container’
>> that would call said procedure.
>> 
>
> Sure, this sounds like a good idea. I can certainly separate out the FHS setup to a separate function and call it. But I'm not sure what you mean by a "generic hook" here. Do you mean that launch-environment/container would have as an argument say a list of functions it would call?

Yes, or an argument with a single procedure to call at a specific
point.  That would default to a no-op.

>> 2. Please add tests. You can probably augment
>> ‘tests/guix-environment-container.sh’ for that. Let us know if
>> you’re not sure how to do that.
>> 
>
> Thanks, definitely forgot about that. In looking at that, I've just ran it with "./pre-inst-env sh tests/guix-environment-container.sh" and see that the exit code is 0. Is that the correct way to run these?

The correct way is:

  make check TESTS=tests/guix-environment-container.sh

Compared to what you wrote, it uses ./test-env (which spawns a daemon
that uses the local store, not /gnu/sore) and sets a bunch of
environment variables.

See
<https://guix.gnu.org/manual/devel/en/html_node/Running-the-Test-Suite.html>.

> Secondly, I'm trying to think of what tests to add. I could of course run the same tests already, but with the --emulate-fhs option, to check that there are no regressions. Other than that, maybe checking that e.g. there's /etc/ld.so.cache, /lib, and so on?

Right, at least you’d want to check for these files/directories.

Note that since the test relies on ‘glibc-for-fhs’, it cannot be done
the “normal way” (that is, using the local store rather than /gnu/store)
because it would end up building the world.

The solution here is to use /gnu/store, if available, and to otherwise
skip the test (return 77).  See ‘tests/guix-pack-relocatable.sh’ up to
line 40 on how to do that.

HTH!

Ludo’.
Ludovic Courtès Sept. 8, 2022, 8:58 p.m. UTC | #4
Howdy,

John Kehayias <john.kehayias@protonmail.com> skribis:

>> I would prefer to keep complexity as low as possible, and thus not have
>> this glibc variant.
>> 
>> Now, I don’t know for this use case how much it matters that libc honors
>> /etc/ld.so.cache. Intuitively, like I wrote on guix-devel, I’d think
>> ld.so.cache doesn’t matter, but you encountered counterexamples.
>> 
>> So I guess that if in practice presence of /etc/ld.so.cache and having
>> glibc honor it is necessary often enough, we can do that.
>> 
>
> Right, though as I said, happy to hear of alternatives or what other use cases come up. This seems rather robust to any "usual" assumptions though.
>
>> It seems that ‘glibc-for-fhs’ is merely added to the environment though,
>> and not actually used?
>> 
>
> Well, it is added to the environment which here means the glibc-for-fhs lib directory ends up in the container's global /lib. This may be useful for anything expecting a more "typical" glibc to be found in the typical location. I can't say I know the particulars here, other than binaries and an example of other nested containers (used in non-free software, but the containers are bwrap and friends) expecting glibc to default to a global ld cache. Again, there may be other workarounds or ways to reduce this, but for now I followed the "emulate" part of the flag :)

Oh I got it; that /lib/libc.so *is* used, but only by binaries that were
built on an FHS distro and that you’d bring in (that’s the whole point,
I guess).  It’s not used by Guix packages.

>> 1. Can we make the implementation more orthogonal and less entangled
>> in the already-long ‘launch-environment/container’?
>> 
>> Maybe that can be accomplished by moving all the code conditional
>> on ‘emulate-fhs?’ out of the way in a separate procedure, and
>> possibly by adding a generic hook in ‘launch-environment/container’
>> that would call said procedure.
>> 
>
> Sure, this sounds like a good idea. I can certainly separate out the FHS setup to a separate function and call it. But I'm not sure what you mean by a "generic hook" here. Do you mean that launch-environment/container would have as an argument say a list of functions it would call?

Yes, or an argument with a single procedure to call at a specific
point.  That would default to a no-op.

>> 2. Please add tests. You can probably augment
>> ‘tests/guix-environment-container.sh’ for that. Let us know if
>> you’re not sure how to do that.
>> 
>
> Thanks, definitely forgot about that. In looking at that, I've just ran it with "./pre-inst-env sh tests/guix-environment-container.sh" and see that the exit code is 0. Is that the correct way to run these?

The correct way is:

  make check TESTS=tests/guix-environment-container.sh

Compared to what you wrote, it uses ./test-env (which spawns a daemon
that uses the local store, not /gnu/sore) and sets a bunch of
environment variables.

See
<https://guix.gnu.org/manual/devel/en/html_node/Running-the-Test-Suite.html>.

> Secondly, I'm trying to think of what tests to add. I could of course run the same tests already, but with the --emulate-fhs option, to check that there are no regressions. Other than that, maybe checking that e.g. there's /etc/ld.so.cache, /lib, and so on?

Right, at least you’d want to check for these files/directories.

Note that since the test relies on ‘glibc-for-fhs’, it cannot be done
the “normal way” (that is, using the local store rather than /gnu/store)
because it would end up building the world.

The solution here is to use /gnu/store, if available, and to otherwise
skip the test (return 77).  See ‘tests/guix-pack-relocatable.sh’ up to
line 40 on how to do that.

HTH!

Ludo’.