I was wondering where the default commands of vagrant are defined.
How does vagrant know what to do when you type in "vagrant up" where is this defined?
I want to make vagrant echo something when you type the command vagrant up for example.
vagrant reads the Vagrantfile when you execute the vagrant command
If you want to echo something when you run the command you'll need to put in this file which is roughly a ruby script
example :
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.box = "xxxxx"
.... your config
p "put your text here"
p "#{Dir.pwd}"
ARGV.each do|a|
puts "Argument: #{a}"
end
p ARGV[0]
and
Related
This may actually be a basic Ruby question more than a Vagrant-specific question. I have two Vagrantfiles. One makes a number of generic settings. The second one makes more specific settings for the particular instance. The first is loaded into the second. The idea is to keep common settings that are the same across all Vagrantfiles in one place so it's normalizes and I don't repeat myself. Some Vagrant settings are an array of strings. If I set one of these in the first Vagrantfile, and I try to add an element to it in the second file, I get an error:
Message: NoMethodError: undefined method `<<' for :__UNSET__VALUE__:Symbol
How can I add to an array?
Here is a boiled down first Vagrantfile with just what I'm interested in:
Vagrantfile.general
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure('2') do |config|
config.vm.provider 'cloud_service' do |cs|
cs.tags = ['ExampleTag1']
end
end
Vagrantfile (Specific)
load 'Vagrantfile.general'
Vagrant.configure('2') do |config|
config.vm.provider 'cloud_service' do |cs|
cs.tags << 'ExampleTag2'
end
end
The following works, but I want to know how to add to the previous array rather than overriding the whole array.
Vagrantfile (Workaround)
load 'Vagrantfile.general'
Vagrant.configure('2') do |config|
config.vm.provider 'cloud_service' do |cs|
cs.tags = ['ExampleTag1', 'ExampleTag2']
end
end
Note: I understand that the tags can be kept in a YAML file that is loaded by first and second files and then added to or subtracted from before setting the tags in the provider. I have read this answer elsewhere. What I am seeking is a more elegant way to handle this. Basically I want to know if it is possible to access the object created by the first Vagrantfile where the array is located and add to it programmatically in the second Vagrantfile using Ruby code.
Update
Here is one option that is Ruby code, but does not access the array inside the Vagrant object: set a global variable in the first Vagrantfile. I'd still like to see an answer that accesses the Vagrant config object and modifies the array.
First
# -*- mode: ruby -*-
# vi: set ft=ruby :
$cs_tags = ['ExampleTag1']
Vagrant.configure('2') do |config|
config.vm.provider 'cloud_service' do |cs|
cs.tags = $cs_tags
end
end
Second
load 'Vagrantfile.general'
$cs_tags << 'ExampleTag2'
Vagrant.configure('2') do |config|
config.vm.provider 'cloud_service' do |cs|
cs.tags = $cs_tags
end
end
I'm trying to build a vagrant file that defines multiple VM.
Vagrant.configure("2") do |config|
config.vm.define "one" do |cfg|
[...]
end
config.vm.define "two" do |cfg|
[...]
end
end
My problem is that after the machine "two" is created and running, I want to run another script in the "one" machine.
I have tried with the experimental 'after" function, but I may use it in the wrong way.
Is it possible to do this with a pure vagrant script? (if true how ? :) )
In my vagrantfile I use two lines of rudy code to get the username and password from the console and pass it on to the shell script for creating an additional user account instead of the default vagrant
This works well for vagrant up but it beats me by prompting the same when I run any other vagrant commands like vagrant status. Is there a way to catch if the vagrant file is called with up command?
require 'io/console'
print "Please enter username: "
#username = STDIN.gets
print "Please enter password: "
#password = STDIN.noecho(&:gets)
Vagrant.configure("2") do |config|
config.vm.box = "generic/debian10"
["Node 01"].each do |node_name|
config.vm.define node_name do |node|
node.vm.provision "shell" do |p|
p.args = [#username, #password]
p.path = "create_user.sh"
end
end
end
end
UPDATE
After #Matt Schuchard's suggestion, I've tried triggers; However, the global variables that are captured inside the trigger block are not shared with the place where I pass them into the shell script (p.args = [#username, #password])
config.trigger.before :up do |trigger|
if #credential_captured == nil # I've used this to prevent executing the following block per each vm
print "Please enter username: "
#username = STDIN.gets
print "Please enter password: "
#password = STDIN.noecho(&:gets)
#credential_captured = true
end
end
Sprinkle Some Plain Ruby into the Vagrantfile
The best practice would really be to put an idempotent provisioning block at the end that picks up your information from the environment or some other fixed location rather than trying to do this as interactive user input within the Vagrantfile. However, if you really want to do it the way you're doing it, just remember that a Vagrantfile is mostly just a DSL on top of Ruby.
You can get the status of a given virtual machine with vagrant status. For a single node, you could just wrap your current prompts at the top in a conditional. For example:
# assuming a single node named "default"
if %x(vagrant status default) =~ /running/
# prompt here
end
If you're running multiple nodes, then I'd suggest wrapping your prompts into a method and moving your conditional down into the body of the shell provisioning block you already have. For example:
def prompt_user
# prompt here
end
# ...
if `vagrant status #{node_name}` =~ running
prompt_user unless #username && #password
node.vm.provision 'shell' do |p|
# provision your node here
end
end
There are likely ways to make this code more efficient, and probably other ways to do what you want, but this approach is fairly straightforward and should at least get you headed in the right direction.
As part of provisioning a VM, I need to create a configuration file at provision time. On my host machine, I'm able to pass variables to an erb file:
erb x=1 y=2 some_conf.erb
Is it possible to render the erb file on the host machine, and then pipe the result to the guest?
If I put the erb command in a config.vm.provision "shell" , the command is run on the guest machine (which does not have Ruby), e.g.
# this command runs on the guest
# where as I want erb to run on the host
config.vm.provision "shell", inline: <<-SHELL
erb x=1 y=2 some_conf.erb > /etc/some_conf
SHELL
Vagrant file is actually a ruby script so you could use the ruby erb template engine. Make sure to create the class necessary for your template
# -*- mode: ruby -*-
# vi: set ft=ruby :
require 'erb'
Vagrant.configure("2") do |config|
template = ERB.new File.read("template/some_conf.erb")
p template.result(binding)
end
If you don't want to set up the new class etc and you have ruby2.2 installed you can just call erb from CLI directly, it will run on your host not the guest
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
exec ('erb x=1 y=2 template/some_conf.erb > some_conf')
end
once the some_conf file is generated on the host, you can use the vagrant file provisioner to push this single file on the host
config.vm.provision "file", source: "some_conf", destination: "/somewhere/on/the/guest/some_conf"
Ok, i'm very new to Ruby (i come from PHP, Symfony2 and AngularJS) and relatively new when it comes to properly writing Vagrantfiles. I'm trying to create a multi-machine environment while trying to stick to DRY principles.
As i read that Vagrantfiles understand Ruby syntax, i looked up the way Ruby defines associative arrays. This happened to be quite easy, apparently not.
My Vagrantfile:
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
#hash for boxes: 'box_name' => 'last_ip_octet'
boxes = {
'frontend' => '10',
'qp' => '11'
}
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "chef/ubuntu-14.04"
#All machines, see the hash defined in top of the Vagrantfile for all the boxes
boxes.each do |key, value|
config.vm.define "#{key}.qp" do |#{key}_qp|
#{key}_qp.vm.network "private_network", ip: "192.168.51.#{value}"
#{key}_qp.vm.provision "shell", path: "../provisioning/agentinstall.sh"
#{key}_qp.vm.synced_folder "./share/#{key}.qp", "/var/www/html"
end
end
end
My problem reads as follows:
There is a syntax error in the following Vagrantfile. The syntax error
message is reproduced below for convenience:
/Users/Zowie/Documents/vagrant/project/temp/Vagrantfile:30: syntax error, unexpected keyword_end, expecting '|'
end
^
Unfortunately, i can't find any info on using Hashes or anything similar in Vagrantfiles.
I really hope you can help me out, because i'd not feel good while writing a super-long Vagrantfile with a lot of repetitions...
Thanks in advance!
The Stackoverflow website answered my question for me!
Thanks to Stackoverflow's code block feature, i noticed that my machine-specific configurations were commented out because i used a '#'.
I fixed it by using the following syntax in my loop (which is also easier to read):
boxes.each do |key, value|
config.vm.define "#{key}.qp" do |node|
node.vm.network "private_network", ip: "192.168.51.#{value}"
node.vm.provision "shell", path: "../provisioning/agentinstall.sh"
node.vm.synced_folder "./share/#{key}.qp", "/var/www/html"
end
end