What is the best way to get UID from user within Chef? - ruby

I am using "user" resource to define the user within Chef.
Now, I want to retrieve the value of UID and GID for the same user.
Can this be done using the ruby code within chef?
Right now, I am trying to use bash resource and running the following command:
id -u $USERNAME

You can use the automatic attributes contributed by Ohai.
That information is accessible via
# uid
node['etc']['passwd']['$USERNAME']['uid']
# gid
node['etc']['passwd']['$USERNAME']['gid']
From the command line, you can explore the attributes as follows:
$ ohai etc/passwd/vagrant
{
"dir": "/home/vagrant",
"gid": 900,
"uid": 900,
"shell": "/bin/bash",
"gecos": "vagrant,,,"
}
$ ohai etc/passwd/vagrant/uid
900
If you create a user during the chef run and want to access its information within the same chef run, you probably have to trigger a reload of the responsible ohai plugin. (It might be possible that triggers this automatically, but I wouldn't expect so.)
ohai 'reload passwd' do
plugin 'passwd'
action :reload
end
user 'john' do
action :reload, 'ohai[reload passwd]'
end

For this you can use Ruby's Etc class: http://ruby-doc.org/stdlib-2.1.2/libdoc/etc/rdoc/Etc.html#method-c-getpwnam
[15] pry(main)> Etc.getpwnam('david').uid
=> 501
[16] pry(main)> Etc.getpwnam('david').gid
=> 20

Related

Deleting multiple users with Ansible ad-hoc command

When running Ansible ad-hoc to remove users I was unable to feed multiple items to
module. Like this:
ansible -i my_inv all -m user -a"name={{ users }} state=absent" --check --extra-vars='{"users":["user1","user2"]}'
the output is:
server1 | SUCCESS => {
"changed": false,
"name": "['user1', 'user2']",
"state": "absent"
}
it seems to be not opening array correctly.
Making json file also didnt work.
{
"users":["user1","user2"]
}
Is there any way to do it without writing a role?
No.
name parameter of user module takes a string as an argument, not a list.
You need either to loop (and for that you'd need a play - not necessarily a role), or run ansible executable several times.

Chef: How to set a user's password from an encrypted data bag

I am using Chef with kitchen (1.5.0) and vagrant (1.8.1) to manage a user consistently with a new server. My user recipe looks like this:
include_recipe "users"
group 'sudo'
password_secret = Chef::EncryptedDataBagItem.load_secret(node['enterprise_sp']['secret_file'])
jays_password = Chef::EncryptedDataBagItem.load('user_secrets','jgodse', password_secret)['password']
shadow_password = `openssl passwd -1 -salt xyz #{jays_password}`.strip
user 'jgodse' do
action :create
group 'sudo'
system true
shell '/bin/bash'
home '/home/jgodse'
manage_home true
password shadow_password #added to /etc/shadow when chef runs
end
The unencrypted data bag was where I configured my password in the clear. I then encrypted the data bag with a knife command.
This works, but this seems like a really dirty way around the problem of setting my password. I had to do that because the password directive of the user block only takes the shadow password, and that can only be generated by shelling out to an openssl command.
Is there a cleaner way of getting the shadow password without shelling out to an openssl command which generates the password?
You should not be storing the password at all, just hash it beforehand and put the hash in the data bag in the first place. Also using encrypted data bags like this is scary-level unsafe, please take some time to familiarize yourself with the threat model of Chef's encryption tools, this ain't it.
At least pre-calculate the password hash and put that into the data bag.
See https://github.com/chef-cookbooks/users for inspiration.

How Do I Get Vagrant/Puppet To Add Linux Passwords Correctly?

I am trying to use Vagrant to create an Ubuntu VM. My host is Windows7 and my basebox is precise64.
If I do the recommended way of adding a user in Puppet like this:
user { "johnboy":
ensure => present,
managehome => true,
password => '$6$ev8faya2$M2pB3YQRpKUJMnJx6LnsyTbDdi.umsEEZttD01pk8ZSfMGrVmlnjoVhIHyuqYt3.yaG1SZjaoSxB39nNgFKb//',
groups => ["admin"],
shell => "/bin/bash";
}
I log in after vagrant has provisioned my box and the hash is not in /etc/passwd.
If I don't set it with the resource type but use exec and usermod like this
user { "johnboy":
ensure => present,
managehome => true,
groups => ["admin"],
shell => "/bin/bash";
}
exec { 'set password':
command => "usermod -p '$6$ev8faya2$M2pB3YQRpKUJMnJx6LnsyTbDdi.umsEEZttD01pk8ZSfMGrVmlnjoVhIHyuqYt3.yaG1SZjaoSxB39nNgFKb//' johnboy",
require => User[johnboy];
}
I end up with only part of the hash in /etc/passwd
johnboy:.umsEEZttD01pk8ZSfMGrVmlnjoVhIHyuqYt3.yaG1SZjaoSxB39nNgFKb//:16101:0:99999:7:::
Some pages suggest installing ruby-shadow so I tried this:
gem install ruby-shadow
However, the install failed, probably because I don't have Ruby installed. Vagrant was a 100 MB download. Is the gem for managing passwords really not included with that?
How do I get Vagrant/Puppet to provision the password correctly?
That's because it's stored inside the /etc/shadow file. This is for security reasons as it is only accessible by the root/super user.
Escape the dollar signs in the hash like this and it should work.
exec { 'set password':
command => "usermod -p '\$6\$ev8faya2\$M2pB3YQRpKUJMnJx6LnsyTbDdi.umsEEZttD01pk8ZSfMGrVmlnjoVhIHyuqYt3.yaG1SZjaoSxB39nNgFKb//' johnboy",
require => User[johnboy];
}

Issue with :hosts

I have a Capfile for Multistage deploys that needs to deploy the code to one server (NFS) and finally restart several application servers. Roles can therefore not be used easily since application servers do not need to be used for deploy:update_code. I have come up with something that might work, but have a issue that needs to be resolved.
application_servers = nil
task :production do
role :nfs, "nfs.someserver.net"
application_servers = "app.someserver.net"
end
task :staging do
role :nfs, "nfs-staging.someserver.net"
application_servers = "app-staging.someserver.net"
end
desc "tail resin logs #{resin_logs}"
task :tail, :hosts => application_servers do
puts("Server is:"#{application_servers})
stream "tail -f #{resin_logs}"
end
And when running:
#$ cap staging tail
* executing `staging'
* executing `tail'
Server is:app-staging.someserver.net
* executing "tail -f /log/resin/*.log"
servers: ["nfs-staging.someserver.net"]
[nfs-staging.someserver.net] executing command
tail: cannot open `/log/resin/*.log' for reading: No such file or directory
tail: no files remaining
command finished
failed: "sh -c 'tail -f /log/resin/*.log'" on nfs-staging.someserver.net
When printing value of application_servers in task tail it says "app-staging.someserver.net", but the value used in :hosts => application_servers is empty (which is why it uses the role nfs instead).
Why does the variable application_server have two different values? Is it scope issue? I have tried with global ($) and that does not work as well.
Solved the issue just by changing from using :hosts to :roles on application specific task and added a new role. The key feature is to use no_release so that the code is not deployed to application servers. We only want to restart resin instance on those machines.
task :production do
role :nfs, "nfs.someserver.net"
role :application, "app.someserver.net", :no_release => true;
end
task :staging do
role :nfs, "nfs-staging.someserver.net"
role :application, "app-staging.someserver.net", :no_release => true;
end
desc "tail resin logs #{resin_logs}"
task :tail, :roles => application_servers do
puts("Server is:"#{application_servers})
stream "tail -f #{resin_logs}"
end

firefox not opening - cron, ruby, firewatir

I have written a ruby script which opens up dlink admin page in firefox and does a ADSL connection or disconnection.
I could run this script in the terminal without any problem. But if I put it as cron job, it doesn't fire up firefox.
This is the entry I have in crontab
# connect to dataone
55 17 * * * ruby /home/raguanu/Dropbox/nettie.rb >> /tmp/cron_test
I see the following entries in /tmp/cron_test. So it looks like the script indeed ran.
PROFILE:
i486-linux
/usr/bin/firefox -jssh
But I couldn't figure out why I didn't see firefox opening up, for this automation to work. Here is /home/raguanu/Dropbox/nettie.rb
#!/usr/bin/ruby -w
require 'rubygems'
require 'firewatir'
require 'optiflag'
module Options extend OptiFlagSet
character_flag :d do
long_form 'disconnect'
description 'Mention this flag if you want to disconnect dataone'
end
flag :l do
optional
long_form 'admin_link'
default 'http://192.168.1.1'
description 'Dlink web administration link. Defaults to http://192.168.1.1'
end
flag :u do
optional
long_form 'user'
default 'admin'
description 'Dlink administrator user name. Defaults to "admin"'
end
flag :p do
optional
long_form 'password'
default 'admin'
description 'Dlink administrator password. Defaults to "admin"'
end
flag :c do
optional
long_form 'connection_name'
default 'bsnl'
description 'Dataone connection name. Defaults to "bsnl"'
end
extended_help_flag :h do
long_form 'help'
end
and_process!
end
class DlinkAdmin
include FireWatir
def initialize(admin_link = "http://192.168.1.1", user = 'admin', pwd = 'admin')
#admin_link, #user, #pwd = admin_link, user, pwd
end
def connect( connection_name = 'bsnl' )
goto_connection_page connection_name
# disconnect prior to connection
#browser.button(:value, 'Disconnect').click
# connect
#browser.button(:value, 'Connect').click
# done!
#browser.close
end
def disconnect( connection_name = 'bsnl' )
goto_connection_page connection_name
# disconnect
#browser.button(:value, 'Disconnect').click
# done!
#browser.close
end
private
def goto_connection_page( connection_name = 'bsnl')
#browser ||= Firefox.new
#browser.goto(#admin_link)
# login
#browser.text_field(:name, 'uiViewUserName').set(#user)
#browser.text_field(:name, 'uiViewPassword').set(#pwd)
#browser.button(:value,'Log In').click
# setup > dataone
#browser.image(:alt, 'Setup').click
#browser.link(:text, connection_name).click
end
end
admin = DlinkAdmin.new(Options.flags.l, Options.flags.u, Options.flags.p)
unless Options.flags.d?
admin.connect( Options.flags.c )
else
admin.disconnect( Options.flags.c )
end
Any help is appreciated.
You need to have a DISPLAY environment pointing at a valid X-server. This could either involve setting it to the value ":0.0" (without quotes), such that it refers to your local standard DISPLAY.
There's a few things to keep in mind though:
You could run an X virtual frame buffer (xvfb), so that Firefox simply uses that as it's display. This would mean that Firefox would be able to do all its graphical operations, but that it would be independent of your standard graphical environment. You'll have to set the DISPLAY variable appropriately so that it points to the xvfb instance. For instance, if you invoke xvfb as follows:
Xvfb :1 -screen 0 1600x1200x32
Then you'll be able to use this by setting the DISPLAY variable to :1
You're starting a full-blown firefox instance to simply connect or disconnect your modem. You would most likely be able to use "curl" to send the appropriate HTTP requests to the server, such that it performs a connect or disconnect for you. One way to trivially see what you should recreate would be to install a Firefox plugin such as LiveHTTPHeaders and note down the most important HTTP requests as you perform the actions manually.
There's even a ruby binding for curl:
libcurl for Ruby. The resulting script should be much smaller than your current script.
Programs run from cron don't have your interactive environment. Therefore they don't have and DISPLAY variable, and so you can't run any X (graphical) programs, e.g. Firefox.
I would suggest doing the HTTP connections yourself, in ruby, rather than trying to automate Firefox.
the crontab entry is wrong
it is like
#min hour day month dow user command
55 17 * * * ur_user_is_missing ruby /home/raguanu/Dropbox/nettie.rb >> /tmp/cron_test

Resources