Reputation: 31
Is there a way to iterate through node.run_state data? This is in a RHEL environment with Active Directory users. I have a ruby block that populates node.run_state. I have to have this run at converge time, because the overall cookbook will be used for build automation. On the very first run, the cookbook installs Centrify, then later needs to run adquery to gather user info for populating home directories with SSH keys.
On a chef-client run, I see this:
Compiling Cookbooks...
{}
Obviously, that's the puts running in compile time against an empty hash. At converge time, nothing happens in the loop with the 2 directory and 1 template resource.
Here is the relevant piece of the recipe:
ruby_block 'set uid, gid, and homedir for users' do
block do
base_attr['ssh_keys'].each do |user, pubkeys|
# next unless Dir.exist?(homedir)
node.run_state[user] = {}
puts "Checking user #{user}..."
if local_users.key?(user)
node.run_state[user]['homedir'] = local_users[user]['homedir']
node.run_state[user]['uid'] = local_users[user]['uid'].to_i
node.run_state[user]['gid'] = local_users[user]['gid'].to_i
elsif centrify_users.key?(user)
node.run_state[user]['homedir'] = centrify_users[user]['homedir']
node.run_state[user]['uid'] = centrify_users[user]['uid'].to_i
node.run_state[user]['gid'] = centrify_users[user]['gid'].to_i
else
puts "user #{user} not found."
# Place holder values.
node.run_state[user]['homedir'] = "/tmp/#{user}"
node.run_state[user]['uid'] = 0
node.run_state[user]['gid'] = 0
end
end
end
end
# Dir.exist? guard should bypass compile-time error.
# "name is a required property"
# next unless Dir.exist?(homedir)
puts node.run_state
node.run_state.each do |user|
directory node.run_state[user]['homedir'] do
owner node.run_state[user]['uid']
group node.run_state[user]['gid']
mode '0700'
end
directory "#{node.run_state[user]['homedir']}/.ssh" do
owner node.run_state[user]['uid']
group node.run_state[user]['gid']
mode '0700'
end
template "#{node.run_state[user]['homedir']}/.ssh/authorized_keys" do
owner node.run_state[user]['uid']
group node.run_state[user]['gid']
mode '0600'
source 'authorized_keys.erb'
variables(
sshkeys: base_attr['ssh_keys'][user]
)
end
end
Any ideas how to make this work?
Upvotes: 2
Views: 1122
Reputation: 31
My subconscious mind told me this morning to pull the path inside the directory resource, and THEN use lazy on it. So I have the working solution. node.run_state in the ruby_block, and lazy blocks around the requisite attributes in the subsequent resources that use node.run_state. Thanks for the feedback on this issue.
Upvotes: 0
Reputation: 21226
As you are setting node.run_state
in the execution phase, you also need to read it in execution phase. Currently your node.run_state.each
is skipped, because, as you noted correctly, node.run_state
is empty.
So you need to move this node.run_state.each
execution into execution phase. One possibility is to create a ruby_block
and move your cycle there, unfortunately you can't use the resource methods there as in recipe, but you can use resource classes directly:
ruby_block 'Create ssh authorized keys' do
block do
node.run_state.each do |user|
d = Chef::Resource::Directory.new(node.run_state[user]['homedir'], run_context)
d.owner node.run_state[user]['uid']
d.group node.run_state[user]['gid']
d.mode '0700'
d.run_action :create
d = Chef::Resource::Directory.new("#{node.run_state[user]['homedir']}/.ssh", run_context)
d.owner node.run_state[user]['uid']
d.group node.run_state[user]['gid']
d.mode '0700'
d.run_action :create
t = Chef::Resource::Template.new("#{node.run_state[user]['homedir']}/.ssh/authorized_keys", run_context)
t.owner node.run_state[user]['uid']
t.group node.run_state[user]['gid']
t.mode '0600'
t.source 'authorized_keys.erb'
t.variables(sshkeys: base_attr['ssh_keys'][user])
t.run_action :create
end
end
end
Upvotes: 0
Reputation: 1169
Add lazy {} block around node.run_state where you are utilizing it. So in your directory and template resource. lazy {} ensures that the resource evaluates during the execution phase of a Chef Infra Client run (as opposed to during the compile phase). You can read more about lazy block here
Upvotes: 1