andk / cpanpm

CPAN.pm
87 stars 79 forks source link

Not able to create local::lib with non-root user in docker container : fileparse(): need a valid pathname at /usr/share/perl/5.30/CPAN/FirstTime.pm #154

Closed hakonhagland closed 2 years ago

hakonhagland commented 2 years ago

I am on Ubuntu 21.10. I have this Dockerfile where I create a non-root user:

FROM ubuntu:20.04
SHELL ["/bin/bash", "-c"]
RUN apt-get update && \
        DEBIAN_FRONTEND="noninteractive" apt-get install -y \
        build-essential curl g++ git \
        vim sudo wget autoconf libtool \
        cmake

ARG user=docker-user
ARG home=/home/$user
RUN useradd --create-home -s /bin/bash $user \
        && echo $user:ubuntu | chpasswd \
        && adduser $user sudo
WORKDIR $home
USER $user
ENV USER=$user
COPY entrypoint.sh $home
ENTRYPOINT ["./entrypoint.sh"] 

and entrypoint.sh script:

#! /bin/bash

perl --version
#cpan -v
cpan Path::Tiny
exec bash

I build a docker image using:

$ docker build -t ubuntu-test-cpan .

and then run the image:

$ docker run -it ubuntu-test-cpan

which gives output:

This is perl 5, version 30, subversion 0 (v5.30.0) built for x86_64-linux-gnu-thread-multi
(with 50 registered patches, see perl -V for more detail)

Copyright 1987-2019, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

Loading internal logger. Log::Log4perl recommended for better logging.

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes] 
Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl/5.30/App/Cpan.pm line 679, <STDIN> line 1.

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib] 
Attempting to create directory /home/docker-user/perl5
Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for local::lib
Writing MYMETA.yml and MYMETA.json
cp lib/lib/core/only.pm blib/lib/lib/core/only.pm
cp lib/local/lib.pm blib/lib/local/lib.pm
cp lib/POD2/PT_BR/local/lib.pod blib/lib/POD2/PT_BR/local/lib.pod
cp lib/POD2/DE/local/lib.pod blib/lib/POD2/DE/local/lib.pod
Manifying 4 pod documents
PERL_DL_NONLAZY=1 "/usr/bin/perl" "-I/home/docker-user/perl5/lib/perl5" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/bad_variables.t ...... ok   
t/carp-mismatch.t ...... ok   
t/classmethod.t ........ ok   
t/de-dup.t ............. ok   
t/lib-core-only.t ...... ok   
t/pipeline.t ........... ok   
t/shell.t .............. ok     
t/stackable.t .......... ok     
t/subroutine-in-inc.t .. ok   
t/taint-mode.t ......... ok   
All tests successful.
Files=10, Tests=149,  1 wallclock secs ( 0.04 usr  0.01 sys +  1.05 cusr  0.32 csys =  1.42 CPU)
Result: PASS
Manifying 4 pod documents
Installing /home/docker-user/perl5/lib/perl5/lib/core/only.pm
Installing /home/docker-user/perl5/lib/perl5/local/lib.pm
Installing /home/docker-user/perl5/lib/perl5/POD2/PT_BR/local/lib.pod
Installing /home/docker-user/perl5/lib/perl5/POD2/DE/local/lib.pod
Installing /home/docker-user/perl5/man/man3/POD2::DE::local::lib.3pm
Installing /home/docker-user/perl5/man/man3/lib::core::only.3pm
Installing /home/docker-user/perl5/man/man3/POD2::PT_BR::local::lib.3pm
Installing /home/docker-user/perl5/man/man3/local::lib.3pm
Appending installation info to /home/docker-user/perl5/lib/perl5/x86_64-linux-gnu-thread-multi/perllocal.pod
Use of uninitialized value $_[0] in substitution (s///) at /usr/share/perl/5.30/File/Basename.pm line 341.
fileparse(): need a valid pathname at /usr/share/perl/5.30/CPAN/FirstTime.pm line 1413.
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

So the installation ends with the error: fileparse(): need a valid pathname at /usr/share/perl/5.30/CPAN/FirstTime.pm line 1413 before it is finished installing Path::Tiny.

If I use the root user instead of the constructed docker-user in Dockerfile it works fine.

hakonhagland commented 2 years ago

I did a little debugging. It seems the problem is that the SHELL environment variable is unset, this variable must be valid when using local::lib. On the other hand, if installing with root user then local::lib is not needed since the script has write access to the installprivlib directories:

$ perl -MConfig -E'say $Config{installprivlib}'
/usr/share/perl/5.30

and the SHELL variable is not used here. By adding ENV SHELL=/bin/bash to the Dockerfile:

FROM ubuntu:20.04
SHELL ["/bin/bash", "-c"]
RUN apt-get update && \
        DEBIAN_FRONTEND="noninteractive" apt-get install -y \
        build-essential curl g++ git \
        vim sudo wget autoconf libtool \
        cmake

ARG user=docker-user
ARG home=/home/$user
RUN useradd --create-home -s /bin/bash $user \
        && echo $user:ubuntu | chpasswd \
        && adduser $user sudo
WORKDIR $home
USER $user
ENV USER=$user
ENV SHELL=/bin/bash
COPY entrypoint.sh $home
ENTRYPOINT ["./entrypoint.sh"] 

the SHELL variable is set correctly.

This solves this issue for me.