Ruby (Chef) Hash Array - Name is a Required Property - ruby

I'm trying to create a recipe to deploy Remote Desktop Services to Windows Servers, everything is working as expected apart from the Application deployment resource I created - it's a simple resource but I'm having a lot of issues passing the applications to be deployed as a hash array.
attributes\default.rb
default['app']['app_options'] = [
{
connection_broker: 'serv-01',
options: {
collectionname: 'Terminal Services',
alias: 'Acrobat',
displayname: 'Adobe Acrobat',
filepath: 'C:\\Program Files (x86)\\Adobe\\Acrobat 11.0\\Acrobat\\Acrobat.exe',
filevirtualpath: 'C:\\Program Files (x86)\\Adobe\\Acrobat 11.0\\Acrobat\\Acrobat.exe',
commandlinesetting: 'DoNotAllow',
iconindex: '0',
iconpath: '\\\\serv-01\\C$\\Program Files (x86)\\Adobe\\Acrobat 11.0\\Acrobat\\Acrobat.exe',
usergroups: ['domain\\group'],
showinwebaccess: '1'
}
},
{
connection_broker: 'serv-01',
options: {
collectionname: 'Terminal Services',
alias: 'Accounts',
displayname: 'Accounts',
foldername: 'Accounts',
filepath: 'D:\\Accounts\\Accounts.bat',
filevirtualpath: 'D:\\Accounts\\Accounts.bat',
commandlinesetting: 'DoNotAllow',
iconindex: '0',
iconpath: 'C:\\Windows\\System32\\cmd.exe',
usergroups: ['domain\\group'],
showinwebaccess: '1'
}
}
]
recipes\remote_desktop.rb
rdapps = node.read('app', 'app_options') || []
rdapps.each do |app|
remote_desktop_apps app['options']['alias'] do
action :create
connection_broker app['connection_broker']
app_options app['options']
end
end
resources\remote_desktop_apps.rb
resource_name :remote_desktop_apps
property :connection_broker, String,
desired_state: false
property :app_options, [String, Hash, Array],
desired_state: false
action :create do
app_options.each do |k,v|
script << "New-RDRemoteApp -ConnectionBroker "#{connection_broker}" {-#{k.to_s.capitalize} #{v}}.join(' ')}"
end
end
Edit
Thanks to #seshadri_c for the help past the first hurdle, I've hit another issue which seems related to the attributes.
Here is the output of a kitchen converge
================================================================================
Error executing action `create` on resource 'remote_desktop_apps[Acrobat]'
================================================================================
Chef::Exceptions::ValidationFailed
----------------------------------
name is a required property
Resource Declaration:
---------------------
# In C:/Users/ADMINI~1/AppData/Local/Temp/kitchen/cache/cookbooks/windows_/recipes/remote_desktop.rb
76: remote_desktop_apps app['options']['alias'] do
77: action :create
78: connection_broker app['connection_broker']
79: app_options app['options']
80: end
81: end
Compiled Resource:
------------------
# Declared in C:/Users/ADMINI~1/AppData/Local/Temp/kitchen/cache/cookbooks/windows_/recipes/remote_desktop.rb:76:in `block in from_file'
remote_desktop_apps("Acrobat") do
action [:create]
default_guard_interpreter :default
declared_type :remote_desktop_apps
cookbook_name "windows_"
recipe_name "remote_desktop"
connection_broker "serv-01"
app_options {"collectionname"=>"Terminal Services", "alias"=>"Acrobat", "displayname"=>"Adobe Acrobat", "filepath"=>"C:\\Program Files (x86)\\Adobe\\Acrobat 11.0\\Acrobat\\Acrobat.exe", "filevirtualpath"=>"C:\\Program Files (x86)\\Adobe\\Acrobat 11.0\\Acrobat\\Acrobat.exe", "commandlinesetting"=>"DoNotAllow", "iconindex"=>"0", "iconpath"=>"\\\\serv-01\\C$\\Program Files (x86)\\Adobe\\Acrobat 11.0\\Acrobat\\Acrobat.exe", "usergroups"=>["domain\\group"], "showinwebaccess"=>"1"}
end
Then there's this message at the end of the run:
FATAL: Chef::Exceptions::ValidationFailed: remote_desktop_apps[Acrobat] (windows_::remote_desktop line 76) had an error: Chef::Exceptions::ValidationFailed: name is a required property
$$$$$$ Exception calling "Read" with "3" argument(s): "Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection."
At line:100 char:11
$$$$$$ + if ($fs.Read($bytes, 0, $fs.Length) -gt 0) {
$$$$$$ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException

Related

CheckMysqlReplicationStatus CRITICAL: undefined method `encoding' for nil:NilClass

sensu CheckMysqlReplication.rb on db servers returns undefined method `encoding' for nil:NilClass when executed in mysql 8.0.13-4 with latin1 as the default character set name. Prior to this error, the CheckMysqlReplication.rb worked perfectly ok on mysql 5.0 with UTF-8 as the default charset.
I have gleaned the code but I am unable to pinpoint where the problem might be from.
here's the check below:
require 'sensu-plugin/check/cli'
require 'mysql'
require 'inifile'
class CheckMysqlReplicationStatus < Sensu::Plugin::Check::CLI
option :host,
short: '-h',
long: '--host=VALUE',
description: 'Database host'
option :port,
short: '-P',
long: '--port=VALUE',
description: 'Database port',
default: 3306,
# #YELLOW
proc: lambda { |s| s.to_i } # rubocop:disable Lambda
option :socket,
short: '-s SOCKET',
long: '--socket SOCKET',
description: 'Socket to use'
option :user,
short: '-u',
long: '--username=VALUE',
description: 'Database username'
option :pass,
short: '-p',
long: '--password=VALUE',
description: 'Database password'
option :master_connection,
short: '-m',
long: '--master-connection=VALUE',
description: 'Replication master connection name'
option :ini,
short: '-i',
long: '--ini VALUE',
description: 'My.cnf ini file'
option :ini_section,
description: 'Section in my.cnf ini file',
long: '--ini-section VALUE',
default: 'client'
option :warn,
short: '-w',
long: '--warning=VALUE',
description: 'Warning threshold for replication lag',
default: 900,
# #YELLOW
proc: lambda { |s| s.to_i } # rubocop:disable Lambda
option :crit,
short: '-c',
long: '--critical=VALUE',
description: 'Critical threshold for replication lag',
default: 1800,
# #YELLOW
proc: lambda { |s| s.to_i } # rubocop:disable Lambda
def detect_replication_status?(row)
%w[
Slave_IO_State
Slave_IO_Running
Slave_SQL_Running
Last_IO_Error
Last_SQL_Error
Seconds_Behind_Master
].all? { |key| row.key? key }
end
def slave_running?(row)
%w[
Slave_IO_Running
Slave_SQL_Running
].all? { |key| row[key] =~ /Yes/ }
end
def run
if config[:ini]
ini = IniFile.load(config[:ini])
section = ini[config[:ini_section]]
db_user = section['user']
db_pass = section['password']
else
db_user = config[:user]
db_pass = config[:pass]
end
db_host = config[:host]
db_conn = config[:master_connection]
if [db_host, db_user, db_pass].any?(&:nil?)
unknown 'Must specify host, user, password'
end
begin
db = Mysql.new(db_host, db_user, db_pass, nil, config[:port], config[:socket])
results = if db_conn.nil?
db.query 'SHOW SLAVE STATUS'
else
db.query "SHOW SLAVE '#{db_conn}' STATUS"
end
unless results.nil?
results.each_hash do |row|
warn "couldn't detect replication status" unless detect_replication_status?(row)
slave_running = slave_running?(row)
output = if db_conn.nil?
'Slave not running!'
else
"Slave on master connection #{db_conn} not running!"
end
output += ' STATES:'
output += " Slave_IO_Running=#{row['Slave_IO_Running']}"
output += ", Slave_SQL_Running=#{row['Slave_SQL_Running']}"
output += ", LAST ERROR: #{row['Last_SQL_Error']}"
critical output unless slave_running
replication_delay = row['Seconds_Behind_Master'].to_i
message = "replication delayed by #{replication_delay}"
if replication_delay > config[:warn] &&
replication_delay <= config[:crit]
warning message
elsif replication_delay >= config[:crit]
critical message
elsif db_conn.nil?
ok "slave running: #{slave_running}, #{message}"
else
ok "master connection: #{db_conn}, slave running: #{slave_running}, #{message}"
end
end
ok 'show slave status was nil. This server is not a slave.'
end
rescue Mysql::Error => e
errstr = "Error code: #{e.errno} Error message: #{e.error}"
critical "#{errstr} SQLSTATE: #{e.sqlstate}" if e.respond_to?('sqlstate')
rescue StandardError => e
critical e
ensure
db.close if db
end
end
end

chef template gives No such file or directory # rb_sysopen Errno::ENOENT

I have chef recipe with this block :
if ( platform === 'suse' )
repo_name="some_repo"
template '/etc/zypp/repos.d/some_repo' do
source 'some_repo.rpm.repo.erb'
variables( :os => "#{os}", :distro => "#{distro}", :repo_name => "#{repo_name}" )
owner "root"
group "root"
mode '644'
end
end
I understand the template should by default create the file.
But it doesn't create the file and it gives the error No such file or directory.
The template some_repo.rpm.repo.erb itself looks like this:
[<%= #repo_name %>]
name=<%= #repo_name %>
baseurl=http://BLA.com//repos/<%= #os %>/<%= #distro %>
enabled=1
gpgcheck=0
sslverify=0
proxy=_none_
What am I doing wrong ?
EDIT :full error logs
Recipe Compile Error in /tmp/ldt_chef_run/local-mode-cache/cache/cookbooks/recipes/default.rb
================================================================================
Errno::ENOENT
-------------
No such file or directory # rb_sysopen - /etc/zypp/repos.d/some_repo
Cookbook Trace:
---------------
/tmp/ldt_chef_run/local-mode-cache/cache/cookbooks/recipes/default.rb:106:in `read'
/tmp/ldt_chef_run/local-mode-cache/cache/cookbooks/recipes/default.rb:106:in `block in from_file'
/tmp/ldt_chef_run/local-mode-cache/cache/cookbooks/recipes/default.rb:104:in `from_file'
Relevant File Content:
----------------------
/tmp/ldt_chef_run/local-mode-cache/cache/cookbooks/zabbix_agent/recipes/default.rb:
99: owner 'root'
100: group 'root'
101: mode '0755'
102: action :create
103: end
104: file '/tmp/some.repos.d/some.repo' do
105: mode '0644'
106>> content IO.read(node['somepackage'][node['platform']]['repo_source'])
107: action :create
108: end
109: end
110:
111: ######### Install package ###########
112: #package 'somepackage' do
113: # action :install
114: #end
115: node['somepackage'][node['platform']]['packages'].each do |pkg|
System Info:
------------
chef_version=14.2.0
platform=redhat
platform_version=7.5
ruby=ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
program_name=/bin/chef-solo
executable=/opt/chef/bin/chef-solo
Running handlers:
[2019-02-10T11:32:27+02:00] ERROR: Running exception handlers
[2019-02-10T11:32:27+02:00] ERROR: Running exception handlers
Running handlers complete
[2019-02-10T11:32:27+02:00] ERROR: Exception handlers complete
[2019-02-10T11:32:27+02:00] ERROR: Exception handlers complete
Chef Client failed. 0 resources updated in 11 seconds
[2019-02-10T11:32:27+02:00] FATAL: Stacktrace dumped to /tmp/ldt_chef_run/local-mode-cache/cache/chef-stacktrace.out
[2019-02-10T11:32:27+02:00] FATAL: Stacktrace dumped to /tmp/ldt_chef_run/local-mode-cache/cache/chef-stacktrace.out
[2019-02-10T11:32:27+02:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2019-02-10T11:32:27+02:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2019-02-10T11:32:27+02:00] FATAL: Errno::ENOENT: No such file or directory # rb_sysopen - /etc/zypp/repos.d/some_repo
[2019-02-10T11:32:27+02:00] FATAL: Errno::ENOENT: No such file or directory # rb_sysopen - /etc/zypp/repos.d/some_repo
EDIT2 :
I know the issue is related to a block coming after the
template i have this :
if %w(redhat suse sles).include?(node['platform'])
directory '/tmp/some.repos.d' do
owner 'root'
group 'root'
mode '0755'
action :create
end
file '/tmp/some.repos.d/some.repo' do
mode '0644'
content IO.read(node['somepakage'][node['platform']]['repo_source'])
action :create
end
end
I wanted to copy the content of the file that the template created:
"/etc/zypp/repos.d/some_repo"
to /tmp/some.repos.d/some.repo
it seems like this block is creating the error with the template block
which make the template not creating the new file, as a resulted the
content IO.read block gets an error as the file was not created at the template stage.
this error only happed if i delete the file :
/etc/zypp/repos.d/some_repo
for testing to see if cookbook will re-create it.
if this file exists no errors.
So, why "content IO.read" cancels "template" ?
This is the workaround :
Addings this line to the start of all blockes :
if %w(redhat suse sles ubuntu debian).include?(node['platform'])
directory '/tmp/some.repos.d' do
owner 'root'
group 'root'
mode '0755'
action :create
end
end
Then just duplicate the "template" block , for the other file :
if ( platform === 'suse' )
repo_name="some_repo"
template '/etc/zypp/repos.d/some.repo' do
source 'some.rpm.repo.erb'
variables( :os => "#{os}", :distro => "#{distro}", :repo_name => "#{repo_name}" )
owner "root"
group "root"
mode '644'
end
template '/tmp/some.repos.d/some.repo' do
source 'some.rpm.repo.erb'
variables( :os => "#{os}", :distro => "#{distro}", :repo_name => "#{repo_name}" )
owner "root"
group "root"
mode '644'
end
end

Use Regex in registry_data_exists Resource in Chef Recipe

I am creating a chef recipe and trying to create/update Registry key using registry_key resource. How I can use regex to validate the presence of the registry key and only update if it is necessary
registry_key'HKLM\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon' do
values [{
name: 'SCRemoveOption',
type: :string,
data: '1', }]
# recursive true
action :create
not_if { registry_data_exists?('HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon',{ name: 'SCRemoveOption', type: :string, data: '1' } ,:x86_64) }
end
If the registry key exists with data 1 or 2 or 3, There is no need to udpate or else the registry_key-data should be updated to 1.
not_if { registry_data_exists?('HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon',{ name: 'SCRemoveOption', type: :string, data: '([1-3])'} ,:x86_64) }
(Apologies for previous effort)
I have preferred using a powershell_script resource as I know PS syntax better than ruby/Chef. I used to check with Security Policy was enabled/disabled as follows:-
powershell_script 'my_script' do
guard_interpreter :powershell_script
cwd 'C:\Temp'
code <<-EOH
<...set the registry key(s)...>
EOH
not_if '(get-itemproperty HKLM:\\System\\CurrentControlSet\\Control\\Lsa).DisableDomainCreds -eq "1"'
end
Perhaps you can adapt to make it work with an array or values.

Method to call other methods multiple times using hash length as iterator

I have 2 methods that I want to call multiple times. The number of times that I want to call them is based on the count of a hash I'm using. I'm trying to create a new method that calls the other 2 and repeats for the length of the hash count. My issue is that I'm getting an error
"findfiles2.rb:61:in` `chdir': no implicit conversion of Enumerator into String (TypeError)
from findfiles2.rb:61:in `store_directories'
from findfiles2.rb:138:in `block in repeat'
from findfiles2.rb:134:in `loop'
from findfiles2.rb:134:in `repeat'
from findfiles2.rb:153:in `<main>'"
Here's my code:
require 'date'
require "mail"
options = { :address => "smtp.gmail.com",
:port => 587,
:domain => 'gmail.com',
:user_name => 'username',
:password => 'password/',
:authentication => 'plain',
:enable_starttls_auto => true }
mail_sender = "somename#gmail.com"
mail_recipient = "somename#yahoo.com"
directories = {
"directory1" => "/path/to/folder1/",
"directory2" => "/path/to/folder2/",
"directory3" => "/path/to/folder3/",
"directory4" => "/path/to/folder4/",
"directory5" => "/path/to/folder5/"
}
directory_count = directories.count.to_i
file_output = "/path/to/output/"
exclude_folder = 'sample'
output_file_name = "directory_list"
output_file_extension = ".csv"
date_today = Date.today.to_s
log_file_path = "/path/to/output/"
log_name = "script_log_" + date_today + ".txt"
log_file_name = log_file_path + log_name
# starts log file
def start_log(file_output, log_name)
Dir.chdir(file_output)
log_output = File.open(log_name, 'a+')
$stdout = log_output
puts Time.now.to_s + " > " + "Starting Script..."
puts "_______________________________________________"
end
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
# changes working directory to the directory variable
puts Time.now.to_s + " > " + "Updating search directory..."
Dir.chdir(directory)
# outputs only subdirectories with a creation date of older than 24 hours, except for folders names 'test'
Dir.glob("*.*").map(&File.method(:realpath))
puts Time.now.to_s + " > " + "Gathering subdirectories..."
subdir_list=Dir.glob("*").map(&File.method(:realpath)).reject{|files| (not File.directory?(files) && (File.mtime(files) < (Time.now - (60*1440))) && (not files == directory + folder_to_exclude)) }
return subdir_list
end
# checks to see if there are any directories in the array
def directory_check(directory_list, save_to_file, today_date, output_file, output_extension)
if directory_list.empty? == false
# changes the working directory to the file output directory for the file
Dir.chdir(save_to_file)
# writes the array contents into a new file
file_name = output_file + "_" + today_date + output_extension
puts Time.now.to_s + " > " + "Saving contents to: " + file_name
File.open(file_name, "a+") do |f|
directory_list.each { |element| f.puts(element) }
end
else
puts Time.now.to_s + " > " + "This directory does not contain any subdirectories that are older than 24 hours"
exit
end
end
# sends an email containing today's report if a file was created today
def send_email(today_date, output_file_path, output_file_name, output_file_extension, mail_options, email_sender, email_recipient)
backlog_file = output_file_path + output_file_name + "_" + today_date + output_file_extension
if File.exist?(backlog_file) == true
puts Time.now.to_s + " > " + "Sending email report to: " + email_recipient + "..."
Mail.defaults do
delivery_method :smtp, mail_options
end
Mail.deliver do
to email_recipient
from email_sender
subject 'Backlog for ' + today_date
body 'Attached is a report showing any batches that have not been processed within the last 24 hours.'
add_file backlog_file
end
else
puts Time.now.to_s + " > " + "No batches older than 24 hours to report"
exit
end
end
This is the method that is giving me trouble
def repeat(directory, times, exclude_folder)
# fail "times must be 1 or more" if times < 1
counter = 1
# counter_string = counter.to_s
# puts counter_string
# directory_counter = directory + counter_string
loop do
if counter != times
subdir_list_contents = store_directories(directory, exclude_folder)
directory_check(subdir_list_contents, file_output, date_today, output_file_name, output_file_extension)
counter = counter + 1
else
break
end
end
end
This is where I'm starting to run everything.
# Starting log file...
start_log(file_output, log_name)
repeat(directories.each, directory_count, exclude_folder)
# # outputs contents of directory 1 to the file (I want to perform this for the amount of times equal to the hash length, which is what I'm creating the repeat method for)
subdir_list_contents = store_directories(directory1, exclude_folder)
directory_check(subdir_list_contents, file_output, date_today, output_file_name, output_file_extension)
# # # If there is a new file from today, sends an email with file as attachment
send_email(date_today, file_output, output_file_name, output_file_extension, options, mail_sender, mail_recipient)
Your code is much too long. As you can see, nobody helps you.
$ ruby -w t.rb
t.rb:125: warning: mismatched indentations at 'end' with 'def' at 104
t.rb:37: warning: assigned but unused variable - log_file_name
/Users/b/.rvm/rubies/ruby-2.4.0-rc1/lib/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:
in `require': cannot load such file -- mail (LoadError)
Post code that we can run. I'm not going to install a whole mail server. So I comment out
#require "mail"
then
t.rb:44:in `chdir': No such file or directory # dir_chdir - /path/to/output/ (Errno::ENOENT)
etc, etc.
Follow the error message :
t.rb:62:in `chdir': no implicit conversion of Enumerator into String (TypeError)
from t.rb:62:in `store_directories'
from t.rb:139:in `block in repeat'
from t.rb:136:in `loop'
from t.rb:136:in `repeat'
from t.rb:149:in `<main>'
All what you need to trace is repeat and store_directories, so you could have reduced the posted code to this strict minimum to reproduce the error :
directories = {
"directory1" => "/path/to/folder1/",
"directory2" => "/path/to/folder2/",
}
directory_count = directories.count.to_i
exclude_folder = 'sample'
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
puts "directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
Dir.chdir(directory)
end
def repeat(directory, times, exclude_folder)
store_directories(directory, exclude_folder)
end
repeat(directories.each, directory_count, exclude_folder)
Execution :
$ ruby -w t.rb
directory=#<Enumerator: {"directory1"=>"/path/to/folder1/", "directory2"=>"/path/to/folder2/"}:each> folder_to_exclude=sample
t.rb:12:in `chdir': no implicit conversion of Enumerator into String (TypeError)
from t.rb:12:in `store_directories'
from t.rb:16:in `repeat'
from t.rb:19:in `<main>'
Had you done this, you don't even had to post a question, because the cause of the error is obvious. In
repeat(directories.each, directory_count, exclude_folder)
directories.each returns an Enumerator. Remove each :
$ ruby -w t.rb
directory={"directory1"=>"/path/to/folder1/", "directory2"=>"/path/to/folder2/"} folder_to_exclude=sample
t.rb:12:in `chdir': no implicit conversion of Hash into String (TypeError)
from t.rb:12:in `store_directories'
from t.rb:16:in `repeat'
from t.rb:20:in `<main>'
I suppose that what you wanted to do is call repeat once for each directory :
def repeat(directory, exclude_folder)
puts "in repeat directory=#{directory} exclude_folder=#{exclude_folder}"
store_directories(directory, exclude_folder)
end
directories.each { | _key, directory | repeat(directory, exclude_folder) }
Execution :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
t.rb:18:in `chdir': No such file or directory # dir_chdir - dir2 (Errno::ENOENT)
from t.rb:18:in `store_directories'
from t.rb:53:in `repeat'
chdir has a side effect : it changes the current directory, and the next time, it will start searching in the new current directory. To avoid this, you need to restore the previous state :
def store_directories(directory, folder_to_exclude)
puts "in store_directories directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
current_directory = Dir.getwd
Dir.chdir(directory)
# ...
# Restore the directory that was current when entering the method.
# Without it, the next chdir will start from the directory left by the previous chdir.
Dir.chdir(current_directory)
end
Now it works :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
After a few more changes, I end up with this :
require 'date'
directories = {
"directory1" => 'dir1',
"directory2" => 'dir2'
}
exclude_folder = 'sample'
#file_output = '.'
#date_today = Date.today.to_s
#output_file_name = 'directory_list'
#output_file_extension = '.csv'
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
puts "in store_directories directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
current_directory = Dir.getwd
puts Time.now.to_s + " > " + "Updating search directory..."
# changes working directory to the directory variable
Dir.chdir(directory)
# outputs only subdirectories with a creation date of older than 24 hours, except for folders names 'test'
puts Time.now.to_s + " > " + "Gathering subdirectories..."
subdir_list = Dir.glob("*").map { | file | File.realpath(file) }
puts "all files : subdir_list=#{subdir_list}"
puts "directory + folder_to_exclude=#{directory + folder_to_exclude}" # nonsense
subdir_list = subdir_list.reject do | file |
not File.directory?(file) \
&& File.mtime(file) < Time.now - 86400 \
&& (not file == folder_to_exclude)
end
puts "after reject : subdir_list=#{subdir_list}"
# Restore the directory that was current when entering the method.
# Without it, the next chdir will start from the directory left by the previous chdir.
Dir.chdir(current_directory)
puts "subdir_list=#{subdir_list.inspect}"
subdir_list
end
# checks to see if there are any directories in the array
def directory_check(directory_list, save_to_file, today_date, output_file, output_extension)
if directory_list.empty? == false
# changes the working directory to the file output directory for the file
Dir.chdir(save_to_file) # <----------------- problem !!!!
# writes the array contents into a new file
file_name = output_file + "_" + today_date + output_extension
puts Time.now.to_s + " > " + "Saving contents to: " + file_name
File.open(file_name, "a+") do |f|
directory_list.each { |element| f.puts(element) }
end
else
puts Time.now.to_s + " > " + "This directory does not contain any subdirectories that are older than 24 hours"
end
end
def repeat(directory, exclude_folder)
puts "in repeat directory=#{directory} exclude_folder=#{exclude_folder}"
subdir_list_contents = store_directories(directory, exclude_folder)
directory_check(subdir_list_contents, #file_output, #date_today, #output_file_name, #output_file_extension)
end
directories.each { | _key, directory | repeat(directory, exclude_folder) }
Execution :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
2017-10-27 08:05:24 +0200 > Updating search directory...
2017-10-27 08:05:24 +0200 > Gathering subdirectories...
all files : subdir_list=["/userdata/devl/ruby/zintlist/directories/dir1/x1.txt", "/userdata/devl/ruby/zintlist/directories/dir1/x2.txt"]
directory + folder_to_exclude=dir1sample
after reject : subdir_list=[]
subdir_list=[]
2017-10-27 08:05:24 +0200 > This directory does not contain any subdirectories that are older than 24 hours
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
2017-10-27 08:05:24 +0200 > Updating search directory...
2017-10-27 08:05:24 +0200 > Gathering subdirectories...
all files : subdir_list=["/userdata/devl/ruby/zintlist/directories/dir2/x3.txt"]
directory + folder_to_exclude=dir2sample
after reject : subdir_list=[]
subdir_list=[]
2017-10-27 08:05:24 +0200 > This directory does not contain any subdirectories that are older than 24 hours

How do i define variable within a template cookbook

I am trying to edit the existing user_management cookbook on the supermarket to include sudoers. I seem to be having problems properly defining the sudoers_groups variable within the template.
Link to default cookbook
https://github.com/FFIN/user_management/blob/master/recipes/default.rb
Here is what my vault looks like.
knife vault show testusers john
action: create
comment: John Smith
dbpass: secret
gid: john
id: john
password: $1$d$xKNtrFrifo6f7tLFW1xh750
shell: /bin/bash
sudo_pwdless: true
sudoer: false
sudoer_group:
command: ALL
name: admin
sudo_pwdless: false
command: ALL
name: wheel
sudo_pwdless: false
command: ALL
name: sysadmin
sudo_pwdless: true
uid: 1002
username: john`
Here is the template section of my recipe
sudoer_users = Array.new()
if user['sudoer']
command = user['command'] ? user['command'] : 'ALL'
hash = { :uname => user['username'], :command => command, :sudo_pwdless => user['sudo_pwdless'] }
sudoer_users.push(hash)
end
template "/etc/sudoers" do
source 'sudoers.erb'
mode '0440'
owner 'root'
group node['root_group']
variables(
:sudoers_users => sudoer_users,
:sudoers_groups => node[:testcookbook][:testusers][:sudoer_group]
)
only_if { sudoer_users }
end
When i run the recipe, i get the following error
Recipe Compile Error in /var/chef/cache/cookbooks/newuser/recipes/default.rb ============================================. ==================================== NoMethodError
-------------`
undefined method [] for nil:NilClass
template "/etc/sudoers" do
61: source 'sudoers.erb'
62: mode '0440'
63: owner 'root'
64: group node['root_group']
65: variables(
66: :sudoers_users => sudoer_users,
67>> :sudoers_groups => node[ :testcookbook][ :testusers][ :sudoer_group]
68: )
69: only_if { sudoer_users }
70: end
My question is how do i go about defining the sudoers_group variable so that it only iterates the sudoer_group section within the vault?
Unfortunately Ruby doesn't give us enough info to check which is undefined, but either node[:testcookbook] or node[:testcookbook][:testusers] is unset/undefined. Double check where you are setting the sudoer_group value because it is likely either misformatted or not uploaded to the Chef Server.
Here is what i did to finally resolve the issue.
I added the following as part of my variables in attributes/default.rb.
default['testcookbook']['testusers']['sudoer_group'] = [
{"name" => "admin", "sudo_pwdless" => false, "command" => "ALL"},
{"name" => "wheel", "sudo_pwdless" => false, "command" => "ALL"},
{"name" => "sysadmin", "sudo_pwdless" => true, "command" => "ALL"}
]`

Resources