Chef - Ruby - ArgumentsError expected 0 - ruby

I'm trying to write a cookbook in Chef (very new) and I get the following error I cannot wrap my head around.
template node '/etc/selinux/config' do
source "config.erb"
mode "0644"
variables(
:selinux_state => node['selinux']['selinux-state'],
:selinux_type => node['selinux']['selinux-type']
)
owner duser
group dgroup
action :create
ignore_failure true
end
FATAL: ArgumentError: wrong number of arguments (given 1, expected 0)
I checked the documentation and as far as I can tell I am following the correct syntax.
Could anyone please enlighten me where the error is?

You have an extra node in the resource declaration. Change:
template node '/etc/selinux/config' do
to
template '/etc/selinux/config' do

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).

To get IP addres of the specific host machine in rub

I want to find the IP address of other system. For example, I am executing my code from server wevrs1234 and I want the IP address of server apvrs1234 and store it in variable. Please help me to get this.
ip = IPSocket.getaddress(Socket.gethostname)
is the code I have so far.
AS per suggestion i have made this code but getting error. Please find my code
publish_vm = node['aem_dispatcher_cookbook']['publish'].to_s
nodes = search(:node, 'hostname:publish_vm')
node.default['aem_dispatcher_cookbook']['ip_address'] = 'nodes.first['ipaddress']'
template node['aem_dispatcher_cookbook']['owner']['home'] + '/conf.d/publish_farm.any' do
source 'publish_farm.any.erb'
owner node['aem_dispatcher_cookbook']['owner']['user']
group node['aem_dispatcher_cookbook']['owner']['group']
mode '0755'
variables(
publish_host: node['aem_dispatcher_cookbook']['publish'],
publish_port: node['aem_dispatcher_cookbook']['publish_port'],
ip_addr: node['aem_dispatcher_cookbook']['ip_address']
)
end
Error
[2020-05-20T06:09:52-05:00] DEBUG: Node wevrd64501.uhc.com loading cookbook aem_dispatcher_cookbook's attribute file /root/.chef/local-mode-cache/cache/cookbooks/aem_dispatcher_cookbook/attributes/default.rb
================================================================================
Recipe Compile Error in /root/.chef/local-mode-cache/cache/cookbooks/aem_dispatcher_cookbook/recipes/default.rb
================================================================================
SyntaxError
-----------
/root/.chef/local-mode-cache/cache/cookbooks/aem_dispatcher_cookbook/recipes/default.rb:333: syntax error, unexpected tIDENTIFIER, expecting keyword_end
...ess'] = 'nodes.first['ipaddress']'
... ^~~~~~~~~
System Info:
You tagged the question with [chef] and [chef-recipe], so I understand you are trying to get another machine's IP address inside recipe. If that another machine is also registered with Chef Server, the easiest would be search. You can search for any machine registered on the Chef Server by some attribute, in your case - hostname.
nodes = search(:node, 'hostname:<another_vm_hostname>')
p nodes.first['ipaddress']
Update:
You have an error in your 3rd line. Don't surround nodes.first['ipaddess'] with quotes.
node.default['aem_dispatcher_cookbook']['ip_address'] = nodes.first['ipaddress']
publish_vm = node['aem_dispatcher_cookbook']['publish'].to_s
ruby_block 'get_ip_from_publish' do
block do
Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
command1 = "nslookup #{publish_vm} |grep '^Address' | awk '{print $2}'| tail -1"
command_out = shell_out(command1)
node.run_state['master_ip'] = command_out.stdout
end
action :run
end
This piece of code helped me to get ip address of desired host machine

How to use local variable of whitespace array in chef template resource

