/usr/local/bin rant
So, imagine you're a CentOS user, and you want to install a CPAN module into the system. Let's say you want to install cpanm.
You get the root shell with sudo -s
.
You enter: cpan App-cpanminus
.
And then you enter: cpanm --help
... and oops:
[root@localhost vagrant]# cpanm --help
bash: cpanm: command not found
WAT?
What just happened is that cpan
installs scripts into /usr/local/bin/
, and /usr/local/bin/
is not in the root's $PATH
.
I don't think CPAN toolchain is to blame here. But I think that if you can't run the software you just installed, something somewhere is horribly wrong.
But wait, there's more.
There're several different ways to get the root shell:
sudo -s
su -
su
Let's see...
[vagrant@localhost ~]$ sudo -s
[root@localhost vagrant]# echo $PATH
/sbin:/bin:/usr/sbin:/usr/bin
[vagrant@localhost ~]$ su
Password:
[root@localhost vagrant]# echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin
[vagrant@localhost ~]$ su -
Password:
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
The first one, sudo -s
, uses the secure_path
option from /etc/sudoers
.
The second one, su
, inherits the current user's environment.
And the third one, su -
, is the same as su -l
, makes the shell a login shell, which resets the environment, so that it's the same as if you'd login with the root account initially.
But wait, it gets worse. Let's try cron:
[root@localhost ~]# crontab -l
* * * * * perl -E 'say $ENV{PATH}' >/tmp/cron.path
[root@localhost ~]# cat /tmp/cron.path
/usr/bin:/bin
Cron is the reason I wrote this post in the first place. The most popular complain about my Ubic these days is that it doesn't start services after the reboot. That's because Ubic bootstraps services on reboot with the crontab, which doesn't include /usr/local/bin/
(because there are many ways to setup Ubic, e.g., with perlbrew, so I didn't want to make any assumptions about the user's environment).
I'm giving up. I'm just going to always add /usr/local/bin to $PATH if it's not already there.
BTW, sudo -s
$PATH issue is more RedHat-family specific, but cron
's $PATH issue is not, as far as I know.
But why? What's the reason for all this? Is it for the sake of security? Can there really be such a program that's safe to keep in /usr/local/bin, accessible to all users, but not to the root? Really?
PS: I know, I know, everyone should use Perlbrew. I agree, but don't forget to source $HOME/perl5/perlbrew/etc/bashrc
everywhere, especially in your crontabs.
If you enjoyed this blog post, you could give me a +1 on the questhub for it. |
cpan(1) installs to wherever your perl's config tells it to install, which is likely in the same place cpan(1) is. And, the -i switch there is just extra typing. :)
For cron, I don't rely on PATH at all:
> And, the -i switch there is just extra typing. :)
Yeah, I know, old habit...
> For cron, I don't rely on PATH at all
This doesn't help if your script calls other scripts.
> which is likely in the same place cpan(1) is
Ok, I checked, that's not the case on CentOS. perl-CPAN.x86_64 contains
/usr/bin/cpan
, which then installs stuff to/usr/local/bin/
with default settings.But I admit I don't know anything about CentOS. Or how to customize
CPAN.pm
's behavior, for that matter... I usually just install cpanm with it and never look back.Why are you using CPAN on CentOS? You should be installing these as RPMs. ;-)
I don't. I don't use CentOS at all. But some users of my code do, and I don't blame them.
Not all modules are packaged as RPMs, and those which are packaged are often out-of-date.
cpan2rpm - There are many packages in the EPEL repo as well.
CPAN is an actual PITA for sys admins. When in Rome do as the Romans. Debian? use apt. RedHat use RPMs. Perl needs to become friendlier to system deployment and stop this CPAN madness. IMHO.
While I certainly understand your point, I completely disagree. Thanks to CPAN (and its clients) I can package once and distribute for every platform/distro, not having to package and repackage and repackage for every format. When the world settles on one installer format (that includes Mac/Windows), then I will happily stop using cpan clients.
/usr/local, on some platforms, is not secure. On other platforms, /usr/contrib is an unsecure location. There is a reason not to include it in root's default path.
Under cron (or system startup, or manually running scripted tasks), I typically have a launcher script that I use if I need to set up an environment. The reason is that I want to have an explicit environment when running things as root. As myself, that is an entirely different story, but as root, I want to know exactly what is going on.
--MLX
But the flipside is that knowing about the various package management tools is a PITA if you're a perl programmer who happens to have to admin various boxes :-)
I install Perl in a number of places, and like the fact that my chosen method for installing Perl and modules works the same on all of them.
That said, why don't you write a separate blog post on "packaging perl for sysadmins" or somesuch. I'd like to read opinions and suggestions from a more seasoned sysadmin on how to approach these sort of things.
Here's a nice thread that speaks to the cpan v package manager choice.
http://mail.pm.org/pipermail/melbourne-pm/2007-May/002316.html
I think developers prefer CPAN because they can immediately get things done, sys admins like order and integration of components into their environment that will play nice with their tool chains. Ultimately if you are deploying across multiple platforms flexibility is key, however in a homogenous environment rapid deployment using native tools is preferred. If the aim is a stable production environment (especially one that can be brought up and torn down quickly - think cloud) my vote is for package managers, even if I have to create my own repo and packages.
It's not a holy war for me however,in development mode I may delay creating a package and use CPAN temporarily, although this has the potential to become a rabbit hole quickly if some module is using Moose for example.
Again, not a holy war. Flexibility and pragmatism, and your particular use cases should dictate behavior instead of dogma and stubbornness.
Looks like your questhub/play-perl links are broken here.
Oops, I copy-pasted Neil's code and forgot to replace the link. Thanks! :)