Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

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

by dazz (Beadle)
on May 26, 2018 at 23:03 UTC ( [id://1215260]=note: print w/replies, xml ) Need Help??


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

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
  • Comment on Re^6: Perl app won't compile /run from cron

Replies are listed 'Best First'.
Re^7: Perl app won't compile /run from cron
by haukex (Archbishop) on May 27, 2018 at 15:39 UTC
    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.

      installing modules into the system Perl has risks
      Very true. Just try to avoid it if at all possible.

      If you can, just leave the system perl alone, install your own version via perlbrew and use paths to this version as hash-bangs in your scripts.

      Then you should have no problems running them via cron.

        Hi
        I have been using perl for about 10 years. I struck and solved the cron PATH limited environment problem years ago.
        Never had a problem running perl scripts from cron before.
        Never new about @INC and never knew about or used local::lib. Never before needed to.

        This has been a frustrating problem to solve. Now that I know what to search for, I find this is a problem shared by many others.
        I am sure it would be really helpful for others in the future to add this as a specific item in the tutorials section of this website.


        Dazz
Re^7: Perl app won't compile /run from cron
by huck (Prior) on May 27, 2018 at 04:16 UTC

    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.

      Hi OK I have not used cpan correctly.
      I have never heard of local::lib or @INC until this thread.
      I did find cpan variables in my .bashrc file and removed them.
      I did run  cpan > o conf init.
      There was no option asked that mentioned "bootstrap".
      On completion of the command .bashrc remained clear of any perl stuff.

      If it isn't a bug it is a bad design. It shouldn't be so difficult to do something so simple.

      Dazz
        I have never heard of local::lib or @INC until this thread.

        @INC is mentioned in the FAQ, perlrun, the documentation for lib and, of course perlvar. I'm slightly surprised that you've read none of these yet.

        It shouldn't be so difficult to do something so simple.

        Where's the difficulty? Just set up your environment properly as outlined in Re: Perl app won't compile /run from cron and you're there.

        It's neither a bug nor bad design. You're using tools without understanding how they work, and then declaring bugs where none exist when things don't work as you imagine they should.

        Your configuration of the CPAN client and setup does not live in your .bashrc file but likely in ~/.cpan/CPAN/MyConfig.pm. If you erase that, CPAN will likely ask you again, which install method you prefer for modules.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2024-04-18 05:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found