New user and coder looking to set variables

Hi All,

I'm a new Chef user, and worse new real programing (done shell and script, but this is new). Anyway I'm running the client as standalone with local recipes and trying to query the account id and instance id for the EC2 instance I'm on (have the command to get this) then I want to parse that down and use it as a variable to use later in the recipe.

More specifically I have a recipe that runs when a new EC2 instance is launched and sets the hostname and joins it to our active Directory domain. now I want to use variables for the server name. To do this I want it to go out and get the account ID the instance is in, use that to set the first half of the servername and then pull the instance ID and add the last 4 characters of that to the servername

thanks in advance for any help I can get, even to just point me in the right direction of a good example.

Doug

Hey Doug,

There are a couple of options here but before that as you didn't indicate how you were getting that I wanted to mention ohai which has a plugin for aws in case you were grabbing it another way. You might even consider writing your own plugin if you wanted to get fancy.

One question that is important to consider here is the scope, is local within the recipe sufficient or does it need to be accessible from other recipes or nodes? I suppose other nodes is a bit more difficult with solo but I digress. All code given here should be considered pseudo as I have not tested any of it.

For a local variable it should be:

recipes/my-recipe.rb:

desired_hostname = "#{node['ec2']['account_id']}-#{node['ec2']['instance_id'][-4..-1]}"
# bunch of stuff

# use it in a template
template '/path/to/template.erb' do
  # optionally include some helper modules
  # helpers(MyHelperModule)
  variables(hostname: desired_hostname)
end

Setting an attribute within a recipe

I am honestly not too familiar with with running chef solo as I have not done that in years but I think you would still be able to set a chef attribute from within your recipe and it should be accessible without the server as long as it is in the same runlist (does not require the same cookbook.

recipes/some_recipe_that_sets_desired_value.rb:

node.default['my_custom_namespace']['desired_hostname'] = "#{node['ec2']['account_id']}-#{node['ec2']['instance_id'][-4..-1]}"

recipes/some-other-recipe.rb:

Chef::Log.Info "I want to set my host to #{node['my_custom_namespace']['desired_hostname']}"

There are also similar approaches that could be taken by storing the data in a data bag but essentially your just setting some data somewhere to be accessed somehow.

Library Helpers

You might also consider writing a library helper methods. Here is a good post talking about that approach.

Hope this was helpful in pointing you in the right direction(s).

Thank you Thank you!! This got me moving in the right direction. Its still not as fancy as it could be but keeps me moving forward. Still having one issue feeding a variable into the groups resource for windows to add the admin groups to administrators (either ignores the variable as text OR adds quotes and fails to find the group name)... ran into something similar with the realm join line below overcoming spaces in the OU path.

Anyway, for others here's the bases of code I ended up with for right now. This is reading the ec2 account ID, from that setting the 5 fixed variables as well as sets the target server name to be the friendly name for the project appended with the last 4 digits from the instance ID (projectname-XXXX).

if "#{node['ec2']['account_id']}" == 'account#1'
node.default['custom_namespace'] = "Freindlyname#1"
node.default['desired_ou'] = "OUpath#1"
node.default['admingroup'] = "ADadmingroupforthisproject"
node.default['domadduser'] = "userdelegatedtojoindomaininou#1"
node.default['domaddpass'] = "userspassword"
elsif "#{node['ec2']['account_id']}" == 'account#2'
node.default['custom_namespace'] = "Freindlyname#2"
node.default['desired_ou'] = "OUpath#2"
node.default['admingroup'] = "ADadmingroupforthisproject"
node.default['domadduser'] = "userdelegatedtojoindomaininou#2"
node.default['domaddpass'] = "userspassword"
elsif "#{node['ec2']['account_id']}" == 'account#3'
node.default['custom_namespace'] = "Freindlyname#3"
node.default['desired_ou'] = "OUpath#3"
node.default['admingroup'] = "ADadmingroupforthisproject"
node.default['domadduser'] = "userdelegatedtojoindomaininou#3"
node.default['domaddpass'] = "userspassword"
else
node.default['custom_namespace'] = "NoMatch"
end

node.default['desired_hostname'] = "#{node['custom_namespace']}-#{node['ec2']['instance_id'][-4..-1]}"

hostname 'changehostname' do
hostname "#{node['desired_hostname']}.domainFQDN"
end

execute 'realm join' do
command "echo #{node['domaddpass']}| realm join -U #{node['domadduser']} domainFQDN --computer-ou="#{node['desired_ou']}" --verbose"
end

ruby_block 'insert_line' do
block do
file = Chef::Util::FileEdit.new("/etc/sudoers")
file.insert_line_if_no_match("nomatch", "##Add the AD users and groups from the ASCN domain.")
file.insert_line_if_no_match("nomatch", "%ASCN\\Domain\ Admins ALL=(ALL:ALL) ALL")
file.insert_line_if_no_match("nomatch", "%ASCN\\#{node['admingroup']} ALL=(ALL:ALL) ALL")
file.write_file
end
end

execute 'allow project login' do
command "realm permit -g #{node['admingroup']}"
end

ugggghhh, sometimes the simplest things just kill me...

So how do I resolve the variable keeping the outside single quotes with not passing in the double quotes around the group name???

Set Variable:
node.default['admingroup'] = "ADgroupname"
Use Variable
members 'domain"'"#{node['admingroup']}"'"' gives me this 'domain"ADgroupname"' But I need 'domain\ADgroupname'

If I drop the outside single quotes it trys to use "servername" prefixed to no matter what else is in the members value, if I drop the "'" around the variable it gives me a syntax error pointed at the a in admin group (syntax error, unexpected local variable or method, expecting `end'...bers 'domain#{node['admingroup']')

had to walk for a little bit but finally alright found the magic formula... ended up really just having to double backslash.

members 'domain\'"#{node['admingroup']}"''