Chef shell_out just giving hex values - ruby

I'm creating the Chef recipe below. However, my shell_out calls are just returning hex values for the expanded variable. How to get the value of the find command in the variable, and not a junk hex value?
Here is the relevant code snipet from my recipe::
so = nil
bash "getPath" do
Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
command = "find \/ -path \\*ohai\/plugins"
so = shell_out(command)
end
listOfFiles = ["#{so}\cert.rb","#{so}\key.rb","#{so}\perms.rb","#{so}\propertiesFiles.rb","#{so}\warFiles.rb","#{so}\yum.rb"]
templates = { 1 => "cert.rb", 2 => "key.rb", 3 => "perms.rb", 4 => "propertiesFiles.rb", 5 => "warFiles.rb", 6 => "yum.rb" }
i = 1
listOfFiles.each do |remote|
template "#{remote}" do
source 'cert.rb' #this is going to be a variable once I figure out how to call it from the "templates" hash. Just doing a static file for troubleshooting purposes now
owner 'root'
group 'root'
mode '0644'
action :create
end
end
Here is part of the chef-client run output:
- create new file #<Mixlib::ShellOut:0x00000004dd88b8>yum.rb
- update content in file #<Mixlib::ShellOut:0x00000004dd88b8>yum.rb from none to fccd51
--- #<Mixlib::ShellOut:0x00000004dd88b8>yum.rb 2016-10-31 11:52:40.652276263 -0400
+++ ./.chef-#<Mixlib::ShellOut:0x00000004dd88b8>yum20161031-8408-1svdruo.rb 2016-10-31 11:52:40.652276263 -0400
## -1 +1,17 ##
+#
+# Cookbook Name:: inventory
+# Recipe:: default
+#
+# Copyright (c) 2016 me, All Rights Reserved.
+
+Ohai.plugin(:Cert) do
+ provides 'certFiles'
+
+ collect_data(:linux) do
+ certFiles Mash.new
+ so = shell_out("find \/ -name \"*.crt\"")
+ certFiles[:values] = so.stdout
+ end
+end
+
- change mode from '' to '0644'
- change owner from '' to 'root'
- change group from '' to 'root'
- restore selinux security context
* ohai[reload] action reloadPuTTYPuTTYPuTTYPuTTYPuTTY
- re-run ohai and merge results into node attributes
Running handlers:
Running handlers complete
Chef Client finished, 8/20 resources updated in 05 seconds
[root#host plugins]# PuTTYPuTTYPuTTYPuTTYPuTTY^C

Almost there!
so = shell_out(command) # Returns a Mixlib::ShellOut object
output = so.stdout # Returns stdout of your command, as String

Related

Chef notification within each method

I have a recipe that iterates a hash containing SQL scripts in an each method and -- in case the script changed from the previous run -- the cookbook_file resource notifies the execute resource to run.
The issue is that it seems it always runs the execute using the last element of the hash.
Following the attributes file
default['sql_scripts_dir'] = 'C:\\DBScripts'
default['script_runner']['scripts'] = [
{ 'name' => 'test', 'hostname' => 'local' },
{ 'name' => 'test2', 'hostname' => 'local' },
{ 'name' => 'test3', 'hostname' => 'local' },
{ 'name' => 'test4', 'hostname' => 'local' },
]
And the recipe
directory node['sql_scripts_dir'] do
recursive true
end
node['script_runner']['scripts'].each do |script|
cookbook_file "#{node['sql_scripts_dir']}\\#{script['name']}.sql" do
source "#{script['name']}.sql"
action :create
notifies :run, 'execute[Create_scripts]', :immediately
end
execute 'Create_scripts' do
command "sqlcmd -S \"#{script['hostname']}\" -i \"#{node['sql_scripts_dir']}\\#{script['name']}.sql\""
action :nothing
end
end
And it produces the following output:
Recipe: test_runner::default
* directory[C:\DBScripts] action create
- create new directory C:\DBScripts
* cookbook_file[C:\DBScripts\test.sql] action create
- create new file C:\DBScripts\test.sql
- update content in file C:\DBScripts\test.sql from none to 8c40f1
--- C:\DBScripts\test.sql 2020-07-30 17:30:30.959220400 +0000
+++ C:\DBScripts/chef-test20200730-1500-11bz3an.sql 2020-07-30 17:30:30.959220400 +0000
## -1 +1,2 ##
+select ##version
* execute[Create_scripts] action run
================================================================================
Error executing action `run` on resource 'execute[Create_scripts]'
================================================================================
Mixlib::ShellOut::ShellCommandFailed
------------------------------------
Expected process to exit with [0], but received '1'
---- Begin output of sqlcmd -S "local" -i "C:\DBScripts\test4.sql" ----
STDOUT:
STDERR: Sqlcmd: 'C:\DBScripts\test4.sql': Invalid filename.
---- End output of sqlcmd -S "local" -i "C:\DBScripts\test4.sql" ----
Ran sqlcmd -S "local" -i "C:\DBScripts\test4.sql" returned 1
The expected behavior is that the recipe runs sequentially the 4 scripts in the example instead of running just the last one. What am I missing for getting it done?
You are creating 4 nearly identical resources all named execute[Create_scripts] and when the notification fires from the first cookbook_file resource being updated it finds the last one of them to be notified and runs against test4 (no matter which cookbook_file resource updates).
The fix is to use string interpolation to change the name of the execute resources to be unique and to notify based on that unique name:
directory node['sql_scripts_dir'] do
recursive true
end
node['script_runner']['scripts'].each do |script|
cookbook_file "#{node['sql_scripts_dir']}\\#{script['name']}.sql" do
source "#{script['name']}.sql"
action :create
notifies :run, "execute[create #{script['name']} scripts]", :immediately
end
execute "create #{script['name']} scripts" do
command "sqlcmd -S \"#{script['hostname']}\" -i \"#{node['sql_scripts_dir']}\\#{script['name']}.sql\""
action :nothing
end
end
Note that this is a manifestation of the same issues behind the old CHEF-3694 warning message where what would happen is that all the four execute resources would be merged into one resource via "resource cloning" with the properties of the subsequent resource being "last-writer-wins".
In Chef 13 this was changed to remove resource cloning and the warning, and in most circumstances having two resources named the same thing in the resource collection is totally harmless -- until you try to notify one of those resources. The resource notification system should really warn in this situation rather than silently picking the last resource that matches (but between notifications, subscribes, lazy resolution and now unified_mode that code is very complicated and you only want it to be firing under exactly the right conditions).

Why does puppet think my custom fact is a string?

I am trying to create a custom fact I can use as the value for a class parameter in a hiera yaml file.
I am using the openstack/puppet-keystone module and I want to use fernet-keys.
According to the comments in the module I can use this parameter.
# [*fernet_keys*]
# (Optional) Hash of Keystone fernet keys
# If you enable this parameter, make sure enable_fernet_setup is set to True.
# Example of valid value:
# fernet_keys:
# /etc/keystone/fernet-keys/0:
# content: c_aJfy6At9y-toNS9SF1NQMTSkSzQ-OBYeYulTqKsWU=
# /etc/keystone/fernet-keys/1:
# content: zx0hNG7CStxFz5KXZRsf7sE4lju0dLYvXdGDIKGcd7k=
# Puppet will create a file per key in $fernet_key_repository.
# Note: defaults to false so keystone-manage fernet_setup will be executed.
# Otherwise Puppet will manage keys with File resource.
# Defaults to false
So wrote this custom fact ...
[root#puppetmaster modules]# cat keystone_fernet/lib/facter/fernet_keys.rb
Facter.add(:fernet_keys) do
setcode do
fernet_keys = {}
puts ( 'Debug keyrepo is /etc/keystone/fernet-keys' )
Dir.glob('/etc/keystone/fernet-keys/*').each do |fernet_file|
data = File.read(fernet_file)
if data
content = {}
puts ( "Debug Key file #{fernet_file} contains #{data}" )
fernet_keys[fernet_file] = { 'content' => data }
end
end
fernet_keys
end
end
Then in my keystone.yaml file I have this line:
keystone::fernet_keys: '%{::fernet_keys}'
But when I run puppet agent -t on my node I get this error:
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: Error while evaluating a Function Call, "{\"/etc/keystone/fernet-keys/1\"=>{\"content\"=>\"xxxxxxxxxxxxxxxxxxxx=\"}, \"/etc/keystone/fernet-keys/0\"=>{\"content\"=>\"xxxxxxxxxxxxxxxxxxxx=\"}}" is not a Hash. It looks to be a String at /etc/puppetlabs/code/environments/production/modules/keystone/manifests/init.pp:1144:7 on node mgmt-01
I had assumed that I had formatted the hash correctly because facter -p fernet_keys output this on the agent:
{
/etc/keystone/fernet-keys/1 => {
content => "xxxxxxxxxxxxxxxxxxxx="
},
/etc/keystone/fernet-keys/0 => {
content => "xxxxxxxxxxxxxxxxxxxx="
}
}
The code in the keystone module looks like this (with line numbers)
1142
1143 if $fernet_keys {
1144 validate_hash($fernet_keys)
1145 create_resources('file', $fernet_keys, {
1146 'owner' => $keystone_user,
1147 'group' => $keystone_group,
1148 'subscribe' => 'Anchor[keystone::install::end]',
1149 }
1150 )
1151 } else {
Puppet does not necessarily think your fact value is a string -- it might do, if the client is set to stringify facts, but that's actually beside the point. The bottom line is that Hiera interpolation tokens don't work the way you think. Specifically:
Hiera can interpolate values of any of Puppet’s data types, but the
value will be converted to a string.
(Emphasis added.)

How does Chef recipe get/retrieve parameters from databag?

I have been trying to learn Chef and trying to test a small Chef cookbook that would do dcpromo of a Windows 2008 R2 server.
I don't remember exactly where I got the two files originally, but I was able to get it working.
The original dcpromo_unattend.txt.erb file was:
[DCINSTALL]
SafeModeAdminPassword=<%= #admin_password %>
RebootOnCompletion=Yes
ReplicaOrNewDomain=domain
NewDomain=forest
NewDomainDNSName=<%= #domain_name %>
ForestLevel=3
DomainLevel=3
InstallDNS=yes
and the default.rb had this part in it:
template dcpromo_file do
source "dcpromo_unattend.txt.erb"
variables({
:admin_password => '',
:domain_name => ''
})
end
I wasn't quite sure what how to pass in the admin_password and domain_name parameters, so I hard-coded both in the dcpromo_unattend.txt.erb file, and, after some tweaking, was able to make the cookbook work.
Now, I'd like to be able to put the admin_password and domain_name values into a databag, so I tried adding:
begin
dcpromote = Chef::DataBagItem.load(:dcpromote, :main)
rescue
Chef::Log.fatal("Could not find the 'main' item in the 'dcpromote' data bag - Raising fatal error!!")
raise
end
and changed the original template section to:
template dcpromo_file do
source "dcpromo_unattend.txt.erb"
variables({
:admin_password => dcpromote['admin_password'],
:domain_name => dcpromote['domain_name']
})
end
and I created a databag named "dcpromote", but that doesn't seem to be working.
Can someone explain how the original template code is supposed to work, i.e., where is it suppose to be retrieving the admin_password and domain_name parameters from?
Also, can anyone tell me what is wrong with the changes that I made to get this to read the admin_password and domain_name from the "dcpromote" databag?
Thanks,
Jim
EDIT: I guess that I've been staring at this for a few more hours, and, actually, I don't even understand how what I did is working.
What I mean is the erb file I have has the password and domain hard-coded:
[DCINSTALL]
SafeModeAdminPassword=xxxxxxxxx
RebootOnCompletion=Yes
ReplicaOrNewDomain=domain
NewDomain=forest
NewDomainDNSName=WHATEVER.com
ForestLevel=4
DomainLevel=4
InstallDNS=yes
Notice that there is NO reference to admin_password or domain_name in that file.
So, how does this part of the recipe/default.rb even working?
template dcpromo_file do
source "dcpromo_unattend.txt.erb"
variables({
:admin_password => '',
:domain_name => ''
})
end
Can someone explain exactly what this part of the recipe code is doing:
variables({
:admin_password => '',
:domain_name => ''
})
??
Thanks,
Jim
EDIT 2:
Adding entire default.rb after changes suggested by #Draco Ater:
#
# Cookbook Name:: dcpromote
# Recipe:: default
#
# Copyright (c) 2015 The Authors, All Rights Reserved.
#
class ServerHelper
extend ::Windows::Helper
class << self
def dism
##dism ||= locate_sysnative_cmd("dism.exe")
end
def powershell
##powershell ||= locate_sysnative_cmd('WindowsPowershell\v1.0\powershell.exe')
end
def feature_installed?(feature)
cmd = Mixlib::ShellOut.new("#{dism} /online /Get-Features", {:returns => [0,42,127]}).run_command
!!(cmd.stderr.empty? && (cmd.stdout =~ /^Feature Name : #{feature}.?$\n^State : Enabled.?$/i))
end
end
end
windows_reboot 60 do
action :nothing
end
#
# Following snippet from: https://supermarket.chef.io/cookbooks/ad
# This snippet checks for presence of a databag named "dcpromote" and for presence
# of an item in the databag named "main". If that item is not present, then
# this snippet logs a fatal error.
begin
dcpromote = Chef::DataBagItem.load('dcpromote', 'main')
rescue
Chef::Log.fatal("Could not find the 'main' item in the 'dcpromote' data bag - Raising fatal error!!")
raise
end
directory Chef::Config[:file_cache_path]
dcpromo_file = File.join(Chef::Config[:file_cache_path], 'dcpromo_unattend.txt')
#cert_script = File.join(Chef::Config[:file_cache_path], 'setupca.vbs')
# Available from e.g. http://blogs.technet.com/b/pki/archive/2009/09/18/automated-ca-installs-using-vb-script-on-windows-server-2008-and-2008r2.aspx
template dcpromo_file do
source "dcpromo_unattend.txt.erb"
variables(
:admin_password => dcpromote['admin_password'],
:domain_name => dcpromote['domain_name']
)
end
powershell_script "run_dcpromo" do
code "dcpromo /unattend:#{dcpromo_file}"
#notifies :request, 'windows_reboot[60]'
not_if { ServerHelper.feature_installed? 'DirectoryServices-DomainController' }
end
windows_feature 'DirectoryServices-DomainController' do
action :install
#notifies :request, 'windows_reboot[60]'
end
This cookbook/recipe is STILL not working with the databag.
To clarify: When I run it with the earlier code with the hard-coded setting of admin_password and domain_name, it works.
However, if I try the code that uses the databag it doesn't work. When I run it with the databag:
1) [This is strange]: If I look at the "unattended" txt file during the run, it looks like it is populated, but then at the end, the password item is set to nothing, i.e., the unattended text file changes during the run.
2) In the end when the Powershell is run, it looks like it gets an error 32.
Here's the console output:
PS C:\Users\Administrator> chef-client -o dcpromote_usedatabag
Starting Chef Client, version 12.3.0
[2015-06-14T07:24:47-07:00] INFO: *** Chef 12.3.0 ***
[2015-06-14T07:24:47-07:00] INFO: Chef-client pid: 260
[2015-06-14T07:25:04-07:00] WARN: Run List override has been provided.
[2015-06-14T07:25:04-07:00] WARN: Original Run List: []
[2015-06-14T07:25:04-07:00] WARN: Overridden Run List: [recipe[dcpromote_usedatabag]]
[2015-06-14T07:25:04-07:00] INFO: Run List is [recipe[dcpromote_usedatabag]]
[2015-06-14T07:25:04-07:00] INFO: Run List expands to [dcpromote_usedatabag]
[2015-06-14T07:25:04-07:00] INFO: Starting Chef Run for node8
[2015-06-14T07:25:04-07:00] INFO: Running start handlers
[2015-06-14T07:25:04-07:00] INFO: Start handlers complete.
[2015-06-14T07:25:04-07:00] INFO: HTTP Request Returned 404 Not Found:
resolving cookbooks for run list: ["dcpromote_usedatabag"]
[2015-06-14T07:25:04-07:00] INFO: Loading cookbooks [dcpromote_usedatabag#0.1.1, windows#1.37.0, che
[2015-06-14T07:25:04-07:00] INFO: Skipping removal of obsoleted cookbooks from the cache
Synchronizing Cookbooks:
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/recipes/default.rb
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/templates/default/d
erb in the cache.
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/Berksfile in the ca
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/.kitchen.yml in the
- windows
- chef_handler
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/chefignore in the c
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/metadata.rb in the
[2015-06-14T07:25:04-07:00] INFO: Storing updated cookbooks/dcpromote_usedatabag/README.md in the ca
- dcpromote_usedatabag
Compiling Cookbooks...
[2015-06-14T07:25:04-07:00] INFO: +++++++++++++++++++++++++++ HI ++++++++++++++++++++++++++++
[2015-06-14T07:25:04-07:00] INFO: +++++++++++++++++++++++++++ HI ++++++++++++++++++++++++++++
[2015-06-14T07:25:04-07:00] INFO: +++++++++++++++++++++++++++ In template +++++++++++++++++++++++++
[2015-06-14T07:25:04-07:00] INFO: +++++++++++++++++++++++++++ In template +++++++++++++++++++++++++
[2015-06-14T07:25:04-07:00] INFO: ++++ xoutput = [123]
Converging 5 resources
Recipe: dcpromote_usedatabag::default
* windows_reboot[60] action nothing[2015-06-14T07:25:04-07:00] INFO: Processing windows_reboot[60]
romote_usedatabag::default line 28)
(skipped due to action :nothing)
* directory[c:/chef/cache] action create[2015-06-14T07:25:04-07:00] INFO: Processing directory[c:/
reate (dcpromote_usedatabag::default line 47)
(up to date)
* template[c:/chef/cache/dcpromo_unattend.txt] action create[2015-06-14T07:25:04-07:00] INFO: Proc
hef/cache/dcpromo_unattend.txt] action create (dcpromote_usedatabag::default line 52)
[2015-06-14T07:25:04-07:00] INFO: template[c:/chef/cache/dcpromo_unattend.txt] created file c:/chef/
nd.txt
- create new file c:/chef/cache/dcpromo_unattend.txt[2015-06-14T07:25:04-07:00] INFO: template[c
_unattend.txt] updated file contents c:/chef/cache/dcpromo_unattend.txt
- update content in file c:/chef/cache/dcpromo_unattend.txt from none to 798057
--- c:/chef/cache/dcpromo_unattend.txt 2015-06-14 07:25:04.000000000 -0700
+++ C:/Users/ADMINI~1/AppData/Local/Temp/chef-rendered-template20150614-260-1cvaiw 2015-06-14 0
700
## -1 +1,10 ##
+[DCINSTALL]
+SafeModeAdminPassword=P#ssw0rd$123
+RebootOnCompletion=Yes
+ReplicaOrNewDomain=domain
+NewDomain=forest
+NewDomainDNSName=whateverisforever123.com
+ForestLevel=4
+DomainLevel=4
+InstallDNS=yes
* powershell_script[run_dcpromo] action run[2015-06-14T07:25:04-07:00] INFO: Processing powershell
action run (dcpromote_usedatabag::default line 68)
================================================================================
Error executing action `run` on resource 'powershell_script[run_dcpromo]'
================================================================================
Mixlib::ShellOut::ShellCommandFailed
------------------------------------
Expected process to exit with [0], but received '32'
---- Begin output of "powershell.exe" -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrest
None -File "C:/Users/ADMINI~1/AppData/Local/Temp/chef-script20150614-260-dfo5yi.ps1" ----
STDOUT:
STDERR:
---- End output of "powershell.exe" -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestri
ne -File "C:/Users/ADMINI~1/AppData/Local/Temp/chef-script20150614-260-dfo5yi.ps1" ----
Ran "powershell.exe" -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputForm
ers/ADMINI~1/AppData/Local/Temp/chef-script20150614-260-dfo5yi.ps1" returned 32
Resource Declaration:
---------------------
# In c:/chef/cache/cookbooks/dcpromote_usedatabag/recipes/default.rb
68: powershell_script "run_dcpromo" do
69: code "dcpromo /unattend:#{dcpromo_file}"
70: #notifies :request, 'windows_reboot[60]'
71: not_if { ServerHelper.feature_installed? 'DirectoryServices-DomainController' }
72: end
73:
Compiled Resource:
------------------
# Declared in c:/chef/cache/cookbooks/dcpromote_usedatabag/recipes/default.rb:68:in `from_file'
powershell_script("run_dcpromo") do
action "run"
retries 0
retry_delay 2
default_guard_interpreter :powershell_script
command "run_dcpromo"
backup 5
returns 0
code "dcpromo /unattend:c:/chef/cache/dcpromo_unattend.txt"
interpreter "powershell.exe"
declared_type :powershell_script
cookbook_name "dcpromote_usedatabag"
recipe_name "default"
not_if { #code block }
end
[2015-06-14T07:26:22-07:00] INFO: Running queued delayed notifications before re-raising exception
Running handlers:
[2015-06-14T07:26:22-07:00] ERROR: Running exception handlers
Running handlers complete
[2015-06-14T07:26:22-07:00] ERROR: Exception handlers complete
[2015-06-14T07:26:22-07:00] FATAL: Stacktrace dumped to c:/chef/cache/chef-stacktrace.out
Chef Client failed. 1 resources updated in 98.15625 seconds
[2015-06-14T07:26:22-07:00] FATAL: Mixlib::ShellOut::ShellCommandFailed: powershell_script[run_dcpro
tabag::default line 68) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit
ved '32'
---- Begin output of "powershell.exe" -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestrict
-File "C:/Users/ADMINI~1/AppData/Local/Temp/chef-script20150614-260-dfo5yi.ps1" ----
STDOUT:
STDERR:
---- End output of "powershell.exe" -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted
File "C:/Users/ADMINI~1/AppData/Local/Temp/chef-script20150614-260-dfo5yi.ps1" ----
Ran "powershell.exe" -NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputFormat N
ADMINI~1/AppData/Local/Temp/chef-script20150614-260-dfo5yi.ps1" returned 32
PS C:\Users\Administrator>
And here's the unattended txt file at the end:
[DCINSTALL]
SafeModeAdminPassword=
RebootOnCompletion=Yes
ReplicaOrNewDomain=domain
NewDomain=forest
NewDomainDNSName=whateverisforever123.com
ForestLevel=4
DomainLevel=4
InstallDNS=yes
Why is the unattended txt file changing twice during the run (and why is the password value disappearing)?
Thanks,
Jim
EDIT 3:
For the record, I was able to get this working by adding an additional parameter to the template file for setting the netbios name:
[DCINSTALL]
RebootOnCompletion=Yes
ReplicaOrNewDomain=domain
NewDomain=forest
SafeModeAdminPassword=<%= #admin_password %>
NewDomainDNSName=<%= #domain_name %>
ForestLevel=4
DomainLevel=4
InstallDNS=yes
DomainNetbiosName=<%= #domain_netbios_name %>
and then modified the default.rb to set that parameter:
template dcpromo_file do
source "dcpromo_unattend.txt.erb"
variables(
:admin_password => dcpromote['admin_password'],
:domain_netbios_name => dcpromote['domain_netbios_name'],
:domain_name => dcpromote['domain_name']
)
Jim
Let's start with the template file itself.
[DCINSTALL]
SafeModeAdminPassword=<%= #admin_password %>
RebootOnCompletion=Yes
ReplicaOrNewDomain=domain
NewDomain=forest
NewDomainDNSName=<%= #domain_name %>
ForestLevel=3
DomainLevel=3
InstallDNS=yes
The code inside <% %> is ruby code. Things that start with # inside the <% %> are variables. The = is a shorthand for printing the value. So the template uses 2 variables to set the values, by just printing them out.
Where do the variables come from? Exactly from this code in recipe ({ and } are not necessary here):
variables(
:admin_password => '',
:domain_name => ''
)
Currently they are initialized by empty strings, but if you put something else there in the recipe, it will be changed in template too. It will not break, if you pass some variables that are not used in the template, it will just be the redundant code.
For now you can put your password and domain name there like that and get this working (producing the right configuration file on target machine)
variables(
:admin_password => 'my_pass',
:domain_name => 'localhost'
)
Now we want to move the values to the data bag. Create a 'dcpromote' databag with 'main' data bag item.
knife data bag create dcpromote main
and edit the json file. In the end you should have something like that:
{
"id": "main", # <= data bag item name
"admin_password": "my_pass",
"domain_name": "localhost"
}
Then in the recipe you read the data bag into the variable (Try using strings, not symbols, as data bag and item name):
begin
dcpromote = Chef::DataBagItem.load( 'dcpromote', 'main' )
rescue
Chef::Log.fatal("Could not find the 'main' item in the 'dcpromote' data bag - Raising fatal error!!")
raise
end
and use it when creating configuration file:
variables(
:admin_password => dcpromote['admin_password'],
:domain_name => dcpromote['domain_name']
)

Problems with chef recipe

Sorry about my English.
Here is a ./recipes/default.rb
node['client-name'].each do |crontab|
item = data_bag_item('bag_name', "#{crontab}")
node.default[:client_timezone] = "#{item['timezone']}"
node.default[:client_name] = "#{crontab}"
template "crontab" do
path "/etc/cron.d/#{deploy}"
source "default.erb"
owner "root"
group "root"
mode "0644"
end
end
The ./attributes/default.rb looks like this:
default['version'] = "1.0.0"
default['client-name'] = ['company_1','company_2']
The templates/crontab.erb looks like this:
30 04 * * * java -Duser.timezone=<%= node[:timezone] %> -jar /var/www/app-<%= node[:version] %>.jar /var/www/<%= node[:client_name] %>/config/spring/job.xml
My recipe puts two similar crontab files (company_1 and company_2) to /etc/cron.d/, but only for the last one attributes' value (company_2). Can you please tell me, where am i wrong?
You need to use the variables section of the template resource to assign the client_name and the timezone explicitly. The recipe might look like this:
node['client-name'].each do |client_name|
item = data_bag_item('bag_name', "#{client_name}")
template "crontab" do
path "/etc/cron.d/#{deploy}"
source "default.erb"
owner "root"
group "root"
mode "0644"
variables ({
:client_name => item['client_name'], # Don't you have this already?
:client_timezone => item['client_timezone']
})
end
end
Your crontab.erb should look like this:
30 04 * * * java -Duser.timezone=<%= #client_timezone %> -jar /var/www/app-<%= node[:version] %>.jar /var/www/<%= #client_name %>/config/spring/job.xml

Chef Recipe to configure multiple mpd instances

I try to create a chef cookbook to launch multiple mpd instances in my vagrant virtual box (using chef-solo).
I want to configure each instance in my Vagrantfile like this:
mpd: {
channels: {
mix: {
name: 'mpd_mix',
bind: '0.0.0.0',
socket: '/home/vagrant/.mpd/socket/mix',
port: '6600'
},
tech: {
name: 'mpd_tech',
bind: '0.0.0.0',
socket: '/home/vagrant/.mpd/socket/tech',
port: '6601'
}
}
}
So the recipe should take these settings and loop through them (creating an mpd instance for each channel).
This is what I currently have as a recipe:
package "mpd"
node.normal[:mpd][:channels].each_value do |channel|
# create socket
file channel[:socket] do
action :touch
end
# trying to set the attributes for the config file and the service
node.set[:mpd][:port] = channel[:port]
node.set[:mpd][:db_file] = "/var/lib/mpd/tag_cache_" + channel[:name]
node.set[:mpd][:bind_2] = channel[:socket]
node.set[:mpd][:icecast_mountpoint] = "/" + channel[:name] + ".mp3"
node.set[:mpd][:channel_name] = channel[:name]
# create service
service channel[:name] do
service_name "mpd" # linux service command
action :enable
end
# create the corresponding config file
config_filename = "/etc/" + channel[:name] + ".conf"
template config_filename do
source "mpd.conf.erb"
mode "0644"
notifies :restart, resources(:service => channel[:name])
end
end
I have several Problems with this:
Ist does not create a system service for each mpd instance, so I can do sudo service mpd_mix start. Why?
It does not use the /etc/mpd_mix.conf config file when launching mpd, because it still calls /etc/init.d/mpd start which uses /etc/mpd.conf. How can I change that, so it uses the correct config file for each mpd instance?
Adjusting the attributes for the creation of the config files does not work as expected (see the node.set part in the code above). Both config files, /etc/mpd_tech.conf and /etc/mpd_mix.conf use the tech channel attributes. Looks like the mix settings get overwritten somehow? How can I fix that?
I'd really appreciate some help on this as I am quite new to chef cookbooks.
I figured out how to do it. Here is the relevant code part:
node[:mpd][:channels].each_value do |channel|
# create socket
file channel[:socket] do
action :touch
end
# create init file
init_filename = "/etc/init.d/" + channel[:name]
template init_filename do
variables :channel => channel
source "mpd.init.erb"
mode "0755"
end
# create service
service channel[:name] do
service_name channel[:name] # linux service command
action :enable
end
# create config file
config_filename = "/etc/" + channel[:name] + ".conf"
template config_filename do
variables :channel => channel
source "mpd.conf.erb"
mode "0644"
notifies :restart, resources(:service => channel[:name])
end
end
If you want to take a closer look, take a look at the complete cookbook repository on github: https://github.com/i42n/chef-cookbook-mpd/blob/master/recipes/default.rb

Resources