Ismail
Ismail

Reputation: 809

Reading a file and creating a user in Chef

I have a list of IP address along with me. In front of those IP I have a username. What I am trying to do is make Chef read the file having IP and username and once it encounter the IP, it should create a user of that name. But when I do I get a user but the name of the user comes out to be a number.

Here is my recipe

File.open("/tmp/users.txt", "r") do |file|
    file.readlines.each_with_index do |ip,user|
      if ip = node[:ipaddress]
            user ip[user] do
                action :create
                supports :manage_home => true
                comment 'Test User'
                home '/home/ip[user]'
                shell '/bin/bash'
                password 'password'
            end
      end
   end

my users.txt file

231.27.59.232, test1
272.27.59.15, tes2
985.54.25.22, test3

Now when I run the recipe this is what I get

Recipe: repo_update::users
   * cookbook_file[/tmp/users.txt] action create (up to date)
   * user[1] action create
     - create user 1
   * user[7] action create
     - create user 7
   * user[2] action create
     - create user 2

Please tell me what is wrong here.

Upvotes: 0

Views: 1305

Answers (2)

Tejay Cardon
Tejay Cardon

Reputation: 4223

The problem is this line:

user ip[user] do

You are calling the [] method on the ip string. Furthermore, you're going to get a name collision between the resource user and the block variable. Finally, you are giving each user the home of '/home/ip[user]'. You need to put the string in "'s and wrap the variable in #{ and } Try this:

File.open("/tmp/users.txt", "r") do |file|
  file.readlines.each do |line|
    entries = line.split(',')
    ip = entries[0].strip
    username = entries[1].strip
    if ip = node[:ipaddress]
      user username do
        action :create
        supports :manage_home => true
        comment 'Test User'
        home "/home/#{username}"
        shell '/bin/bash'
        password 'password'
      end
    end
 end

Also, reading this all from a file is a very non cheffy thing to do. Either use a databag or a hash stored in an environment variable, which also saves you from needing to loop at all:

userhash = node['my_users'][node['ipadddress']]
user userhash['username']
  action :create
  supports :manage_home => true
  comment 'test user'
  home userhash['home'] || "/home/#{userhash['username']"
  shell userhash['shell'] || '/bin/bash'
  password userhash['password'] || 'password'
end

Upvotes: 0

Tensibai
Tensibai

Reputation: 15784

Lots of problem here... The answer of Tejay is the way to go, I'll just try to explain why your code don't work and how to fix it so it could be of some use later :)

File.open("/tmp/users.txt", "r") do |file|
  file.readlines.each_with_index do |ip,user|
    puts "values are #{ip} and #{user}"
  end
end

Gives:

values are 231.27.59.232, test1
 and 0
values are 272.27.59.15, tes2
 and 1
values are 985.54.25.22, test3
 and 2

each_with_index won't split magically your line into two part, it will just assign the last parameter the actual index in the iteration.

A fixed version of your code would be:

File.open("/tmp/users.txt", "r") do |file|
  file.readlines.each do |line| # just iterate and get line
    ip,myuser=line.gsub("\n",'').split(',') # set ip and myuser variable with values comma separated, using myuser to avoid conflict with the resource name. Using gsub to remove traling carriage return in user name
    if ip == node[:ipaddress] # test equality, a single = will assign ip a value and always be true.
      user myuser do # create the user using the variable, no need to interpolate here
        action :create
        supports :manage_home => true
        comment 'Test User'
        home "/home/#{myuser}" # use interpolation here inside double quotes (won't work in single quotes)
        shell '/bin/bash'
        password 'password'
      end
    end
  end
end

Upvotes: 1

Related Questions