ERROR new to chef - ruby

New to Chef, bare wi/ me. Building my cookbook.

How did you set the databag?
are you able to get the credential out using :
$ knife vault show nameOfVault nameOfItem
or
$ knife data bag show nameOfVault nameOfItem_keys

Glad you have your data bag loading and indeed, with Test Kitchen you do not need to use knife to upload to Chef Server, as Test Kitchen uses Chef Zero / Solo.
The issue you have here is that you have not correctly formatted reading from the data bag object once you have read. You need to do this instead:
ruby_block "insert_line" do
block do
file = Chef::Util::FileEdit.new('/var/lib/net-snmp/snmpd.conf')
file.insert_line_if_no_match("/www.example.com/", "createUser
#{snmp3usercreds['user']}
SHA #{snmp3usercreds['auth_pssword']}
AES #{snmp3usercreds['enc_password']} ")
file.write_file
end
end
So, you will see I have changed snmp3usercreds[user] to snmp3usercreds['user'] with quotes around the user to show it is a string (rather than a variable as is the case with your code).

Related

Chef - Get output of remote_execute resource

Usually I get command outputs in variables like this:
res = `find . -name my_script.sh`. Then I can parse the output for what I am interested in.
How can I get the output of a command executed by a machine_execute resource ?
machine_execute 'Check IPA status' do
command 'ipactl status'
machine 'IPA_Admin_server'
end
You can't, Chef resources don't generally have outputs. In some cases the support an output API (like the AWS provisioning driver's aws_object helpers) but for something like this you would need to get the low-level Machine object and call its execute method. Take a look at how the resource is implemented for an example. You might also want to skip Provisioning's transport layer and use Train as we are probably going to try and centralize on that library.

Run arbitrary ruby code in a chef cookbook

I have a simple chef cookbook and all it does is it sets the MOTD on a CentOS machine. It takes the content of the /tmp/mymotd.txt and turns it into the MOTD.
I also have a simple ruby script (a full-fledged ruby script) that simply reads the text from the web-server and puts in into the /tmp/mymotd.txt.
My questions are:
how do I run this ruby script from within the cookbook?
how do I pass some parameters to the script (e.g. the address of the web-server)
Thanks a lot beforehand.
Ad 1.
You can use libraries directory in scripts to place there your ruby script and declare it in a module. Example:
# includes
module MODULE_NAME
# here some code using your script
# Example function
def example_function (text)
# some code
end
end
You can use then
include MODULE_NAME
in your recipe to import those functions and just use it like
example_function(something)
What's good - you can use there also Chef functions and resources.
IMPORTANT INFO: Just remember that Chef has 2 compilation phases. First will be all of Ruby code, second all of Chef resources. This means, that you have to remember priority of code. I won't write here more info about it, since you haven't asked for this, but if you want, you can find it here.
Ad 2.
You can do this in several ways, but it seems to me, that the best option for you would be to use environments. You can find more info in here. Basically, you can set up environment for script before it will run - this way you can define some variables you would use later.
Hope this helps.

Error in uploading Data bag from Ruby

I have designed code in ruby which converts my xls to json partially through spreadsheet and code. I need to upload this json to my data bag on chef-server. I am using knife commands from ruby code and running it. The json files upload to my local chef-repo correctly, but for transferring to chef-server I am getting this error:
ERROR: Chef::Exceptions::ValidationFailed: Data Bag Items must contain a Hash or Mash!
I have validated the json, id matches name of file and tried using [] braces at start and end but doesn't work. This is start of my json:
{
"id": "default_1",
"Sr.No" : "1", ....}
My ruby code essentials look like :
require 'spreadsheet'
book = Spreadsheet.open('BI.xls')
sheet1 = book.worksheet('Sheet1')
.
.
.
cmd1 = "cd #{current_dir}/chef-repo"
cmd2 = "knife data_bag create TestDB" #tried knife data bag too
cmd4 = "knife data_bag from file TestDB default_1.json" #tried knife data bag too
upload = %x[#{cmd1} && #{cmd2} && #{cmd4} ]
puts "#{upload}"
The command knife node list shows nodes correctly. I am new to chef and ruby , searched and tried many things but not working.
It surprisingly got sorted out! I stored all docs in chef-repo, and separated one file into two, the first to convert .xls to json , and the other to execute knife commands . I now run both ruby scripts from chef-repo and the work just as expected. Phew!

Getting recipe list through chef server api

I want to get the recipes that a cookbook contains, through chef-server-api. Following is the code I'm using for getting the cookbook list, individual cookbook details through the api :
require 'rubygems'
require 'chef/config'
require 'chef/log'
require 'chef/rest'
require 'chef/cookbook_version'
client_name = "admin"
signing_key_filename="c:/chef-repo/.chef/admin.pem"
server_url = "https://10.132.17.244:443"
rest = Chef::REST.new(server_url, client_name, signing_key_filename)
cookbooks = rest.get_rest("/cookbooks?all_versions")
cookbooks.keys.each do |name|
cookbook_versions = rest.get_rest("/cookbooks/#{name}")
print "#{name}\n"
cookbook_versions[name]["versions"].each do |cv|
version = cv["version"]
cookbook = rest.get_rest("/cookbooks/#{name}/#{version}")
print "\t#{cookbook}\n"
#parsed = JSON[cookbook]
end
end
The problem I'm facing is to get the recipe list from the 'cookbook' object. I tried parsing it to ruby hash and then read, but of no use. If I directly print the 'cookbook' variable, the output is something like the screenshot
I'm not able to get how to interpret the output I am getting by hitting the '/cookbooks/NAMEW/VERSION' endpoint, and get the recipes present in an individual cookbooks.
When using the Chef gem it automatically decodes some responses into Ruby objects for you. You can either use the object directly (specifically you want #recipe_filenames and then parse those to the cookbook_name::recipe_name format) or you could use a better API client like Chef-API or PyChef.
Need a ruby solution? The following example uses jq to filter the JSON resultset returned by knife:
$ knife cookbook show apache2 2.0.0 recipes -Fj | jq '.[]|.name'
"mod_cgi.rb"
"mod_proxy_http.rb"
"mod_proxy_html.rb"
"mod_access_compat.rb"
"mod_authz_dbd.rb"
"mod_proxy_express.rb"
..
..

Chef cookbook - copy file to local user with '~' ruby variable

Well, let's start by saying I'm a chef noob and I am trying to hash this code out.
I am in a full mac shop. I am using Chef to automate system wide changes. As I'm new, I'm rolling it out onto our Mac AV systems.
Basically, there is a folder on a file server that has MAC SCREEN SAVERS directory. I copy the server directory locally to the MAC OS X /User/user_name/Pictures directory.
So, this is what I got in chef:
local_folder_modified = File.mtime("~/Pictures/SCREEN SAVER NEW MACS")
server_folder_modified = File.mtime("/Volumes/SERVER/SCREEN\ SAVER\ NEW\ MACS/")
if server_folder_modified != local_folder_modified
# file has changed
then
require 'fileutils'
FileUtils.cd('server_folder_modified') do
FileUtils.rm('local_folder_modified/*')
FileUtils.cp_r './*', 'local_folder_modified'
Else
end
end
Anyways, I can't figure how to set the '~' to be the running user of this recipe. So, if Comp_A has user Jim_Beam and Comp_B has user Jack_Daniels, I don't want to set the code to be:
ENV[HOME] = /user/jimbeam
As it won't work on Jack_Daniels. Right?
I've read that file.expand will work, or ENV, but I am really unsure what will be the best code to say
"hey, I want the current user that will need this screen saver - so set the environment as a variable so it works across different nodes".
Anyways, thanks for your help. I hope I am making sense!
Yes, use File.expand. It will expand the tilde ~ to be the the home directory of the user running this cookbook. Alternatively, you could do:
"#{ENV['HOME']}/Pictures/SCREEN SAVER NEW MACS"
Like the previous comment, this is not chef DSL or ruby code. What is the source of this code or is it just pseudo-code to ask the question?
Also, chef-client is not frequently run as multiple users in a chef server deployment. It's usually run in a sudo context. So maybe you are referring to a --local-mode or chef-zero application?
You may want to use file stat of /dev/console to get the current user. Depending how you are running the chef-client Env[‘Home’] might not give you want you want. Try this:
console_user = Etc.getpwuid(::File.stat("/dev/console").uid).name
home_dir = ::File.join(‘Users’, console_user)
You can see that the chef launchd provider uses this method to determine the console user
Also there is a much simpler way to do what you are trying to accomplish with the remote_file resource. Try this:
console_user = Etc.getpwuid(::File.stat("/dev/console").uid).name
home_dir = ::File.join(‘Users’, console_user)
pics = ::File.join("#{home_dir}/Pictures/")
server_base_url = "https://PLACE_WHERE_STORE/Wallpapers")
[
‘Pic1’,
‘Pic2’,
].each do |pic|
remote_file ::File.join(pics, pic) do
source “#{server_base_url}/#{pic}”
owner console_user
group console_user
mode '0755'
action :create
end
end
For added security you should also include checksum

Resources