mcollective inventory script - ruby

I created mCollective inventory script as below,
def formatting(users_ids)
YAML.load(File.open(users_ids))
end
inventory do
format "%s\t%s\t"
fields { [facts["hostname"], formatting(facts["users_ids"]) ] }
end
Here users_ids facter is in yaml format on the server. So when I do inventory for this facter I need to parse that yaml format to hash. But when I run with this script getting below error,
[root#mco-server]#
The inventory application failed to run, use -v for full error backtrace details: (eval):2:in `initialize': No such file or directory - ---
root: 0
test1: 503
testuser: 2033
[root#mco-server]#
Not sure if am missing something to get the output parsed. The strange thing is its not printing hostname also.
The facter output is below on the server from facts.yaml
users_ids: |-
---
root: 0
test1: 503
testuser: 2033
Any help would be much appreciated.

According to the error message, the argument you are passing to users_ids is not a valid filename.
def formatting(users_ids)
YAML.load(File.open(users_ids))
end
Somehow your code is passing --- as an argument to that method. This is likely due to the combination of your API calls to parse and load the yaml and the yaml file itself. Consider changing the API call to a cleaner:
def formatting(users_ids)
YAML.load_file(users_ids)
end
and I think you really want a hash in your yaml and not an array of key-value pairs with an element of ---, so your yaml should really be:
users_ids:
root: 0
test1: 503
testuser: 2033
which would also remove the --- which typically indicates the beginning of a yaml, and also seems to be what your code is erroring on in the way you are trying to load the yaml.

Related

inspec - i want to output structured data to be parsed by another function

I have a inspec test, this is great:
inspec exec scratchpad/profiles/forum_profile --reporter yaml
Trouble is I want to run this in a script and output this to an array
I cannot find the documentation that indicated what method i need to use to simulate the same
I do this
def my_func
http_checker = Inspec::Runner.new()
http_checker.add_target('scratchpad/profiles/forum_profile')
http_checker.run
puts http_checker.report
So the report method seems to give me load of the equivalent type and much more - does anyone have any documentation or advice on returning the same output as the --reporter yaml type response but in a script? I want to parse the response so I can share output with another function
I've never touched inspec, so take the following with a grain of salt, but according to https://github.com/inspec/inspec/blob/master/lib/inspec/runner.rb#L140, you can provide reporter option while instantiating the runner. Looking at https://github.com/inspec/inspec/blob/master/lib/inspec/reporters.rb#L11 I think it should be smth. like ["yaml", {}]. So, could you please try
# ...
http_checker = Inspec::Runner.new(reporter: ["yaml", {}])
# ...
(chances are it will give you the desired output)

Get the keyname from a YAML configuration file

I would like to get the name of a key in a YAML configuration file like the following
The YAML file contains a collection of structs in structs, the organisations have a number represented as a symbol which is the key/class name. I need to retrieve this symbol
require 'yaml'
data = YAML.load(DATA)
data.organisations.each do |organisation|
organisation #<struct language="nl", name="myname">
# following line is what I need, I expect it to be :"121"
organisation.class #<Class:0x00000004fd4248>
end
__END__
--- !ruby/struct
organisations: !ruby/struct
:121: !ruby/struct
language: nl
name: organisationname
Can someone help me retrieving the name of the struct ?
I tried around a bit and found this:
data.organisations.members
=> [:"121"]
The way I found this (which is useful in other circumstances, too) is the following:
data.organisations.methods - Object.new.methods
And then I tried out every method that seemed reasonable.

Ruby, parsing YAML and outputting value

I'm pretty new to ruby and all the documentation on this subject has confused me a bit. So here goes.
I'm using inspec to test my infrastructure, but I want it to consume some variables from the YAML file used by ansible. This effectively means I can share vars from ansible code and use them in ruby.
The YAML file looks like this:
- name: Converge
hosts: all
vars:
elasticsearch_config:
cluster.name: "{{ elasticsearch_cluster_name }}"
node.name: "es-test-node"
path.data: "/var/lib/elasticsearch"
path.logs: "/var/log/elasticsearch"
elasticsearch_cluster_name: test
pre_tasks:
roles:
- elasticsearch
post_tasks:
At this point, I'm just playing around with ruby code to extract that, and have:
require 'yaml'
parsed = begin
YAML.load(File.open("../../playbook.yml"))
rescue ArgumentError => e
puts "Could not parse YAML: #{e.message}"
end
puts parsed
Which outputs the hash:
{"name"=>"Converge", "hosts"=>"all", "vars"=>{"elasticsearch_config"=>{"cluster.name"=>"{{ elasticsearch_cluster_name }}", "node.name"=>"es-test-node", "path.data"=>"/var/lib/elasticsearch", "path.logs"=>"/var/log/elasticsearch"}, "elasticsearch_cluster_name"=>"test"}, "pre_tasks"=>nil, "roles"=>["elasticsearch"], "post_tasks"=>nil}
So far so good. This all makes sense to me. Now, I would like to pull values out of this data and use them in the ruby code, referencing them by the keys. So, if I wanted to get the value of vars.elasticsearch_config.node.name, how would I go about doing this?
YAML.load reads the document into an array, so you must get the first element in your example:
loaded_yaml[0]["vars"]["elasticsearch_config"]["node.name"]
The reason for this is that the document you are parsing begins with a single dash, indicating a list item. Even though there is only one item in the list, Psych (thy YAML engine) is still placing it into an array representing a list. This is also why you got a no implicit conversion of String to Integer error. Note that the response you get is enclosed by square brackets:
=> [{"name"=>"Converge", "hosts"=>"all", "vars"=>{"elasticsearch_config"=>{"cluster.name"=>"{{ elasticsearch_cluster_name }}", "node.name"=>"es-test-node", "path.data"=>"/var/lib/elasticsearch", "path.logs"=>"/var/log/elasticsearch"}, "elasticsearch_cluster_name"=>"test"}, "pre_tasks"=>nil, "roles"=>["elasticsearch"], "post_tasks"=>nil}]

ruby/hash:Chef::Node::ImmutableMash included in file when converting Chef attributes to yaml

I am trying to write a .yml file from a subset of attributes. Here's the resource definition I'm using:
file '/home/user/file.yml' do
owner 'user'
group 'user'
mode '0755'
content node['default']['properties'].to_yaml
end
When I run this, the file.yml ends up looking like this though:
--- !ruby/hash:Chef::Node::ImmutableMash
config: !ruby/hash:Chef::Node::ImmutableMash
example: value
another: value
How do I get clean yaml output without all the !ruby/hash:Chef::Node::ImmutableMash output?
Turns out all you need to do is convert the attributes to a hash explicitly before converting to yaml. Here is the working code:
file '/home/user/file.yml' do
owner 'user'
group 'user'
mode '0755'
content node['default']['properties'].to_hash.to_yaml
end
Note: you'll need to be using chef-client 11.10.0 or later, because
there used to be a bug with the to_hash method. More info here:
https://stackoverflow.com/a/14782389/1688034

How to write a file that is both valid ruby syntax and valid YAML syntax

In order to have only a single point of configuration for my app I need to make a YAML config file that is also valid ruby code. I.e. a mixed syntax file that can be parsed as YAML and parsed as ruby.
My application is a suite of processes managed by the god gem. I want to load a new group of maintained processes (watches) for each new configuration file.
God allows loading a new app.god (ruby) file with new watches defined, but I don't want an app.god and app.yml, just one file. Simplest might be to just have the app.god file and include the configuration within that, but I preferred the idea of a yml file that was also valid ruby code.
#I found this that might be helpful:
#This is a valid ruby and a valid YAML file
#Comments are the same in YAML and ruby
true ?true:
- <<YAML.to_i
# At this point in ruby it is the contents of a here doc (that will be
# converted to an integer and negated if true happens not to be true)
# In YAML it is a hash with the first entry having key "true ?true"
# representing a list containing the string "- <<YAML.to_i"
# If your YAML object should be a list not a hash you could remove the first line
any_valid_yaml: from here
a_list:
- or
- anything
- really
#Then mark the end of the YAML document with
---
#And YAML is done and ignores anything from here on
#Next terminate the ruby here document
YAML
#Now we're in ruby world
#this = "pure ruby"
def anything(ruby)
"here"
end

Resources