Hi I'm trying to add a Directory Index directive to the default VirtualHost for Apache from the Vagrantfile. I'm wondering if there is a way to edit a file from the Vagrantfile (I'm usung inline SHELL). I know I could copy an entire VH file to the guest machine, but I want to know how to write into files if possible.
Thanks!
You can do that with ansible like this:
config.vm.provision "ansible_local" do |ansible|
ansible.verbose = "vv"
ansible.become = true # execute as root
ansible.playbook = "relative_path_to_ansible_file/playbook.yml"
end
or with a shell
Vagrant.configure("2") do |config|
config.vm.provision "shell" do |s|
s.inline = "echo $1"
s.args = "'hello, world!'"
end
end
https://www.vagrantup.com/docs/provisioning/shell.html
My vagrantfile looks like this:
# -*- mode: ruby -*-
# vi: set ft=ruby :
vagrant_home = "/home/vagrant/"
local_share = "#{ENV['HOME']}"
unless Vagrant.has_plugin?("vagrant-vbguest")
puts "Vagrant plugin 'vagrant-vbguest' is not installed!"
puts "Execute: vagrant plugin install vagrant-vbguest"
end
unless Vagrant.has_plugin?("vagrant-sshfs")
puts "Vagrant plugin 'vagrant-sshfs' is not installed!"
puts "Execute: vagrant plugin install vagrant-sshfs"
end
Vagrant.configure("2") do |stage|
stage.vm.box = "centos/7"
stage.vm.hostname = "HSS-IAAS-VB"
stage.vm.box_check_update = true
stage.vm.network "private_network", :type => 'dhcp'
stage.vm.provider "virtualbox" do |vb|
vb.name = "centos7-dev"
vb.gui = false
vb.memory = "1024"
stage.ssh.keys_only = false
stage.ssh.username = "#{ENV['USER']}"
stage.ssh.forward_agent = true
stage.ssh.insert_key = true
stage.ssh.private_key_path = "#{ENV['HOME']}/.ssh/id_rsa" , "/home/#{ENV['USER']}/.ssh/id_rsa
stage.vm.provision :shell, privileged: false do |s|
ssh_pub_key = File.readlines("#{Dir.home}/.ssh/id_rsa.pub").first.strip
s.inline = <<-SHELL
echo #{ssh_pub_key} >> #{ENV['home']}.ssh/authorized_keys
sudo bash -c \"echo #{ssh_pub_key} >> #{ENV['home']}/.ssh/authorized_keys\"
SHELL
end
end
end
My issue is that when I run this vagrantfile, I receive an error that states the following: default: Warning: Authentication failure. Retrying... and if I run in debug mode I just see a bunch of timeouts..
All that I am trying to do is rather than create a "vagrant" user, I want to create a user that is the same as the user on the host machine by using #{ENV['USER']} and have the user immediately be able to run vagrant ssh and if their host user is test.user, then the guest user will be test.user..
vagrant ssh-config was:
Host default
HostName 127.0.0.1
User aaron.west
Port 2200
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /Users/aaron.west/.ssh/id_rsa
IdentityFile /Users/aaron.west/.ssh/id_rsa
LogLevel FATAL
all help is appreciated :)
I believe you'll have to create a new user on your Vagrant machine. As per the docs for the ssh.username setting, it doesn't sound like that setting actually creates a user. It only helps you to tell Vagrant what user to connect as, if the box was made with a username other than vagrant.
You probably need to shell out to useradd during provisioning.
I'm getting this error during vagrant up
There are errors in the configuration of this machine. Please fix
the following errors and try again:
SSH:
* `private_key_path` file must exist: insecure_key
How do I setup the private key in order to ssh into use vagrant ssh? I'm using Windows 7.
My vagrant file
Vagrant.configure("2") do |config|
config.vm.define "phusion" do |v|
v.vm.provider "docker" do |d|
d.cmd = ["/sbin/my_init", "--enable-insecure-key"]
d.image = "phusion/baseimage"
d.name = 'dockerizedvm'
d.has_ssh = true
#d.force_host_vm = true
end
v.ssh.port = 22
v.ssh.username = 'root'
v.ssh.private_key_path = 'insecure_key'
v.vm.provision "shell", inline: "echo hello"
#v.vm.synced_folder "./keys", "/vagrant"
end
end
So in my case I was using cygwin with windows, and I received:
* `private_key_path` file must exist:
C:\cygwin64\home\basic.user/.vagrant.d/insecure_private_key
After a few minutes of investigation I realized the VAGRANT_HOME environment variable was not ok, so exporting the right environment variable did the job:
VAGRANT_HOME=/cygdrive/c/Users/basic.user
export VAGRANT_HOME
insecure_key should be a file containing an SSH key. The file should be in the same folder where you vagrant up. The following is an alternative:
curl -o insecure_key -fSL https://github.com/phusion/baseimage-docker/raw/master/image/insecure_key
chmod 600 insecure_key
vagrant ssh
I'm trying to have my vagrant configuration run a different shell script for each machine in my Multi-Machine environment.
I have a definition for smartos as well as one for centos, however I want to run a different shell provider configuration for each, before running the same chef-solo provider configuration on both.
#!/usr/bin/env ruby
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
$smartos_script = <<-SHELL
echo "http://10.40.95.5" > /opt/local/etc/pkgin/repositories.conf
rm -rf /var/db/pkgin && pkgin -y update
SHELL
$centos_script = <<-SHELL
touch /opt/my_file
SHELL
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.berkshelf.enabled = true
config.ssh.forward_agent = true
config.vm.define :smartos do |smartos|
smartos.vm.box = "smartos"
smartos.vm.box_url = 'http://dlc-int.openindiana.org/aszeszo/vagrant/smartos-base1310-64-virtualbox-20130806.box'
smartos.vm.guest = :solaris
config.vm.provision :shell do |shell|
shell.inline = $smartos_script
end
end
config.vm.define :centos do |centos|
centos.vm.box = "centos"
centos.vm.box_url = 'http://dlc-int.openindiana.org/aszeszo/vagrant/smartos-base1310-64-virtualbox-20130806.box'
config.vm.provision :shell do |shell|
shell.inline = $centos_script
end
end
config.vm.provision :chef_solo do |chef|
chef.add_recipe 'test'
end
end
I have also tried using smartos.vm.provision instead of config, but have seen no difference.
Does anyone have any idea how I can do this?
You were on the right track with
I have also tried using smartos.vm.provision instead of config
Try this simple Vagrantfile out
$smartos_script = <<-SHELL
touch /opt/foo
SHELL
$centos_script = <<-SHELL
touch /opt/bar
SHELL
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define :smartos do |smartos|
smartos.vm.box = "smartos"
smartos.vm.box_url = 'http://dlc-int.openindiana.org/aszeszo/vagrant/smartos-base1310-64-virtualbox-20130806.box'
smartos.vm.provision :shell do |shell|
shell.inline = $smartos_script
end
end
config.vm.define :centos do |centos|
centos.vm.box = "centos"
centos.vm.box_url = 'http://dlc-int.openindiana.org/aszeszo/vagrant/smartos-base1310-64-virtualbox-20130806.box'
centos.vm.provision :shell do |shell|
shell.inline = $centos_script
end
end
end
When you run "vagrant up" and ssh into a machine, e.g. vagrant ssh smartos and cd to /opt you will see that the file "foo" has been created. And when you ssh into to cents machine you see that the file "bar" is created.
I'd like the question to be answered in general, but to illustrate it, here's a use case:
I'm using Vagrant for a simple LMAP project. I use standalone Puppet for provisioning. Now, there might be some developers who sit behind a proxy and they would need some additional configuration to be made to the VM. I have things working on the Puppet side: I can pass the proxy IP (if any) as a fact to puppet in the Vagrantfile and Puppet reacts accordingly if it's set.
The only issue I have is: how can developers specify/override this setting for their development environment without having to change the Vagrantfile (which is under version control and must remain dev-environment-neutral)?
If would be awesome if people could override some Vagrant settings in a file called e.g. Vagrantfile.local, which I would exclude via .gitignore.
Since a Vagrantfile is just Ruby, I tried the following:
# Also load per-dev custom vagrant config
custom_vagrantfile = 'Vagrantfile.local'
load custom_vagrantfile if File.exist?(custom_vagrantfile)
The file inclusion basically works, but it looks like in the included file, I'm not in the same Vagrant context anymore...
Vagrant::Config.run do |config|
config.vm.provision :puppet do |puppet|
puppet.facter = { "proxy" => "proxy.host:80" }
end
end
... also "resets" all other puppet config values I made in the main Vagrantfile, which makes me think I'm heading in the wrong direction here. I should note that I'm a total noob at Ruby ;)
Can anyone give me a hint or even a working solution for how per-dev customization could be done here in general?
The Vagrantfile is just Ruby, so YAML is another option.
For example, in the Vagrantfile I do this:
# -*- mode: ruby -*-
# vi: set ft=ruby :
require 'yaml'
settings = YAML.load_file 'vagrant.yml'
db_ip_address = settings['db']['ip_address']
api_ip_address = settings['api']['ip_address']
Vagrant.configure("2") do |config|
config.vm.box = "ffuenf/ubuntu-13.10-server-amd64"
config.vm.box_url = "https://vagrantcloud.com/ffuenf/ubuntu-13.10-server-amd64/version/4/provider/virtualbox.box"
config.vm.define "db" do |db|
db.vm.synced_folder settings['db']['artifacts_dir']['host'], settings['db']['artifacts_dir']['guest']
db.vm.network "private_network", ip: db_ip_address
... other stuff ...
end
config.vm.define "api" do |api|
api.vm.synced_folder settings['api']['artifacts_dir']['host'], settings['api']['artifacts_dir']['guest']
api.vm.network "private_network", ip: api_ip_address
api.vm.network "forwarded_port", guest: settings['api']['forwarded_port']['guest'], host: settings['api']['forwarded_port']['host']
end
end
Then I have a vagrant.yml file (I just made up the name; you can use whatever name you like) for the developer-specific configuration:
db:
ip_address: 192.168.4.14
artifacts_dir:
host: /Users/willie/myapp/db-scripts
guest: /opt/myapp/db
api:
ip_address: 192.168.4.15
forwarded_port:
host: 9080
guest: 8080
artifacts_dir:
host: /Users/willie/myapp/artifacts
guest: /opt/myapp/api
I would suggest using environment variables to dynamically change the behavior of the Vagrantfile without editing the file itself.
To give a real world example, here's how you could use an Ubuntu base box by default but have an environment variable define an alternative Linux distribution:
if ENV['OPERATINGSYSTEM']
if ENV['OPERATINGSYSTEM'].downcase == 'redhat'
os_name = 'centos'
config.vm.box = 'centos'
config.vm.box_url = 'https://dl.dropbox.com/u/7225008/Vagrant/CentOS-6.3-x86_64-minimal.box'
else
raise(Exception, "undefined operatingsystem: #{ENV['OPERATINGSYSTEM']}")
end
else
os_name = 'precise64'
config.vm.box = 'precise64'
config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
end
This example comes from https://github.com/puppetlabs/puppetlabs-openstack_dev_env
If you are prepared to define settings that are applied to all your vagrant boxes it's worth noting that, "Vagrant actually loads a series of Vagrantfiles, merging the settings as it goes." (ref https://docs.vagrantup.com/v2/vagrantfile/)
So I have the following defined in ~/.vagrant.d/Vagrantfile to increase the amount of RAM for my Vagrant boxes:
Vagrant.configure(2) do |config|
config.vm.provider "virtualbox" do |vb|
vb.memory = 2048
end
end
Here's an idea. It may be "ugly" and "wrong", but, at least, it works :)
# file2.rb, this is your per-dev configuration file
puts "included external file which uses outer var: #{foo}"
# file1.rb, this would be your Vagrantfile
puts 'first'
foo = 'bar'
external = File.read 'file2.rb'
eval external
puts 'second'
Let's run that
$ ruby file1.rb
first
included external file which uses outer var: bar
second
Adapting to your example, file2.rb would contain only usage of config without defining it (config will be provided from outer context)
config.vm.provision :puppet do |puppet|
puppet.facter = { "proxy" => "proxy.host:80" }
end
And your Vagrant file may look like this:
Vagrant::Config.run do |config|
external = File.read 'Vagrantfile.local'
eval external
# proceed with general settings here
config.vm.provision :puppet do |puppet|
puppet.facter = { "proxy" => "proxy.host:80" }
end
end
Update (another, "data-driven" approach)
# Vagranfile.local
config_values[:puppet][:facter][:proxy] = 'proxy.host:80'
# Vargantfile
Vagrant::Config.run do |config|
config_values = {
puppet: {
facter: {
proxy: nil
},
manifests_file: 'my_manifest.pp'
}
}
external = File.read 'Vagrantfile.local'
eval external # this should overwrite proxy config
# proceed with general settings here
config.vm.provision :puppet do |puppet|
if config_values[:puppet][:facter][:proxy]
puppet.facter = { "proxy" => config_values[:puppet][:facter][:proxy] }
end
puppet.manifests_file = config_values[:puppet][:manifests_file]
end
end
I believe that's the exact use case that Nugrant plugin was created to solve. It allows each of your devs to have a .vagrantuser (which is a .gitignore-ed file) in YAML specifying custom configuration values then reference these values with ease in Vagrantfile.
In your case, a proxied developer would have their .vagrantuser file looking like this:
proxy: 'proxy.host:80'
And your Vagrantfile would look like this (pseudo code, I don't really know ruby):
Vagrant::Config.run do |config|
config.vm.provision :puppet do |puppet|
if config.user.has_key?('proxy')
puppet.facter = { "proxy" => config.user.proxy }
end
end
end
You should bundle a sample/reference vagrantuser (i.e. vagrantuser.example) file for your devs to copy and adjust to their environment.
To extend on #Willie Wheeler 's answer. My setup is:
Root
|-- defaults.yml
|-- env.yml
|-- Vagrantfile
Vagrantfile
# Load local env config
require 'yaml'
dir = File.dirname(File.expand_path(__FILE__))
# defaults
settings = YAML::load_file("#{dir}/defaults.yml")
if File.exist?("#{dir}/env.yml")
env_settings = YAML::load_file("#{dir}/env.yml")
settings.merge!(env_settings)
end
...
# Customize the amount of memory on the VM:
vb.memory = settings["vb"]["memory"]
defaults.yml
vb:
memory: 1024
env.yml
vb:
memory: 204
This will merge whatever defaults you have with your per-dev config. Also it is clear to developers what values they can actually change
Consider using vagrant-proxyconf plugin. It allows to set proxy for all Vagrant VMs globally.
Another solution is to run external shell script during provisioning. I use separate config.vm.provision section at the beginning of Vagrantfile to do it:
# reset: true below is needed to reset the connection to the VM so that new
# environment variables set in /etc/environment will be picked up in next
# provisioning steps
config.vm.provision "shell", reset: true, inline: <<-SHELL
if [ -f /vagrant/Vagrantfile-settings.sh ]
then
/vagrant/Vagrantfile-settings.sh
fi
SHELL
Then just put a Vagrantfile-settings.sh file next to Vagrantfile, add it to .gitignore (or whatever) and put any script inside, for example to set proxy for interactive terminal, all daemons and docker containers:
# Proxy for interactive terminals
echo "http_proxy=http://PROXY_ADDRESS:PROXY_PORT" >> /etc/environment
echo "https_proxy=http://PROXY_ADDRESS:PROXY_PORT" >> /etc/environment
echo "no_proxy=127.0.0.1,localhost" >> /etc/environment
# Proxy for daemons (e.g. Docker deamon - used to pull images, apt - run from default daily cron job)
mkdir /etc/systemd/system.conf.d
echo [Manager] > /etc/systemd/system.conf.d/01-http-proxy.conf
echo "DefaultEnvironment=\"http_proxy=PROXY_ADDRESS:PROXY_PORT\"" >> /etc/systemd/system.conf.d/01-http-proxy.conf
echo "DefaultEnvironment=\"https_proxy=PROXY_ADDRESS:PROXY_PORT\"" >> /etc/systemd/system.conf.d/01-http-proxy.conf
echo "DefaultEnvironment=\"no_proxy=127.0.0.1,localhost\"" >> /etc/systemd/system.conf.d/01-http-proxy.conf
echo "# Docker requires upper-case http proxy environment variables..." >> /etc/systemd/system.conf.d/01-http-proxy.conf
echo "DefaultEnvironment=\"HTTP_PROXY=http://PROXY_ADDRESS:PROXY_PORT2\"" >> /etc/systemd/system.conf.d/01-http-proxy.conf
echo "DefaultEnvironment=\"HTTPS_PROXY=http://PROXY_ADDRESS:PROXY_PORT\"" >> /etc/systemd/system.conf.d/01-http-proxy.conf
echo "DefaultEnvironment=\"NO_PROXY=127.0.0.1,localhost\"" >> /etc/systemd/system.conf.d/01-http-proxy.conf
# Proxy for docker containers started with `docker run`
mkdir /home/vagrant/.docker
cat <<EOF > /home/vagrant/.docker/config.json
{
"proxies": {
"default": {
"httpProxy": "http:/PROXY_ADDRESS:PROXY_PORT",
"httpsProxy": "http://PROXY_ADDRESS:PROXY_PORT",
"noProxy": "127.0.0.1,localhost"
}
}
}
EOF
chown -R vagrant:vagrant /home/vagrant/.docker
You can load the settings from YAML file. This is demonstrated in Drupal VM as below:
# Use config.yml for basic VM configuration.
require 'yaml'
dir = File.dirname(File.expand_path(__FILE__))
if !File.exist?("#{dir}/config.yml")
raise 'Configuration file not found! Please copy example.config.yml to config.yml and try again.'
end
vconfig = YAML::load_file("#{dir}/config.yml")
So then you can create config.yml like:
vagrant_box: geerlingguy/ubuntu1404
vagrant_user: vagrant
vagrant_ip: 192.168.88.88
and in Vagrantfile you can use variables as:
config.vm.box = vconfig['vagrant_box']
config.vm.network "private_network", ip: vconfig['vagrant_ip']