I am trying to use whitespace arrays in chef template, like below and when I run the chef-client to execute the recipe getting an error saying: option variables must be a kind of [Hash]! below is recipe file
abc = node['abc']
def1 = node['def']
abc_sit = abc['sit']
def_sit = def1['sit']
%w{abc_sit def_sit}.each do | client |
template "/etc/#{client}.sh" do
source 'tunnel.erb'
owner 'root'
group 'root'
variables ("#{client}") --> At this line I am getting error
end
end
The error I am getting when I run the chef-client:
option variables must be a kind of [Hash]! You passed "abc_sit"
As it says, you have to pass in a Hash. Perhaps something like variables myclient: client and then <%= #myclient %> in the template.

Setting Cron using chef

I have a question about ruby/chef, I am creating a recipe that will setup a cron job once we chef-client the node and I am getting a syntax error when I run my kitchen test
The following block of code is part of my recipe
action node["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["enabled"] = ? :create : :delete
minute node["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["minute"]
hour node["hadoop_temp"]["scripts"]["cron"]["clean_teamp"]["hour"]
day node["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["day"]
month node["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["month"]
weekday node["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["weekday"]
the following block is part of my attributes.
#Run the cron every day at 12AM cleans /temp
default["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["enabled"] = false
default["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["minute"] = "0"
default["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["hour"] = "0"
default["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["day"] = "*"
default["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["month"] = "*"
default["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["weekday"] = "*"
when I run my kitchen test I am getting the following error.
SyntaxError
-----------
/tmp/kitchen/cache/cookbooks/hadoop_temp/recipes/clean_temp.rb:25: syntax error, unexpected '?'
..."hadoop_temp"]["enabled"] = ? :create : :delete
I do not understand boolean 100% in ruby what I want to accomplish is if the entry exist create but if in the future I want to delete I just have to switch the attribute to true.
You could learn about the ternary operator in rubylearn about the ternary operator in ruby
I did took the = sign out of the recipe action. now it looks like:
action node["hadoop_temp"]["scripts"]["cron"]["clean_temp"]["enabled"] ? :create : :delete
Thank you #StephenKing the test passed

dynamic usage of attribute in recipe

I am trying to increment the value and use in another resource dynamically in recipe but still failing to do that.
Chef::Log.info("I am in #{cookbook_name}::#{recipe_name} and current disk count #{node[:oracle][:asm][:test]}")
bash "beforeTest" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
ruby_block "test current disk count" do
block do
node.set[:oracle][:asm][:test] = "#{node[:oracle][:asm][:test]}".to_i+1
end
end
bash "test" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
However I'm still getting the error bellow:
NoMethodError ------------- undefined method echo' for Chef::Resource::Bash
Cookbook Trace: ---------------
/var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb:3:in block (2 levels) in from_file'
Resource Declaration: ---------------------
# In /var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb
1: bash "beforeTest" do
2: code lazy{
3: echo "#{node[:oracle][:asm][:test]}"
4: }
5: end
Please can you help how lazy should be used in bash? If not lazy is there any other option?
bash "beforeTest" do
code lazy { "echo #{node[:oracle][:asm][:test]}" }
end
You should quote the command for the interpolation to work; if not, ruby would search for an echo command, which is unknown in ruby context (thus the error you get in log).
Warning: lazy has to be for the whole resource attribute; something like this WON'T work:
bash "beforeTest" do
code "echo node asm test is: #{lazy { node[:oracle][:asm][:test]} }"
end
The lazy evaluation takes a block of ruby code, as decribed here
You may have a better result with the log resource like this:
log "print before" do
message lazy { "node asm test is #{node[:oracle][:asm][:test]}" }
end
I've been drilling my head solving this problem until I came up with lambda expressions. But yet just using lambda didn't help me at all. So I thought of using both lambda and lazy evaluation. Though lambda is already lazy loading, when compiling chef recipe's, the resource where you call the lambda expression is still being evaluated. So to prevent it to being evaluated (somehow), I've put it inside a lazy evaluation string.
The lambda expression
app_version = lambda{`cat version`}
then the resource block
file 'tmp/validate.version' do
user 'user'
group 'user_group'
content lazy { app_version.call }
mode '0755'
end
Hope this can help others too :) or if you have some better solution please do let me know :)

Resources