In the tutorial
https://docs.vagrantup.com/v2/multi-machine/
there are a few examples of code such as
config.vm.define :testing do |test|
config.vm.define "web" do |web|
In some of these examples, the string after define is the same as after do (web, web) , in some it is not (testing, test). Why?
Also, why use quotes with "web" but colon with :testing ?
Its more ruby language than vagrant, but basically config.vm.define is a method which takes one parameter, then there is a ruby block statement and within this block the method parameter has a specific name which is defined between the |
Also, why use quotes with "web" but colon with :testing ?
As a ruby novice, I would say it is the same - the :x is called symbols and you can read some differences about using one or the other
Related
I'm creating a chef recipe to apply a configuration change on all servers whose hostname matches a specific pattern using regexp. However, I'm not sure how to do it.
Example: my hostname looks like this:
dvabwichf01
dvcdwichf01
my recipe in default.rb is :
case node['hostname']
when '*ab*'
template "/tmp/regextest" do
source "test_ab.erb"
mode "0644"
end
else
template "/tmp/regextest" do
source "test_cd.erb"
mode "0644"
end
end
But this is not working as expected, only the "else" template is updating on all servers. please assist.
You would need to use an actual regex, not a string like you have there (also you're using fnmatch glob matching, not a regex). That would only fix when the hostname is literally *ab*. A regexp literal in Ruby usually looks like /whatever/. so when /ab/ in this case.
I used switch for choosing values by adding a method in my helper file (in my case I put it into / app / helpers / application_helper.rb
Example below:
def name_of_your_method(hostname)
case hostname
when "Host1"
"template_1"
when "Host2"
"template_2"
when "Host2"
"template_3"
when "Host3"
"template_4"
else
"template_default"
end
end
Then in your code you would use the name in your method:
<%= user.hostname %>
And in your table(data) you would have a column for hostname(in this example)
Hope this helps
I'm confused with the ruby syntax used to configure Vagrant. Especially with this construct. Is this an assignment, a method call, or something else? Is it pure ruby or vagrant specific dialect?
config.vm.network "forwarded_port", guest: 3000, host: 3000
And this one. Is the "ansible" an assignment or an argument, and where |ansible| comes from?
config.vm.provision "ansible" do |ansible|
ansible.playbook = "provisioners/docker.yml"
end
Where I can find more information about those specific expressions?
Those are DSLs, Ruby is a very good language for writing DSL, take a look a this other question
Although those are DSLs, you can throw vanilla Ruby code outside those blocks, and probably inside as well as long as it gets evaluated.
The Vagrantfile is written in standard Ruby syntax.
Here is an example Vagrantfile
Vagrant.configure("2") do |config|
# this is an evaluation statement
# .box is an string attribute
config.vm.box = "debian/stretch64"
# this is a method call
# .synced_folder is a method that takes two positional arguments ('synced_folder', '/vagrant'),
# followed by some keyword arguments (disabled: true)
config.vm.synced_folder 'synced_folder', '/vagrant', disabled: true
# this is a method call, followed by a "do ... end" block
# .provider is a method that takes one positional argument (:libvirt)
config.vm.provider :libvirt do |node|
# these are two evaluation statements
node.cpus = 4
node.memory = 4096
end
end
From the official documents,
you can see the variable "string" in "config.vm.box (string)",
but not following the methods config-vm-provider and config-vm-synced_folder.
I was also confused about the Vagrantfile syntax, even after reading the offical documents.
I think it's because Ruby looks very different to me compared to other languages I used before.
Vagrant.configure(2) do |config|
config.vm.define "chefnode" do |chefnode|
chefnode.vm.box = "geerlingguy/ubuntu1604"
chefnode.vm.hostname = 'cnode'
chefnode.vm.network "public_network"
end
config.vm.define "chefserver" do |chefserver|
chefserver.vm.box = "geerlingguy/ubuntu1604"
chefserver.vm.hostname = 'cserver'
chefserver.vm.network "public_network"
end
end
I am badly struggling on the above (vagrant dsl) code. Is this Ruby DSL or plain Ruby or something else? Why is there an "=" sign for vm.box and vm.hostname, but not for vm.network??
first of all it's ruby, which as a language can be very handy when you want to create your own DSL. All DSLs are built using base ruby concepts like blocks (do ... end) - no magic here.
In your case we may say it's DSL created by Vagrant owners.
Why do they once use = and an another time not? In this specific case I assume it's caused by fact you have one argument which is a String and is required, and later on yo may pass a hash with different setup options, like in example from documentation.
Vagrant.configure("2") do |config|
config.vm.network "forwarded_port", guest: 80, host: 8080
end
If they wanted to use = they would have to enforce you to pass a Hash in which name key would be required and the rest would be optional, I mean something like this:
config.vm.network = { name: "default" }
This is standard Ruby, no DSL or metaprogramming magic here.
Ruby is unusual in this regard, but the following are both calling methods on the object returned by chefserver.vm:
chefserver.vm.hostname = 'chefserver' # calls method 'hostname='
chefserver.vm.network "public_network" # calls method 'network'
Ruby does not require the use of parentheses for a method call (although sometimes they are necessary to clarify to the interpreter what you mean).
I don't know Chef, so I can't say why the network call is not network=, except that in Ruby calling a method whose name ends with '=' with more than 1 parameter does not work. And although only 1 parameter to network is specified here, in Ruby there can be optional arguments. The method may have been defined something like this:
def network(name, something = 'foo')
# ...
end
...so that the method can be called with either 1 or 2 arguments.
I'm looking to create a role based on host name prefix and I'm running into some problems. Ruby is new to me and although I've done extensive searching for a solution, I'm still confused.
Host names look like this:
work-server-01
home-server-01
Here's what I've written:
require 'facter'
Facter.add('host_role') do
setcode do
hostname_array = Facter.value(:hostname).split('-')
first_in_array = hostname_array.first
first_in_array.each do |x|
if x =~ /^(home|work)/
role = '"#{x}" server'
end
role
end
end
I'd like to use variable interpolation within my role assignment, but I feel like using a case statement along with 'when' is incorrect. Please keep in mind that I'm new to Ruby.
Would anybody have any ideas on how I might achieve my goal?
Pattern-Matching the Hostname Fact
The following is a relatively DRY refactoring of your code:
require 'facter'
Facter.add :host_role do
setcode do
location = case Facter.value(:hostname)
when /home/ then $&
when /work/ then $&
else 'unknown'
end
'%s server' % location
end
end
Mostly, it just looks for a regex match, and assigns the value of the match to location which is then returned as part of a formatted string.
On my system the hostname doesn't match either "home" or "work", so I correctly get:
Facter.value :host_role
#=> "unknown server"
I cant figure out how to use a simple global variable in an rspec test. It seems like such a trivial feature but after much goggleing I havent been able to find a solution.
I want a variable that can be accessed/changed throughout the main spec file and from functions in helper spec files.
Here is what I have so far:
require_relative 'spec_helper.rb'
require_relative 'helpers.rb'
let(:concept0) { '' }
describe 'ICE Testing' do
describe 'step1' do
it "Populates suggestions correctly" do
concept0 = "tg"
selectConcept() #in helper file. Sets concept0 to "First Concept"
puts concept0 #echos tg?? Should echo "First Concept"
end
end
.
#helpers.rb
def selectConcept
concept0 = "First Concept"
end
Can someone point out what I am missing or if using "let" is totally the wrong method?
Consider using a global before hook with an instance variable: http://www.rubydoc.info/github/rspec/rspec-core/RSpec/Core/Configuration
In your spec_helper.rb file:
RSpec.configure do |config|
config.before(:example) { #concept0 = 'value' }
end
Then #concept0 will be set in your examples (my_example_spec.rb):
RSpec.describe MyExample do
it { expect(#concept0).to eql('value') } # This code will pass
end
It turns out the easiest way is to use a $ sign to indicate a global variable.
See Preserve variable in cucumber?
This is an old thread, but i had this question today. I just needed to define a long string to stub out a command that is in multiple files as:
# in each spec file that needed it
let(:date_check) do
<<~PWSH.strip
# lots of powershell code
PWSH
end
# in any context in that file (or a shared context)
before(:each) do
stub_command(date_check).and_return(false)
end
Searched, Stack Overflow, etc, landed on this: Note the usage of the variable doesn't change at all! (Assumes all specs require 'spec_helper')
# in spec_helper.rb
def date_check
<<~PWSH.strip
# lots of powershell code
PWSH
end
# in any context in any spec file
before(:each) do
stub_command(date_check).and_return(false)
end
I suggest you define the variable in the helper file, where it can be used by other helper code, and can be accessed from your tests.
For my project, I wanted to keep all the setup stuff in spec_helper.rb, and use those settings, plus any custom variables and methods in the tests. The following, modified from the RSpec-core 3.10 docs, is not Rails-specific.
Create a new setting for RSpec.configure called my_variable, and give it a value, like this:
# spec/spec_helper.rb
RSpec.configure do |config|
config.add_setting :my_variable
config.my_variable = "Value of my_variable"
end
Access settings as a new read-only property in RSpec.configuration from your test:
# spec/my_spec.rb
RSpec.describe(MyModule) do
it "creates an instance of something" do
my_instance = MyModule::MyClass.new(RSpec.configuration.my_variable)
end
end