fix-permission not enough for installing extra-snapshot packages
Closed this issue · 12 comments
The source of the problem is that the build lock files are owned by root in recent Docker images such as crosscompass/ihaskell-notebook:fb96a81230df (currently latest) on DockerHub.
In order to fix this, I think your Dockerfile should apply fix-permission to /opt/IHaskell as well as $STACK_ROOT or /opt/stack after everything has been built and registered. For some reasons, this does not seem to be the case now.
Assuming the user sticks to global project rather than local stack.yaml file, (FYI, using local stack.yaml shares the same problem), the user needs to edit global project stack.yaml to list newly intsalled extra-snapshot package in extra-deps
. Otherwise, it is not visible from stack therefore not visible in notebooks.
The problem is when you touch the stack.yaml file you need to re-build all previously built project-local packages under /opt/IHaskell and things like ghc-parser which depend on them. There seems to be additional timestamp check that didn't exist in older stack versions, which invalidates all project-local builds. This is itself bit annoying, but not a big bottleneck because it uses previously built results (not actually re-compiling all the Haskell source) and just register them again to the package database. If this succeeds I think it is tolerable (in terms of compile time, not quite sure for image size bloating when trying to build on top of your image), although not ideal.
However, I was not able to re-build packages like those in /opt/IHaskell inside the running Docker image as a user, because few build lock file permissions are root owned.
To go around the problem, what I did is something like this, unfortunately bloating image more than size twice. (FYI, tree-view and data-partition are non-snapshot packages and global-project.stack.yaml is same as the global-porject stack.yaml in you Docker image but with those additional non-snapshot packages appended to extra-deps
)
FROM crosscompass/ihaskell-notebook:fb96a81230df
USER root
RUN jupyter labextension install @jupyterlab/katex-extension
RUN mkdir /home/$NB_USER/picalc
COPY *.ipynb /home/$NB_USER/picalc/
RUN fix-permissions /home/$NB_USER/picalc
COPY global-project.stack.yaml $STACK_ROOT/global-project/stack.yaml
RUN stack install unbound-generics uglymemo lens tree-view data-partition \
&& stack build $STACK_ARGS ihaskell \
&& stack build $STACK_ARGS ghc-parser \
&& stack build $STACK_ARGS ipython-kernel \
## ihaskell-display
&& stack build $STACK_ARGS ihaskell-aeson \
&& stack build $STACK_ARGS ihaskell-blaze \
&& stack build $STACK_ARGS ihaskell-charts \
&& stack build $STACK_ARGS ihaskell-diagrams \
&& stack build $STACK_ARGS ihaskell-gnuplot \
&& stack build $STACK_ARGS ihaskell-graphviz \
&& stack build $STACK_ARGS ihaskell-hatex \
&& stack build $STACK_ARGS ihaskell-juicypixels \
# && stack build $STACK_ARGS ihaskell-magic \
# && stack build $STACK_ARGS ihaskell-plot \
# && stack build $STACK_ARGS ihaskell-rlangqq \
# && stack build $STACK_ARGS ihaskell-static-canvas \
# Skip install of ihaskell-widgets, they don't work.
# See https://github.com/gibiansky/IHaskell/issues/870
# && stack build $STACK_ARGS ihaskell-widgets \
&& stack build $STACK_ARGS hvega \
&& stack build $STACK_ARGS ihaskell-hvega \
&& fix-permissions $STACK_ROOT \
&& chown --recursive $NB_USER:users $STACK_ROOT \
&& chown --recursive $NB_USER:users /opt/IHaskell \
&& chown --recursive $NB_USER:users /opt/hvega
ENV JUPYTER_ENABLE_LAB=yes
I think it might work with fix-permission rather than chown, but have not tested that yet.
P.S.> fix-permission instead of chown does the work
instead of those four lines above
&& fix-permissions $STACK_ROOT
&& chown --recursive $NB_USER:users $STACK_ROOT
&& chown --recursive $NB_USER:users /opt/IHaskell
&& chown --recursive $NB_USER:users /opt/hvega
these three lines below does the job with much less image size
&& fix-permissions $STACK_ROOT/global-project
&& fix-permissions /opt/IHaskell
&& fix-permissions /opt/hvega
Thanks for the bug report!
We definitely want to be able to change the global-project/stack.yaml
and then build more packages.
I would be happy to review a PR from you for this, if you think you know a good fix. I will investigate in the meanwhile.
Dockerfile should apply fix-permission to /opt/IHaskell as well as $STACK_ROOT or /opt/stack after everything has been built and registered. For some reasons, this does not seem to be the case now.
fix-permission
sets the setgid
bit so that all files and subdirectories inherit group ownership. However, it “does not affect group ID of the files that are created elsewhere and moved to the directory in question.”
Have you tried running fix-permission
after you copy over your new stack.yaml
and before you stack install
, like this?
COPY global-project.stack.yaml $STACK_ROOT/global-project/stack.yaml
RUN fix-permissions $STACK_ROOT/global-project
Could I see your repository, including your global-project.stack.yaml
file? Can you push it to Github?
I tried adding some more extra-deps:
to the /opt/stack/global-project/stack.yaml
from inside the JupyterLab interface then building the extra-deps:
with stack
and it worked.
I strongly suspect that if you fix-permissions
after COPY global-project.stack.yaml
, as I suggested above, then that will solve your problem.
Could I see your repository, including your
global-project.stack.yaml
file? Can you push it to Github?
https://github.com/kyagrd/ihaskell-picalc/blob/master/dockerdev/global-project.stack.yaml
Here I added lines 41 and 42
Have you tried running
fix-permission
after you copy over your newstack.yaml
and before youstack install
, like this?COPY global-project.stack.yaml $STACK_ROOT/global-project/stack.yaml RUN fix-permissions $STACK_ROOT/global-project
This does not solve the problem because the file permission error also comes from /opt/IHaskell or /opt/hvega where one needs to rebuild local packages after editing the global project stack.yaml file.
What I think would solve the problem is to make sure that there are no files left behind as root only writable without being fix-permission
in $STACK_ROOT/global-proejct, /opt/IHaskell, and /opt/hvega (maybe there are more directories to fix but for me making sure those three directory are recursivley fix-permission
ed does the job)
Let me try reproduce the error message to point you to the exact file name that caused those errors, and come back here.
Just to make sure that we are on the same page.
What I mean by fail to do it "as a user in the running Docker image" is when I try to install the package via JupyterLab Terminal or via shell-script command within IHaskell notebook. Editing global-project stack.yaml file is already possible in your DockerHub image. Permission of global proejct stack.yaml file is already sane. It's some other few build-lock files that are lingering as root write only is causing the problem.
There aren't any problems with docker scripting of course, because one could just invoke root user privilege in a docker script.
Have you tried running
fix-permission
after you copy over your newstack.yaml
and before youstack install
, like this?COPY global-project.stack.yaml $STACK_ROOT/global-project/stack.yaml RUN fix-permissions $STACK_ROOT/global-project
This does not solve the problem because the file permission error also comes from /opt/IHaskell or /opt/hvega where one needs to rebuild local packages after editing the global project stack.yaml file.
What I think would solve the problem is to make sure that there are no files left behind as root only writable without being
fix-permission
in $STACK_ROOT/global-proejct, /opt/IHaskell, and /opt/hvega (maybe there are more directories to fix but for me making sure those three directory are recursivleyfix-permission
ed does the job)Let me try reproduce the error message to point you to the exact file name that caused those errors, and come back here.
Here is the entire run of a JupterLab Termial from the running image of crosscompass/ihaskell-notebook:fb96a81230df
jovyan@7707cf3d4825:~$ ls
ihaskell_examples pwd work
jovyan@7707cf3d4825:~$ cd /opt/
bin/ conda/ ghc/ hvega/ IHaskell/ stack/
jovyan@7707cf3d4825:~$ cd /opt/stack/
jovyan@7707cf3d4825:/opt/stack$ ls
config.yaml global-project pantry programs setup-exe-cache setup-exe-src snapshots stack.sqlite3 stack.sqlite3.pantry-write-lock
jovyan@7707cf3d4825:/opt/stack$ cd global-project/
jovyan@7707cf3d4825:/opt/stack/global-project$ ls
stack.yaml stack.yaml.lock
jovyan@7707cf3d4825:/opt/stack/global-project$ ls -al
total 20
drwsrwsr-x 1 jovyan users 4096 Apr 27 07:04 .
drwsrwsr-x 1 root users 4096 Apr 27 09:33 ..
drwsrwsr-x 1 root users 4096 Apr 27 09:35 .stack-work
-rw-rw-r-- 1 jovyan users 2014 Apr 27 06:58 stack.yaml
-rw-rw---- 1 root users 2113 Apr 27 07:04 stack.yaml.lock
jovyan@7707cf3d4825:/opt/stack/global-project$ cat stack.yaml
# Stack global project /opt/stack/global-project/stack.yaml in the Docker image.
# https://docs.haskellstack.org/en/stable/yaml_configuration/#yaml-configuration
# All the IHaskell packages are listed as extra-deps rather than packages,
# because we never want to build anything automatically, we always want to
# select exactly what we build for the IHaskell notebook environment.
# For example, `stack ghci` tries to load every package listed in `packages`,
# and we don't want that behavior. Several of these packages are unbuildable
# at the time of this writing. See the Dockerfile for the list of packages
# which are pre-built into the Docker image.
#
# To make an notebook project with custom `stack.yaml`, copy this `stack.yaml`
# file into the project directory that has the `.ipynb` notebook file and
# then make changes to the copied `stack.yaml`.
packages: []
extra-deps:
- /opt/IHaskell
- /opt/IHaskell/ipython-kernel
- /opt/IHaskell/ghc-parser
- /opt/IHaskell/ihaskell-display/ihaskell-aeson
- /opt/IHaskell/ihaskell-display/ihaskell-blaze
- /opt/IHaskell/ihaskell-display/ihaskell-charts
- /opt/IHaskell/ihaskell-display/ihaskell-diagrams
- /opt/IHaskell/ihaskell-display/ihaskell-gnuplot
- /opt/IHaskell/ihaskell-display/ihaskell-graphviz
- /opt/IHaskell/ihaskell-display/ihaskell-hatex
- /opt/IHaskell/ihaskell-display/ihaskell-juicypixels
- /opt/IHaskell/ihaskell-display/ihaskell-magic
- /opt/IHaskell/ihaskell-display/ihaskell-plot
- /opt/IHaskell/ihaskell-display/ihaskell-rlangqq
- /opt/IHaskell/ihaskell-display/ihaskell-static-canvas
- /opt/IHaskell/ihaskell-display/ihaskell-widgets
- /opt/hvega/hvega
- /opt/hvega/ihaskell-hvega
#
# dependencies needed for ihaskell-diagrams but not in Stackage snapshot
- diagrams-cairo-1.4.1.1
- cairo-0.13.8.0
- pango-0.13.8.0
- glib-0.13.8.0
- gtk2hs-buildtools-0.13.8.0
#
# dependences needed for ihaskell-charts but not in Stackage snapshot
- Chart-cairo-1.9.3
# Resolver copied from IHaskell stack.yaml, see the Dockerfile.
resolver: lts-14.27
jovyan@7707cf3d4825:/opt/stack/global-project$ cat > stack.yaml
# Stack global project /opt/stack/global-project/stack.yaml in the Docker image.
# https://docs.haskellstack.org/en/stable/yaml_configuration/#yaml-configuration
# All the IHaskell packages are listed as extra-deps rather than packages,
# because we never want to build anything automatically, we always want to
# select exactly what we build for the IHaskell notebook environment.
# For example, `stack ghci` tries to load every package listed in `packages`,
# and we don't want that behavior. Several of these packages are unbuildable
# at the time of this writing. See the Dockerfile for the list of packages
# which are pre-built into the Docker image.
#
# To make an notebook project with custom `stack.yaml`, copy this `stack.yaml`
# file into the project directory that has the `.ipynb` notebook file and
# then make changes to the copied `stack.yaml`.
packages: []
extra-deps:
- /opt/IHaskell
- /opt/IHaskell/ipython-kernel
- /opt/IHaskell/ghc-parser
- /opt/IHaskell/ihaskell-display/ihaskell-aeson
- /opt/IHaskell/ihaskell-display/ihaskell-blaze
- /opt/IHaskell/ihaskell-display/ihaskell-charts
- /opt/IHaskell/ihaskell-display/ihaskell-diagrams
- /opt/IHaskell/ihaskell-display/ihaskell-gnuplot
- /opt/IHaskell/ihaskell-display/ihaskell-graphviz
- /opt/IHaskell/ihaskell-display/ihaskell-hatex
- /opt/IHaskell/ihaskell-display/ihaskell-juicypixels
- /opt/IHaskell/ihaskell-display/ihaskell-magic
- /opt/IHaskell/ihaskell-display/ihaskell-plot
- /opt/IHaskell/ihaskell-display/ihaskell-rlangqq
- /opt/IHaskell/ihaskell-display/ihaskell-static-canvas
- /opt/IHaskell/ihaskell-display/ihaskell-widgets
- /opt/hvega/hvega
- /opt/hvega/ihaskell-hvega
#
# dependencies needed for ihaskell-diagrams but not in Stackage snapshot
- diagrams-cairo-1.4.1.1
- cairo-0.13.8.0
- pango-0.13.8.0
- glib-0.13.8.0
- gtk2hs-buildtools-0.13.8.0
#
# dependences needed for ihaskell-charts but not in Stackage snapshot
- Chart-cairo-1.9.3
- tree-view-0.5
# Resolver copied from IHaskell stack.yaml, see the Dockerfile.
resolver: lts-14.27
jovyan@7707cf3d4825:~$ stack install tree-view
tree-view> configure
tree-view> Configuring tree-view-0.5...
tree-view> build
tree-view> Preprocessing library for tree-view-0.5..
tree-view> Building library for tree-view-0.5..
tree-view> [1 of 1] Compiling Data.Tree.View
tree-view> copy/register
tree-view> Installing library in /opt/stack/snapshots/x86_64-linux/4fd42ae9a557848c60380cbbcb7b203aafa3c3921e6f2fe8e4dce7dfdd0d6f70/8.6.5/lib/x86_64-linux-ghc-8.6.5/tree-view-0.5-EvRQw2klzjNK3yCPTFplie
tree-view> Registering library for tree-view-0.5..
jovyan@7707cf3d4825:~$ stack exec ghc-pkg -- list # locally built packages like ihaskell-display is now hidden
/opt/stack/programs/x86_64-linux/ghc-8.6.5/lib/ghc-8.6.5/package.conf.d
Cabal-2.4.0.1
array-0.5.3.0
base-4.12.0.0
binary-0.8.6.0
bytestring-0.10.8.2
containers-0.6.0.1
deepseq-1.4.4.0
directory-1.3.3.0
filepath-1.4.2.1
ghc-8.6.5
ghc-boot-8.6.5
ghc-boot-th-8.6.5
ghc-compact-0.1.0.0
ghc-heap-8.6.5
ghc-prim-0.5.3
ghci-8.6.5
haskeline-0.7.4.3
hpc-0.6.0.3
integer-gmp-1.0.2.0
libiserv-8.6.3
mtl-2.2.2
parsec-3.1.13.0
pretty-1.1.3.6
process-1.6.5.0
rts-1.0
stm-2.5.0.0
template-haskell-2.14.0.0
terminfo-0.4.1.2
text-1.2.3.1
time-1.8.0.2
transformers-0.5.6.2
unix-2.7.2.2
xhtml-3000.2.2.1
/opt/stack/snapshots/x86_64-linux/4fd42ae9a557848c60380cbbcb7b203aafa3c3921e6f2fe8e4dce7dfdd0d6f70/8.6.5/pkgdb
tree-view-0.5
/opt/stack/global-project/.stack-work/install/x86_64-linux/4fd42ae9a557848c60380cbbcb7b203aafa3c3921e6f2fe8e4dce7dfdd0d6f70/8.6.5/pkgdb
(no packages)
jovyan@7707cf3d4825:~$ stack build ihaskell-graphviz # let's try to re-build one I need
alex > using precompiled package
base-compat > using precompiled package
base64-bytestring > using precompiled package
base-orphans > using precompiled package
basement > using precompiled package
blaze-builder > using precompiled package
cereal > using precompiled package
clock > using precompiled package
cmdargs > using precompiled package
colour > using precompiled package
cryptohash-md5 > using precompiled package
cryptohash-sha1 > using precompiled package
data-default-class > using precompiled package
dlist > using precompiled package
cereal-text > using precompiled package
exceptions > using precompiled package
happy > using precompiled package
ghc-lib-parser > using precompiled package
ansi-terminal > using precompiled package
hashable > using precompiled package
haskeline > using precompiled package
cookie > using precompiled package
data-default-instances-containers> using precompiled package
data-default-instances-dlist > using precompiled package
haskell-src-exts > using precompiled package
hourglass > using precompiled package
hscolour > using precompiled package
async > using precompiled package
case-insensitive > using precompiled package
integer-logarithms > using precompiled package
memory > using precompiled package
mime-types > using precompiled package
network > using precompiled package
network-info > using precompiled package
old-locale > using precompiled package
parsec > using precompiled package
http-types > using precompiled package
polyparse > using precompiled package
asn1-types > using precompiled package
cryptonite > using precompiled package
pem > using precompiled package
primitive > using precompiled package
data-default-instances-old-locale> using precompiled package
Cabal > using precompiled package
network-uri > using precompiled package
old-time > using precompiled package
asn1-encoding > using precompiled package
random > using precompiled package
refact > using precompiled package
scientific > using precompiled package
data-default > using precompiled package
entropy > using precompiled package
ghc-paths > using precompiled package
cpphs > using precompiled package
asn1-parse > using precompiled package
semigroups > using precompiled package
socks > using precompiled package
attoparsec > using precompiled package
split > using precompiled package
strict > using precompiled package
syb > using precompiled package
/opt/IHaskell/ghc-parser/.stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build-lock: openFd: permission denied (Permission denied)
Progress 62/108
jovyan@7707cf3d4825:~$ ls -al /opt/IHaskell/ghc-parser/.stack-work/dist/x86_64-linux/Cabal-2.4.0.1/
total 212
drwxr-sr-x 5 root users 4096 Apr 27 08:16 .
drwxr-sr-x 3 root users 4096 Apr 27 08:16 ..
drwxr-xr-x 4 root users 4096 Apr 27 08:16 build
-rw-r--r-- 1 root users 0 Apr 27 08:16 build-lock
drwxr-sr-x 2 root users 4096 Apr 27 08:16 package.conf.inplace
-rw-r--r-- 1 root users 191416 Apr 27 08:16 setup-config
drwxr-sr-x 3 root users 4096 Apr 27 08:16 stack-build-caches
-rw------- 1 root users 35 Apr 27 06:58 stack-cabal-mod
As you can see build-lock is read only for users group and only writable by root
I don't have a PR yet but I have a pretty concrete suggestion.
I think appending \
and then these two lines after the line above
&& fix-permissions /opt/IHaskell
&& fix-permissions /opt/hvega
should solve the problem. This is place where all the builds related to IHaskell and hvega are done. That might get rid of lingering lock-files of root write only in the build directories of those packages.
If I get a chance to really get my hands on to test this and it works out (and it does not bloat image size), then I might do a pull request and hopefully we can close this issue :)
I couldn't reproduce what you're seeing.
I always see build-lock
group-writable in my image.
jovyan@6b44936fd5b5:/opt/IHaskell/ghc-parser/.stack-work/dist/x86_64-linux/Cabal-2.4.0.1$ ll
total 224
drwsrwsr-x 1 root users 4096 Jun 15 06:45 ./
drwsrwsr-x 1 root users 4096 Jun 15 04:59 ../
drwsrwsr-x 1 root users 4096 Jun 15 06:45 build/
-rw-rw-r-- 1 root users 0 Jun 15 04:59 build-lock
But I pushed your suggestion to master anyway, since I'm sure it won't hurt. Please tell me if it helps you.
(I'm having a bit of difficulty building the new master on Dockerhub for some some reason. It builds on my machine.)
Ok, the new image with your suggestions is built on Dockerhub now.
https://hub.docker.com/repository/docker/crosscompass/ihaskell-notebook/tags?page=1
Ok, the new image with your suggestions is built on Dockerhub now.
https://hub.docker.com/repository/docker/crosscompass/ihaskell-notebook/tags?page=1
Thanks! Re-building locally installed packages like ihaskell-* inside running Docker image as non-root now works!!