Search code examples
rubyyamlinspec

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?


Solution

  • 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}]