I am new with ruby.
I want to use simple yml settings file
this is my code
LaunchEC2s.rb
#!/usr/bin/ruby
require 'rubygems'
require 'aws-sdk'
require 'yaml'
AWS_CON = Yaml.load_file("AWSsettings.yml") unless defined? AWS_CON
def launchEC2(count)
key_pair = ec2.key_pairs[AWS_CON['key_pair']]
image_id
ec2 = AWS::EC2.new.regions[AWS_CON['region']]
instances = ec2.instances.create(
:image_id => AWS_CON['image_id'],
:instance_type => AWS_CON['instance_type'],
:count => count,
:security_groups => AWS_CON['security_groups'],
:key_pair => key_pair)
end
launchEC2(2)
my yml file looks like
# AWS yml file
key_pair: xxx
region: us-west-2
image_id: ami-b5a7ea85
instance_type: t2.micro
security_groups: xxx
when I run it I get
./LaunchEC2s.rb:6:in `<main>': uninitialized constant Yaml (NameError)
I'm sorry is this question is dumb but I cant figure it up
What am I doing wrong ?
I'm pretty sure you want to do YAML.load_file("AWSsettings.yml") instead of Yaml.load_file("AWSsettings.yml") (the difference being all caps).
Try this:
Create a yml file in config/
say config/ec2_keys.yml
development:
region: us-west-2
image_id: ami-b5a7ea85
instance_type: t2.micro
security_groups: xxx
Now you want to initialize them once for all. For that create this one line file:
config/initializers/load_ec2.rb
EC2 = YAML.load(ERB.new(File.read("#{Rails.root.to_s}/config/ec2_keys.yml")).result)[Rails.env]
Now use the constants wherever required as:
EC2["region"]
#=> "us-west-2"
EC2["image_id"]
#=> "ami-b5a7ea85"
Related
I'm facing a problem that I couldn't find a working solution yet.
I have my YAML config file for the environment, let's call it development.yml.
This file is used to create the hash that should be updated:
data = YAML.load_file(File.join(Rails.root, 'config', 'environments', 'development.yml'))
What I'm trying to accomplish is something along these lines. Let's suppose we have an element of the sort
data['server']['test']['user']
data['server']['test']['password']
What I want to have is:
data['server']['test']['user'] = #{Server.Test.User}
data['server']['test']['password'] = #{Server.Test.Password}
The idea is to create a placeholder for each value that is the key mapping for that value dynamically, going until the last level of the hash and replacing the value with the mapping to this value, concatenating the keys.
Sorry, it doesn't solve my problem. The location data['server']['test']['user'] will be built dynamically, via a loop that will go through a nested Hash. The only way I found to do it was to append to the string the key for the current iteration of the Hash. At the end, I have a string like "data['server']['test']['name']", which I was thinking on converting to a variable data['server']['test']['name'] and then assigning to this variable the value #{Server.Test.Name}. Reading my question I'm not sure if this is clear, I hope this helps to clarify it.
Input sample:
api: 'active'
server:
test:
user: 'test'
password: 'passwordfortest'
prod:
user: 'nottest'
password: 'morecomplicatedthantest'
In this case, the final result should be to update this yml file in this way:
api: #{Api}
server:
test:
user: #{Server.Test.User}
password: #{Server.Test.Password}
prod:
user: #{Server.Prod.User}
password: #{Server.Prod.Password}
It sounds silly, but I couldn't figure out a way to do it.
I am posting another answer now since I realize what the question is all about.
Use Iteraptor gem:
require 'iteraptor'
require 'yaml'
# or load from file
yaml = <<-YAML.squish
api: 'active'
server:
test:
user: 'test'
password: 'passwordfortest'
prod:
user: 'nottest'
password: 'morecomplicatedthantest'
YAML
mapped =
yaml.iteraptor.map(full_parent: true) do |parent, (k, _)|
v = parent.map(&:capitalize).join('.')
[k, "\#{#{v}}"]
end
puts YAML.dump(mapped)
#⇒ ---
# api: "#{Api}"
# server:
# test:
# user: "#{Server.Test.User}"
# password: "#{Server.Test.Password}"
# prod:
# user: "#{Server.Prod.User}"
# password: "#{Server.Prod.Password}"
puts YAML.dump(mapped).delete('"')
#⇒ ---
# api: #{Api}
# server:
# test:
# user: #{Server.Test.User}
# password: #{Server.Test.Password}
# prod:
# user: #{Server.Prod.User}
# password: #{Server.Prod.Password}
Use String#%:
input = %|
data['server']['host']['name'] = %{server_host}
data['server']['host']['user'] = %{server_host_user}
data['server']['host']['password'] = %{server_host_password}
|
puts (
input % {server_host: "Foo",
server_host_user: "Bar",
server_host_password: "Baz"})
#⇒ data['server']['host']['name'] = Foo
# data['server']['host']['user'] = Bar
# data['server']['host']['password'] = Baz
You can not add key-value pair to a string.
data['server']['host'] # => which results in a string
Option 1:
You can either save Server.Host as host name in the hash
data['server']['host']['name'] = "#{Server.Host}"
data['server']['host']['user'] = "#{Server.Host.User}"
data['server']['host']['password'] = "#{Server.Host.Password}"
Option 2:
You can construct the hash in a single step with Host as key.
data['server']['host'] = { "#{Server.Host}" => {
'user' => "#{Server.Host.User}",
'password' => "#{Server.Host.Password}"
}
}
I am trying to get up and running with bonsai. I intend to use sinatra and ruby (not rails) although right now I am just trying to connect from my local machine. The script is:
require "csv"
require "elasticsearch"
require 'elasticsearch/transport'
Elasticsearch::Model.client = Elasticsearch::Client.new url: 'https://uz09z96il1:5g9p3h8jow#hectors-first-starte-5298580603.us-west-2.bonsai.io', log: true
#Elasticsearch::Client.new host: 'https://uz09z96il1:5g9p3h8jow#hectors-first-starte-5298580603.us-west-2.bonsai.io', log: true
#Elasticsearch::Model.client = Elasticsearch::Client.new('https://uz09z96il1:5g9p3h8jow#hectors-first-starte-5298580603.us-west-2.bonsai.io')
#client = Elasticsearch::Client.new log: true
#Elasticsearch::Model.client = Elasticsearch::Client.new url: 'https://uz09z96il1:5g9p3h8jow#hectors-first-starte-5298580603.us-west-2.bonsai.io', log: true
CSV.open("candidates.csv", "r") do |f|
f.each_with_index do |item, i|
next if i == 0
p item
client.index index: 'data', type: 'person', body: '{
"first": "#{item[1]}",
"last": "#{item[2]}"
}'
end
end
The basic error is that connection is refused, in this particular example like so:
uninitialized constant Elasticsearch::Model (NameError)
As you can see, from the commented out lines, I have tried as many variations as I can think of.
What's the best way to accomplish this? All help gratefully received, thank you.
You are getting
uninitialized constant Elasticsearch::Model (NameError)
because you haven't included the proper class. Try adding:
require 'elasticsearch/model'
At the top of your code.
I read some quick tutorials on Yaml or yml file format. I made a yaml document to represent my data. I saw some ruby tutorials which tell you how to extract yaml with ruby. Unfortunately, they just print the whole data or just keys and values. It does not meet my needs. Please help.
yaml file -
dev:
game1:
server1:
url: 'dev-game1-a-srv01.gamer.com'
log-path: '/srv/logs'
server2:
url: 'dev-game1-a-srv02.gamer.com'
log-path: '/srv/logs'
game2:
server1:
url: 'dev-game2-a-srv01.gamer.com'
log-path: '/srv/logs'
server2:
url: 'dev-game2-b-srv02.gamer.com'
log-path: '/srv/logs'
server3:
url: 'dev-game2-b-srv01.gamer.com'
log-path: '/srv/logs'
prod:
etc....
How do I select dev, game2, server 3, url using ruby code ?
Using the code below, I get an exception -
require 'yaml'
def server_info
path = 'C:\Code\demo-srv.yml'
yml = YAML::load(File.open(path))
game2 = yml['dev']['game2']
game2.each{|server|
if server['server3']
puts server['server3']['url']
end
}
end
server_info
error -
server.rb:8:in `[]': can't convert String into Integer (TypeError)
from server.rb:8:in `server_info'
from server.rb:7:in `each'
from server.rb:7:in `server_info'
from server.rb:14
Did you define the yaml-data or are you only the consumer of an existing yaml-file?
If you defined it, I would replace the array of servers with a Hash (see the missing - before the server names):
dev:
game1:
server1:
url: 'dev-game1-a-srv01.gamer.com'
log-path: '/srv/logs'
server2:
url: 'dev-game1-a-srv02.gamer.com'
log-path: '/srv/logs'
game2:
server1:
url: 'dev-game2-a-srv01.gamer.com'
log-path: '/srv/logs'
server2:
url: 'dev-game2-b-srv02.gamer.com'
log-path: '/srv/logs'
server3:
url: 'dev-game2-b-srv01.gamer.com'
log-path: '/srv/logs'
Then you can try yml['dev']['game2']['server3']['url'].
Attention: There are no checks for missing/wrong data. if the entry for game2 would miss, this code will raise an exception.
So, maybe you shoudl do something like
if yml['dev'] and yml['dev'].kind_of?(Hash)
if yml['dev']['game2'] and ....
...
else
puts "No dev-branch defined"
end
Else you can try something like:
def server_info
yml = YAML::load(DATA)
yml['dev']['game2'].each{|server|
if server['server3']
p server['server3']['url']
end
}
end
Attention (for both solutions):
There are no checks for missing/wrong data. The existence of server['server3'] is checked here. For real code, you should also check the existence of the dev and game2 data.
Answer continuation after edit:
The error convert String into Integer is often thrown if you have an array but expect a hash and you try to access an array element with a string.
You can try the following code. There are two changes:
line 8 contains the output of server - you will see it is an array, no hash.
line 9+10: The array is checked and used by its two elements (via #first and #last)
require 'yaml'
def server_info
path = 'C:\Code\demo-srv.yml'
#~ yml = YAML::load(File.open(path))
yml = YAML::load(DATA)
game2 = yml['dev']['game2']
game2.each{|server|
p server #-> you get an array
if server.first == 'server3'
puts server.last['url']
end
}
end
server_info
The file -
dev:
game1:
server1:
url: 'dev-game1-a-srv01.gamer.com'
log-path: '/srv/logs'
server2:
url: 'dev-game1-a-srv02.gamer.com'
log-path: '/srv/logs'
game2:
server1:
url: 'dev-game2-a-srv01.gamer.com'
log-path: '/srv/logs'
server2:
url: 'dev-game2-b-srv02.gamer.com'
log-path: '/srv/logs'
server3:
url: 'dev-game2-b-srv01.gamer.com'
log-path: '/srv/logs'
I don't know why but yml['dev']['game2']=>
[{"server1"=>{"url"=>"dev-game2-a-srv01.gamer.com", "log-path"=>"/srv/logs"}},
{"server2"=>{"url"=>"dev-game2-b-srv02.gamer.com", "log-path"=>"/srv/logs"}},
{"server3"=>{"url"=>"dev-game2-b-srv01.gamer.com", "log-path"=>"/srv/logs"}}]
So you have to use find on this Array to have the key.
require 'yaml'
# require 'pry'
def server3_url
yml = YAML::load(File.read('yaml.yml'))
# binding.pry
begin
yml['dev']['game2'].find{|x| x['server3']}['server3']['url']
rescue
end
end
puts server3_url
server3_url will return nil if it doesn't find a key
Changing your code the following should fix the issue.
# ...
game2.each{ |server, data|
if server == 'server3'
puts data['url']
end
}
# ...
You are encountering the type error because the yielded value server is an array, not a hash. This is happening because you are calling each on the game2 variable, which is a hash, and only yielding to a single variable.
Examples
hash = { one: 1, two: 2, three: 3 }
Yielding to a single variable
When Hash#each is called with only one variable, the current key and value are assigned to that variable as an array in the order [key, value]
hash.each do |number|
puts number.inspect
end
# Prints
# [:one, 1]
# [:two, 2]
# [:three, 3]
Yielding to multiple variables
When Hash#each is called with two variables, the current key will be assigned to the first variable, and the current value will be assigned to the second.
hash.each do |key, value|
puts "Key: #{key}; Value: #{value}"
end
# Prints:
# Key: one; Value: 1
# Key: two; Value: 2
# Key: three; Value: 3
I've got a Vagrant setup in which I'm trying to use Chef-solo to generate an conf file which loops though defined variables to pass to the application. Everything is working except the loop and I'm not familiar enough with Ruby/Chef to spot the error.
I'm going to lay out the whole chain of events in case there is something along the way that is the problem, but the first portions of this process seem to work fine.
A config file is written in yaml and includes env variable definitions to be passed:
...
variables:
- DEBUG: 2
...
The config file is read in by the Vagrantfile into a ruby hash and used to create the Chef json nodes:
...
settings = YAML::load(File.read("config.yaml"))
# Provision The Virtual Machine Using Chef
config.vm.provision "chef_solo" do |chef|
chef.json = {
"mysql" => {"server_root_password" => "secret"},
"postgresql" => {"password" => {"postgres" => "secret"}},
"nginx" => {"pid" => "/run/nginx.pid"},
"php-fpm" => {"pid" => "/run/php5-fpm.pid"},
"databases" => settings["databases"] || [],
"sites" => settings["sites"] || [],
"variables" => settings["variables"] || []
}
...
A bunch of chef cookbooks are run (apt, php, nginx, mysql etc) and finally my custom cookbook which is whats giving me grief. The portion of the cookbook responsible for creating a the conf file is shown here:
# Configure All Of The Server Environment Variables
template "#{node['php-fpm']['pool_conf_dir']}/vars.conf" do
source "vars.erb"
owner "root"
group "root"
mode 0644
variables(
:vars => node['variables']
)
notifies :restart, "service[php-fpm]"
end
And the vars.erb is just a one-liner
<%= #vars.each {|key, value| puts "env[" + key + " = " + value } %>
So, when I run all this chef spits out an error about not being able to convert a hash to a string.
can't convert Chef::Node::immutableMash into String
So for some reason this is coming across as an immutableMash and the value of key ends up being the hash [{"DEBUG"=>2}] and value ends up a nil object, but I'm not sure why or how to correct it.
The hash is ending up as the value of key in your example because the YAML file declares DEBUG: 2 as a list member of variables. This translates to variables being an array with a single hash member.
Try changing the template code to this:
<%= #vars[0].each {|key, value| puts "env[" + key + " = " + value } %>
Or try changing the YAML to this and not changing the template code:
variables:
DEBUG: 2
Either change will get your template loop iterating over the hash that you are expecting.
my goal:
check if yaml document include value for specific key using ypath/xpath
select value for specified key using ypath/xpath
document yaml:
app:
name: xxx
version: xxx
description:
author:
name: xxx
surname: xxx
email: xxx#xxx.xx
what was checked:*
google
stackoverflow
Ruby API (YAML::DBM as one of methods it provide is select)
example:
Module::Class.select('description/author/name')
Module::Class.select('*/name')
Module::Class.isset?('*/name')
Use yaml:
require 'yaml'
yml = YAML.load_file('your_file.yml')
Now yml is a hash. You can use it like one. Here is a simple and ugly solution for what you try:
if !yml["description"].nil? && !yml["description"]["author"].nil? && !yml["description"]["author"]["name"].nil? && !yml["description"]["author"]["name"].empty?
puts "An author is set!"
end
Since there are no up-to-date YPath implementations around, I would suggest to give a chance ActiveSupport and Nokogiri:
yml = LOAD_YML_WITH_YOUR_PREFERRED_YAML_ENGINE
# ActiveSupport adds a to_xml method to Hash
xml = yml.to_xml(:root => 'yaml')
doc = Nokogiri::XML(xml)
doc.xpath("description/author/name").map do |name|
puts [name['key'], name['value']]
end