What I have: Chef;
What I need: RVM installed for node[:deploy][:user][:name]. I need user-wide install, not system-wide.
What I tried latest:
script 'install_rvm' do
user = node[:deploy][:user][:name]
interpreter '/bin/bash'
code "su -l #{user} -c '\curl https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer | bash -s stable'"
not_if { ::File.exists? "/home/#{user}/.rvm" }
end
When I manually run su -l <username> -c '\curl <long_url> | bash -s stable' on test server surely it works perfectly.
I expect Chef to run the same code, and in logs it seems like it does, but the next execute resource fails because in fact there is no /home/<username>/.rvm present.
Yes I know that in Chef I can specify user as user node[:deploy][:user][:name] instead of changing user with su but for some reason if I do that rvm would try to install itself in /root/.rvm (env not properly reset?).
Well, I would like to ask, why is Chef so extremely crappy even for such dead-simple tasks, but it looks like I've chosen the wrong place, so the question is what am I doing wrong or do I miss something obvious?
why not use chef-rvm from Fletcher Nichol - it is the supported way to deal with RVM in Chef.
Well, at least that worked and may be useful if all better ways to do it with Chef fail for you. Here is the resource for installing ruby
execute 'install_rvm' do
user('root')
user = node[:deploy][:user][:name]
command "su -l #{user} -c '\curl https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer | bash -s stable'"
not_if { ::File.exists? "/home/#{user}/.rvm" }
end
And the bonus one to create gemset if it is not already present:
execute 'rvm_install_ruby' do
user('root')
user = node[:deploy][:user][:name]
ruby = node[:deploy][:ruby]
gemset = node[:deploy][:gemset]
command "su -l #{user} -c 'rvm use #{ruby}##{gemset} --install --create'"
not_if do
if latest_patchlevel = `rvm list`.scan(/(ruby-#{ruby}-p)(\d+)/).map{ |a| a.last.to_i }.sort.last
`rvm list gemsets`.match /ruby-#{ruby}-p#{latest_patchlevel}##{gemset}/
end
end
end
Related
Today I started learning ansible and first thing I came across while trying to run the command ping on remote server was
192.168.1.100 | UNREACHABLE! => {
"changed": false,
"msg": "(u'192.168.1.100', <paramiko.rsakey.RSAKey object at 0x103c8d250>, <paramiko.rsakey.RSAKey object at 0x103c62f50>)",
"unreachable": true
}
so I manually setup the SSH key, I think I faced this as no writeup or Tutorial by any devops explains the step why they don't need it or if they have manually set it up before the writing a tutorial or a video.
So I think it would be great if we can automate this step too..
If ssh keys haven't been set up you can always prompt for an ssh password
-k, --ask-pass ask for connection password
I use these commands for setting up keys on CentOS 6.8 under the root account:
cat ~/.ssh/id_rsa.pub | ssh ${user}#${1} -o StrictHostKeyChecking=no 'mkdir .ssh > /dev/null 2>&1; restorecon -R /root/; cat >> .ssh/authorized_keys'
ansible $1 -u $user -i etc/ansible/${hosts} -m raw -a "yum -y install python-simplejson"
ansible $1 -u $user -i etc/ansible/${hosts} -m yum -a "name=libselinux-python state=latest"
${1} is the first parameter passed to the script and should be the machine name.
I set ${user} elsewhere, but you could make it a parameter also.
${hosts} is my hosts file, and it has a default, but can be overridden with a parameter.
The restorecon command is to appease selinux. I just hardcoded it to run against the /root/ directory, and I can't remember exactly why. If you run this to setup a non-root user, I think that command is nonsense.
I think those installs, python-simplejson and libselinux-python are needed.
This will spam the authorized_keys files with duplicate entries if you run it repeatedly. There are probably better ways, but this is my quick and dirty run once script.
I made some slight variations in the script for CentOS 7 and Ubuntu.
Not sure what types of servers these are, but nearly all Ansible tutorials cover the fact that Ansible uses SSH and you need SSH access to use it.
Depending on how you are provisioning the server in the first place you may be able to inject an ssh key on first boot, but if you are starting with password-only login you can use the --ask-pass flag when running Playbooks. You could then have your first play use the authorized_key module to set up your key on the server.
this is what I am doing:
Creating a new server on Linode. OS is centos 6.5
Logging in as root
running the following script to add a user called shortfellow which does not have a password.
The script is:
#!/bin/bash
yum -y update
adduser shortfellow
mkdir -p /home/shortfellow/.ssh
echo "ssh-rsa REALLYLONGSSHPUBLICKEY shortfellow#example.io" >> /home/shortfellow/.ssh/authorized_keys
chmod -R 700 /home/shortfellow/.ssh
chown -R shortfellow:shortfellow /home/shortfellow/.ssh
su - shortfellow
exit
The problem is that first time when I try to ssh into the system. It does not work at all. It simply asks for the password. I hit ctrl + c and try to ssh again as the same user, it works.
this behaviour is really annoying because I am writing code to create the server programmatically and it does not work because of this silly issue.
Does anyone have any idea why this might not be working as expected?
I did /sbin/mkhomedir_helper shortfellow in the script before the exit and it works correctly after that.
I guess the issue was really that the home directory for a user is created only at login and when I tried to programmatically create this user this would not happen for some reason.
I'm trying to run
ssh-add -L
(or any other dashed option), and zsh returns zsh: parse error near `-L'. It's the first time I see zsh do that, and it doesn't do it with any other command.
Any ideas ?
First thing to find out is whether ssh-add is an alias or a shell function, rather than the binary executable /usr/bin/ssh-add.
Second, try to run the same command in a ZSH session without your custom ZSH configuration. To get a clean environment, run
env -i TERM=$TERM LC_ALL=$LC_ALL LANG=$LANG zsh -f
Then try ssh-add -L again and let us know what you see.
Moreover, please post the output of the following:
uname -a
zsh --version
I want to make a shellscript to install Wine on a Mac
and i want the user to enter his/her password so the script can use it later on to make the installation unattended by automatically entering the password on "sudo" commands. This is what i got for now:
clear
echo Wine Installer v1.0
echo -------------------
echo by Sydcul
sleep 4
clear
echo "Please enter your OS X user password."
echo "It is needed in some parts of the installation."
read PASSWORD
echo "Wine installation starting."
echo "Please do not shut down your system."
mkdir winetmp
cd winetmp
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3.tar.bz2
tar xjvf MacPorts-2.0.3.tar.bz2
cd MacPorts-2.0.3
echo $PASSWORD | ./configure && make && sudo make install
echo $PASSWORD | sudo port -v selfupdate
echo $PASSWORD | sudo port -v install xorg
echo $PASSWORD | sudo port -v install wine
rm -rf ~/winetmp
clear
echo "Wine is successfully installed and ready for use!"
But at a certain point is still asks for the password.
How can i fix this?
Honestly, I would drop all that $PASSWORD stuff and remove the sudo from all your commands. You are writing an installation script, which should be run with elevated privileges. Have your users execute your script with sudo ./installwine.sh, and then run the commands in the script without sudo. All your port -v stuff will inherit the elevated privileges.
If you'd like to offer your user a nice error message if they forget to run the script with sudo (rather than just having your first call to port fail cryptically), you could check to see if the effective user ID ($EUID) is 0, and print the error message and exit otherwise. See https://askubuntu.com/questions/30148/how-can-i-determine-whether-a-shellscript-runs-as-root-or-not.
You can prompt the user for the password for the first time and then save it in a file (and don't forget to encrypt it).
The next time when you need it you can easily read it from the same file and store it in a variable and then use this command
echo $variablename | sudo -S command
Actually I think sudo doesn't accept password from stdin (you need to specify -S parameter to enable this).
As workaround you can execute sudo su to gain root privileges for all commands.
UPD: I'm not recommend to save password to file cause it is very bad solution from security point.
UPD2: You forget about Xcode, if it is not installed this script fails on compile stage :)
Why don't you just use the custom prompt option for sudo, and let it ask for the password if it needs it?
You start by checking if they're already root or not like this:
SUDO=""
if [[ 0 == $(id -u) ]]
then
SUDO="sudo "
fi
$SUDO command 1
$SUDO command arg arg arg
and then optionally combine that with the ability to customize the sudo prompt using the -p option.
then
SUDO="sudo -p \"I need elevated access for this part. Please enter %u's password:\" "
fi
You still get control over the interface, but don't prompt for a password unless you need it. Some people may have sudo set up for nopassword operation, for example. Others might run your installer as root. Or maybe their pasword is already cached with sudo. Etc. It's best to let sudo manage prompting, possibly using an askpass program (see the -A option) if necessary.
I'm trying to set up a cron job with the following command:
crontab -l
Begin Whenever generated tasks for: myapp
* * * * * /bin/bash -l -c 'cd /Users/boris/projects/myapp && script/rails runner "Resque.enqueue(MyModel)"'
I get the following error; in which I see its loading Ruby 1.8. The problem is I'm using RVM with ruby 1.9.2. How do I specify the correct RVM path in CRON?
Subject: Cron <boris#jz> /bin/bash -l -c cd /Users/boris/projects/myapp && script/rails runner "Resque.enqueue(Place)"
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=boris>
X-Cron-Env: <USER=boris>
X-Cron-Env: <HOME=/Users/boris>
Message-Id: <20110523022400.A5B242C608D#jz.local>
Date: Sun, 22 May 2011 19:24:00 -0700 (PDT)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- bundler/setup (LoadError)
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /Users/boris/projects/myapp/config/boot.rb:6
from script/rails:5:in `require'
from script/rails:5
How do I specify the correct RVM path in CRON?
Thanks in advance
Ruby path with which ruby:
/Users/boris/.rvm/rubies/ruby-1.9.2-p180/bin/ruby
Please do not use the -l switch in cron jobs. The --login switch instructs bash to run as a login shell. Therefore, it will load your environment, and things might appear to work. However, cron jobs are by nature non-interactive, non-login shells. Invoking them as if they were is just bad practice. Also, when bash starts a login shell, it first loads the system environment (/etc/profile), and if in that file something needs to print to the screen (like motd), your cron job will report nasty errors like this:
stty: TIOCGETD: Inappropriate ioctl for device
You don't need to write a cron runner neither (following that logic, you might as well write a cron runner runner). Please keep things simple. All you need to do is configure your cron job to launch a bash shell, and make that bash shell load your environment.
The shebang line in your script should not refer directly to a ruby executable, but to rvm's ruby:
#!/usr/bin/env ruby
This instructs the script to load the environment and run ruby as we would on the command line with rvm loaded.
On many UNIX derived systems, crontabs can have a configuration section before the actual lines that define the jobs to be run. If this is the case, you would then specify:
SHELL=/path/to/bash
This will ensure that the cron job will be spawned from bash. Still, your environment is missing, so to instruct bash to load your environment, you will want to add to the configuration section the following:
BASH_ENV=/path/to/environment (typically .bash_profile or .bashrc)
HOME is automatically derived from the /etc/passwd line of the crontab owner, but you can override it.
HOME=/path/to/home
After this, a cron job might look like this:
15 14 1 * * $HOME/rvm_script.rb
What if your crontab doesn't support the configuration section. Well, you will have to give all the environment directives in one line, with the job itself. For example,
15 14 1 * * export BASH_ENV=/path/to/environment && /full/path/to/bash -c '/full/path/to/rvm_script.rb'
Full blog post on the subject
Your problem is that you're executing two commands but not as you expect. The two commands are:
/bin/bash -l -c cd /Users/boris/projects/myapp
script/rails runner "Resque.enqueue(MyModel)"
With the second only executing if the first succeeded. I think you just need some quotes:
* * * * * /bin/bash -l -c 'cd /Users/boris/projects/myapp && script/rails runner "Resque.enqueue(MyModel)"'
Those single quotes will feed your cd ... && script/rails ... pair to /bin/bash as a single command and that should change the current working directory to what you want when script/rails is executed.
Easiest solution is to use this command instead:
Begin Whenever generated tasks for: myapp
* * * * * /bin/bash -l -c 'cd /Users/boris/projects/myapp && ./script/rails runner "Resque.enqueue(MyModel)"'