Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^4: Perl app won't compile /run from cron

by dazz (Beadle)
on May 24, 2018 at 22:56 UTC ( [id://1215177]=note: print w/replies, xml ) Need Help??


in reply to Re^3: Perl app won't compile /run from cron
in thread Perl app won't compile /run from cron

Hi
I didn't intentionally install the modules in the home directory but even if I did, I am trying to run a cron perl script as user (not root). So perl should have configured itself to do that by default.
I have just run  sudo cpan BLOB, the other module not found. It is installed in /usr/local/share/perl/5.24.1/BLOB
Installing the modules as root has fixed the problem. The perl compiler can now find the modules by default.

So modules installed with CPAN in the home user directory aren't found when the script is run as user by cron. That's a bug.


Dazz

Replies are listed 'Best First'.
Re^5: Perl app won't compile /run from cron
by huck (Prior) on May 24, 2018 at 23:25 UTC

    That's a bug.

    No it is not a bug, cron was designed that way

    cron is designed to set up a minimal environment when it starts a cron job. It is not a login session so it does not add any environment settings specified via login-semantics such as found in rc files. it is up to you to set them up.

    The Cron Environment and Cron Job Failures discusses this in more depth.

Re^5: Perl app won't compile /run from cron
by marto (Cardinal) on May 25, 2018 at 05:28 UTC

    "I didn't intentionally install the modules in the home directory but even if I did, I am trying to run a cron perl script as user (not root). So perl should have configured itself to do that by default. "

    This would be undesirable behaviour. Users without appropriate permissions should not be able to install things system wide. Fortunately for us as users the tools provide this useful feature under the hood to take care of this. If you read cpanm and local::lib you'll understand what they do.

    "So modules installed with CPAN in the home user directory aren't found when the script is run as user by cron. That's a bug."

    I appreciate why you may think so, but this is not the case, it isn't a bug. If you take a step back and think about this from the perspective of security and a multi user system, this is how it's supposed to work. The alternative options described in other responses would also have worked.

      Hi
      If I install a module with cpan as root, then the @INC is correctly updated and the perl scripts run perfectly from cron as user or root.
      So a user without root access loads perl into the user home dir, then tries to run the same script from cron user. That fails because cpan didn't update @INC environment correctly.

      How can that not be a cpan bug???

      Having to hand edit @INC is a work-around, not a solution.
      Similarly installing modules as root to avoid the issue for a user is also a work-around, and not a good one.

      The solution is to fix the root cause.

      It is not a risk to security if the user environment @INC is updated by cpan to allow a user to run perl scripts from user cron. If it is designed that way, then what you are saying is that it is designed to fail by default. It isn't like running a perl script from cron is a rare event. It should be easy.


      Dazz
        It should be easy.

        Agreed, and I know issues like this can be frustrating to debug, so I hope some clarification is helpful:

        the @INC is correctly updated ... That fails because cpan didn't update @INC environment correctly. ... the user environment @INC is updated by cpan

        Sorry, no, because it's not cpan's job to change @INC or the environment. cpan just installs modules into the directories that are available.

        installing modules as root to avoid the issue for a user is also a work-around, and not a good one

        Well, if you're installing modules into the system Perl, then normally only root has access to those directories.

        Here's a brief and slightly simplified overview of what's going on here:

        • Perl is compiled with a default set of paths of paths for @INC. For the system Perl, these are usually under /usr, and can be written to only by root. You can install modules there via the system's package manager (preferred, because otherwise there is a small but nonzero chance that a module installation can mess up the system Perl, and that's a huge pain to clean up), or with sudo cpan or a manual install performed with sudo. These modules are then available to everyone and don't require any changes to @INC because the paths are compiled into the perl binary.
        • Unfortunately, Image::Grab does not seem to be available as a precompiled Debian package - if it were, it'd probably be named libimage-grab-perl. So the approach to use cpan is fine. (Side note: you might want to check out cpanm, a nice alternative.)
        • What happened here is that when you run cpan as a normal user without sudo, on the first run modern versions of cpan will detect that they don't have write permissions to the system directories compiled into perl. It will then offer you some alternatives, the default being the use of local::lib.
        • local::lib will set up a directory, by default ~/perl5/lib/perl5, and it will also set up environment variables, normally by appending them to .profile or .bashrc, which do two things: First, they direct Perl's module installation tools to install modules in the new location. Second, it sets the PERL5LIB environment variable to point to the new directory. PERL5LIB is the environment variable that perl looks at for additional entries for @INC. This is why, when you log into a new shell, things "just work": PERL5LIB is set up correctly because .profile and .bashrc are run at login. It also means that it only works in the login shell of that user.
        • When running from cron, things are different! cron only provides a limited environment to the programs it runs. This means that PERL5LIB is not available by default there. You can see this yourself in action by running this from the shell: perl -MData::Dumper -e 'print Dumper($^X, $ENV{PERL5LIB}, \@INC)' and then putting the same thing in a crontab entry (redirect the output to a file, e.g. >/tmp/crontest, to capture the output) and comparing the outputs.
        The solution is to fix the root cause.

        I hope you see now that the root cause here is the environment provided by cron.

        This being Perl, there are a bunch of different solutions: a bunch of different ways to set PERL5LIB so that it's available even when scripts are run by cron (one example), other ways to set up @INC so that it always includes the directory where the modules are installed, and ways of installing modules so that perl can always find them (as I've described). So many, in fact, that I don't think listing them all here will be very helpful - each has its advantages and disadvantages, also depending on things like whether you need the modules to be available to all users or even all scripts that you want to run, and so on. So I'll just make a few suggestions of solutions (not workarounds!), and if you need more information, feel free to ask and provide more details of how you want your setup to look.

        • You can keep using local::lib, and as I've said before you can set up PERL5LIB in your crontab, since this really is the root cause. It's pretty simple: From your shell where things work, run echo $PERL5LIB, then take that value and stick a new line PERL5LIB=... at the top of your crontab (like PERL5LIB=/home/darren/perl5/lib/perl5).

        • Using perlbrew, you can install your own version(s) of Perl into your home directory (by default under ~/perl5/perlbrew). When you install Perl into a single directory like this, the nice thing is that it does not spread its library paths (the ones compiled into the perl binary) all around the system - instead they are all contained underneath that one directory, no fiddling around with PERL5LIB or local::lib necessary!

          So for example, I just used perlbrew to install Perl v5.26.2 on one of my Raspberry Pis. I disabled the local::lib environment variables, and now can do perlbrew use perl-5.26.2, and then use cpan to install modules into that Perl normally. And, I can now run that copy of Perl from my crontab via /home/pi/perl5/perlbrew/perls/perl-5.26.2/bin/perl, with access to all the modules!

        • Although as I said, installing modules into the system Perl has risks, if it's only one module and this is just a single-user system (in my experience on a Raspberry Pi one just tends to stick with the default pi user), the risk isn't too great. Since you've already got local::lib set up for the normal user, it might be easiest to not try and clean that up, and instead log in as root via sudo -i and then just run cpan from there. The advantage of this method over the above two is that the modules become available to everyone.

        The root cause is you are not using cron correctly

        see https://stackoverflow.com/questions/32726324/i-installed-a-module-successfully-with-cpan-but-perl-cant-find-it-why.

        If you choose to bootstrap local::lib (the default), the module will be installed inside ~/perl5. You may also be prompted something like: Would you like me to append that to /home/foo/.bashrc now? [yes] If you choose yes (the default), some variables will be added to your .bashrc (or the equivalent for your shell) so that when you run CPAN in the future, modules will continue to be installed in your home directory:

        so you have PERL5LIB updates stored in .bashrc (or the equivalent for your shell), but cron BY DESIGN does not run anything in that file. it is up to you to include anything from that file that you need in your cron request. Again see The Cron Environment and Cron Job Failures

        It was not "designed to fail by default", cpan did what it was designed to do, and cron did what it was designed to do, but instead you failed to use cron correctly.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1215177]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2024-03-28 13:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found