Chef/Vagrant - how to point omnibus installer to an already downloaded file? - vagrant

Every time I vagrant destroy then vagrant up the Vagrantfile processing goes out and fetches the same old Chef it did last time.
config.omnibus.chef_version = :latest
How do I avoid downloading 34MB every single time? Sometimes I do want to restart from scratch rather than use vagrant provision.
I watched where it fetched the Chef from, downloaded it myself to
/Users/jluc/kds2/chef/vagrant/chef_11.14.6-1_amd64.deb
By commenting out the chef_version directiveI was kinda hoping to use install_url, but it doesn't seem happy with my file.
#config.omnibus.chef_version = :latest
config.omnibus.install_url = '/Users/jluc/kds2/chef/vagrant/chef_11.14.6-1_amd64.deb'
Skipping the install_url and pointing chef_version to my downloaded file did not help either.
The doc (https://github.com/schisamo/vagrant-omnibus) says install_url should be an install script. How do I use the normal install script, but use my downloaded file?
#Peter
Great. Sounds like it would work, but having trouble getting it to. I have this in an install script which I reference in the Vagrantfile It works from vagrant ssh
#!/usr/bin/env bash
dpkg --install /vagrant/chef_11.14.6-1_amd64.deb
but not from the Vagrantfile:
config.omnibus.install_url = '/vagrant/utilities/chefinstall.sh'

The vagrant-omnibus plugin allows you to give any script to install chef. So if you put the chef install into the folder where the Vagrantfile is, you could point to an install script that looks like:
#!/usr/bin/env bash
dpkg --install /vagrant/chef_11.14.6-1_amd64.deb
Put it in the same folder as your Vagrantfile. Then in your Vagranfile:
config.omnibus.chef_version = '11.14.6'
config.omnibus.install_url = './chefinstall.sh'
That should work. It's clever enough that it'll check what version of Chef is installed on the box, and only run the script if that's missing.
You could also use the vagrant cachier plugin, so it won't have to download everytime, the newest version of the omnibus plugin hooks into the cache:
config.omnibus.cache_packages = true
So if your main concern is having to download repeatably, check out vagrant-cachier

Peter's suggestion about adding chef_version makes it work just fine.
That's the correct answer, I am just leaving this write up because it gives more context on the directory structure which is something I always struggle with with Chef docs.
config.omnibus.chef_version = '11.14.6'
config.omnibus.install_url = install_url
Details:
(note: Not looking at vagrant-cachier because I am trying to limit my dependencies on non-core (Opscode) cookbooks/plugins. Getting Berkshelf stable took me the better part of a week on OSX Mavericks).
The install script, chefinstall.sh:
#!/usr/bin/env bash
dpkg --install /vagrant/chef_11.14.6-1_amd64.deb
This is my setup, directory-wise
|-- Vagrantfile
|-- chef_11.14.6-1_amd64.deb
|-- utilities
| |-- chefinstall.sh
From the host, this is what the permissions look like:
audrey:utilities jluc$ ls -l chefinstall.sh
-rwxr-xr-x 1 jluc staff 68 10 Sep 12:19 chefinstall.sh
And from the guest, just in case:
vagrant#vagrant:~$ ls -l /vagrant/utilities/chefinstall.sh
-rwxr-xr-x 1 vagrant vagrant 68 Sep 10 12:19 /vagrant/utilities/chefinstall.sh
This is what I put in the Vagrantfile, no success until I added the chef_version as per Peter's suggestion.
#relative (to Vagrantfile) on host
install_url = './utilities/chefinstall.sh'
puts "jlp:install_url:#{install_url}:"
This is what Pete found that makes it work, adding the chef_version:
config.omnibus.chef_version = '11.14.6'
config.omnibus.install_url = install_url
Before the chef_version, I found that this hack was working as well.
config.vm.provision :shell, :inline => "sudo /vagrant/utilities/chefinstall.sh"

Related

Get Puppet Modules for Vagrant

I have vagrant working and I just want to do this:
include 'stdlib'
file_line { 'ssh_key_server1' :
path => '/home/vagrant/.ssh/authorized_keys',
line => 'ssh-rsa AAAA
}
It complains about the stdlib module. So, I googled all over to solve it and found a post that recommended this:
git submodule add https://github.com/puppetlabs/puppetlabs-stdlib.git modules/stdlib
It copied the module source code from git but didn't seem to compile and vagrant won't compile it for me when I do a vagrant provision. How do I compile?
I also tried using something called librarian puppet. It seemed to want puppet installed on my host machine. Please don't make me do that. Is there another way?

Fully configured ruby development environment with vagrant

I would like to have a fully configured ruby unix development environment using Vagrant configuration and provisioning. Ideally it would refer to a simple base box (e.g., precise32) and build the environment up through provisioning in such a way thait it will easily be repeatable for other team members, can be posted to github, and can be upgraded as new versions of the different technologies are available by just changing the provisioning. I have not found any full examples of this searching the web although [Rails Dev Box][1] has some useful ideas. Most of the dev environment examples (like Rails Dev Box) do not set up the guest dev environment because they assume dev will be done on the host using a shared file strategy - or if they do the configuration by hand and then save the box rather than provisioning it.
This also needs to work both in behind a proxy as well as with no proxy.
Here are the steps I am thinking will be required:
On the host:
install virtualbox, vagrant, vagrant proxyconf
On the guest, via Vagrantfile/provisioning:
use a base unix box (e.g., precise32)
optionally set proxy variables (if proxyconf plugin is installed and http_proxy env var is set)
provision everything else (puppet, chef, or shell script)
install various unix tools (apt-get install git, etc.expo ...)
set up bash environment
set up vim environment (pathogen plugin, ruby plugins, etc.)
install rvm
install ruby 1.9, 2.0, JRuby, Rubinius
installs and configures tmux
Ideally I could push this into github, it could be cloned, then cd to new directoy, and vagrant up to have a fully configured dev environment ...
Does anyone have any examples of doing this?
My preference for doing a task like this would be to use puppet as the provisioning step in your Vagrantfile.
With something like this, you can always get something thrown together quick and dirty by just doing all the steps in a shell provisioner... but I prefer the puppet and modules approach as I've found it easier to maintain, extend and to share with the team.
I've experimented with a couple of different ways of doing the provisioning with Ruby and rvm as you mentioned;
Theres the rvm puppet module by maestrodev which allows you to configure many of rvms core features: ruby versions, gemsets, gems and rvm wrappers. Typically to manage which puppet modules are included with a project I use the librarian-puppet gem which allows you to use a Puppetfile to specify the module and the version you require, much like bundler. This handles dependencies such as the stdlib and concat modules. This scenario requires external internet access to have been configured before provisioning so as to be able to download ruby and rubygems.
Offline installation of rvm - I made the relevant files (rvm itself, ruby and rubygems) accessible to the vagrant machine using a shared folder and turned the offline rvm instructions into a (not very good) puppet module and used that. One particular gotcha to pay attention to here is the naming of the ruby source that gets installed; the extension has to be .tar.bz2, its described in the list.
Additionally for your other provisioning steps you can build up puppet modules yourself for your additional requirements: vim / tmux etc and keep this versioned separately in git. You can get pretty far with modules with just the 'puppet trifecta':
class vim {
package { 'vim':
ensure => installed,
}
file { '.vimrc':
ensure => file,
...
}
}
Additionally check out the puppet forge for modules which might have already been written to do what you want.
So heres an example of what you could check in:
/ Puppetfile
/ README.md
/ Vagrantfile
/ puppet
/manifests
site.pp
And the vagrant provisioner would be
Vagrant.configure("2") do |config|
config.vm.provision "puppet" do |puppet|
puppet.manifests_path = "puppet/manifests"
puppet.module_path = "puppet/modules"
puppet.manifest_file = "site.pp"
end
end
I've used a rake task before to use librarian-puppet to pull in puppet dependencies from git / puppet forge and any additional steps you might need to do before vagranting up. This way the code as configuration is all you check in.
Finally, with puppet you can use the facter and hiera tools which are very useful for keeping data out of your modules and worth having a look at as a means of refactoring once you have your initial setup working.

vagrant include plugin source in my project

I would like to minimize the setup for users of my vagrant project.
I already think that installing Virtualbox and Vagrant are too steps too many for users of my project. See here for more info on that.
Because my project depends on a few plugins, rather than require the user to use vagrant plugin install ..., I would like to automate installation of the plugins.
Question 1: Is it an ok practise to include the plugin source in my project tree, and include the plugin using Vagrant.require_plugin "plugin-dir/plugin-name"?
Question 2: Will this approach work?
The plugins I depend on are available on github so I can add them as git submodules as described here
Edit
The approach above did NOT work for the vagrant-vbguest plugin
I had a similar need and the method I went with was to add the following at the top of my Vagrantfile:
unless Vagrant.has_plugin?("vagrant-omnibus") || ARGV[0] == 'plugin'
origargs = ARGV.join(" ");
puts "Plugins not found"
exec "vagrant plugin install vagrant-omnibus;vagrant #{origargs}"
end
It doesn't really answer your questions I guess but it works for me, I found that I also needed to add sudo in front of the vagrant plugin command for my ubuntu setup, but as you don't state what OS you are running that might not be relevant.

Demand a Vagrant plugin within the Vagrantfile?

Supposed execution of a Vagrantfile requires a specific Vagrant plugin to be installed. So, basically what you need to do is
$ vagrant plugin install foobar-plugin
$ vagrant up
If you skip the first step, vagrant up fails.
Is there an option in Vagrant to make it install the plugin automatically? In other words: Is it possible to specify within a Vagrantfile which plugins to install automatically before creating and booting up the machine?
UPDATE Aug 31, 2018: See #Starx's fix below for later versions of Vagrant (1.8 and above)
Here is version based on Louis St. Amour's solution together with Rob Kinyon's comment about re-exec if a new plugin was installeed, I use it successfully in my own setup:
required_plugins = %w(vagrant-share vagrant-vbguest...)
plugins_to_install = required_plugins.select { |plugin| not Vagrant.has_plugin? plugin }
if not plugins_to_install.empty?
puts "Installing plugins: #{plugins_to_install.join(' ')}"
if system "vagrant plugin install #{plugins_to_install.join(' ')}"
exec "vagrant #{ARGV.join(' ')}"
else
abort "Installation of one or more plugins has failed. Aborting."
end
end
Since I'm a Ruby dev, and Bindler is no longer being maintained, I found it most natural to just write some code at the top of my Vagrantfile to install required plugins if missing (e.g. before Vagrant.configure line)
The following works for me:
required_plugins = %w( vagrant-hostmanager vagrant-someotherplugin )
required_plugins.each do |plugin|
system "vagrant plugin install #{plugin}" unless Vagrant.has_plugin? plugin
end
system, unlike using backticks, will echo the command to stdout, just as running the command yourself would. And this way I don't need yet another strangely named plugin or system to keep track of required plugins which can be updated by Vagrant anyway.
As I pointed out on my answer to your other question, you can use bindler for installing a set of plugins specific to a project using a single command.
If bindler is installed and the required plugin is not, bindler will error out and will abort the process. There is also an open issue related to automatically installing plugins on vagrant ups but so far no one signed up for it yet.
If you don't want to use bindler, you can make use of Vagrant.has_plugin? (available on 1.3.0+) at the top of your Vagrantfile and error out if the required plugin is not installed.
Something like:
unless Vagrant.has_plugin?("vagrant-some-plugin")
raise 'some-plugin is not installed!'
end
Vagrant.configure("2") do |config|
config.vm.box = "box-name"
end
UPDATE: Bindler is no longer supported and no equivalent funcionality has been provided by Vagrant core as of May 11th, 2015
2019 Update: Vagrant now has functionality to require plugins through the Vagrantfile via:
Vagrant.configure("2") do |config|
config.vagrant.plugins = "vagrant-some-plugin"
# or as array:
config.vagrant.plugins = ["vagrant-some-plugin", "vagrant-some-other-plugin"]
# or as hash
config.vagrant.plugins = {"vagrant-some-plugin" => {"version" => "1.0.0"}}
end
If Vagrant detects there are plugins not already installed it will prompt the user to install them itself:
$ vagrant up
Vagrant has detected project local plugins configured for this
project which are not installed.
vagrant-some-plugin
Install local plugins (Y/N) [N]: y
Installing the 'vagrant-some-plugin' plugin. This can take a few minutes...
Fetching vagrant-some-plugin-1.0.0.gem
Installed the plugin 'vagrant-some-plugin (1.0.0)'!
Vagrant has completed installing local plugins for the current Vagrant
project directory. Please run the requested command again.
See https://www.vagrantup.com/docs/vagrantfile/vagrant_settings.html
Please note that as of Vagrant 1.5, you can specify your dependencies in your Gemfile. Per the blog post on the update:
Now, Vagrant 1.5 will automatically load any gems in the "plugins"
group in your Gemfile. As an example, here is the Gemfile for a
"vagrant-bar" plugin:
source "https://rubygems.org"
group :development do
gem "vagrant",
git: "https://github.com/mitchellh/vagrant.git"
end
group :plugins do
gem "vagrant-foo",
gem "vagrant-bar", path: "."
end
Couldn't add a comment to Louis St-Amour's answer, but I wanted to post this just in case anyone needed help extending his solution.
# Check for missing plugins
required_plugins = %w(vagrant-list)
plugin_installed = false
required_plugins.each do |plugin|
unless Vagrant.has_plugin?(plugin)
system "vagrant plugin install #{plugin}"
plugin_installed = true
end
end
# If new plugins installed, restart Vagrant process
if plugin_installed === true
exec "vagrant #{ARGV.join' '}"
end
On the new version of Vagrant, answer by #Amos Shapira gets stuck in an infinite loop. The reason for that is each call to vagrant plugin install also processes the Vagrantfile and when processed executes the code relating to installing the plugin again and again and so on.
Here is my solution which avoids the loop.
# Plugins
#
# Check if the first argument to the vagrant
# command is plugin or not to avoid the loop
if ARGV[0] != 'plugin'
# Define the plugins in an array format
required_plugins = [
'vagrant-vbguest', 'vagrant-hostmanager',
'vagrant-disksize'
]
plugins_to_install = required_plugins.select { |plugin| not Vagrant.has_plugin? plugin }
if not plugins_to_install.empty?
puts "Installing plugins: #{plugins_to_install.join(' ')}"
if system "vagrant plugin install #{plugins_to_install.join(' ')}"
exec "vagrant #{ARGV.join(' ')}"
else
abort "Installation of one or more plugins has failed. Aborting."
end
end
end
I just noticed here http://docs.vagrantup.com/v2/plugins/packaging.html an instruction
Vagrant.require_plugin "vagrant-aws"
which does exactly the same thing as what descibed fgrehm: raising quickly an error if the plugin is not installed.
As far as I know, there are stil no way to auto-install plugins
My answer is very close to Louis St-Amour's answer, but instead of installing plugins automatically, it just raises an error message, so that the user has to install the plugin manually.
I would rather users be aware of any plugins that get installed, because they apply globally to all Vagrant instances, not just to the current Vagrantfile.
Put at the top of Vagrantfile one line like this for each plugin, in this example, vagrant-vbguest:
raise "vagrant-vbguest plugin must be installed" unless Vagrant.has_plugin? "vagrant-vbguest"
You could use this project (I am the author): https://github.com/DevNIX/Vagrant-dependency-manager
It's based on similar answers but trying to be more complete and stable. The big advantage of this idea is, you can distribute your Vagrantfile and it will run on every computer regardless of the installed plugins on that environment.
It is easy to use:
Copy dependency_manager.rb next to your Vagrantfile
Include it and call check_plugins passing your dependencies as an array
Example:
# -*- mode: ruby -*-
# vi: set ft=ruby :
require File.dirname(__FILE__)+"./dependency_manager"
check_plugins ["vagrant-exec", "vagrant-hostsupdater", "vagrant-cachier", "vagrant-triggers"]
Vagrant.configure(2) do |config|
config.vm.box = "base"
end
???
Profit!
I would love to merge pull requests, fix any issue you could have, and to get ideas of new features. Currently I'm thinking about updating the dependency manager itself, and requiring specific plugin versions :D
Regards!
I got a problem with new install of Vagrant, where .vagrant.d directory is not created yet. I was able to make the snippet from Luis St. Amour working by catching the exception.
required_plugins = %w(vagrant-share vagrant-vbguest)
begin
plugins_to_install = required_plugins.select { |plugin| not Vagrant.has_plugin? plugin }
if not plugins_to_install.empty?
puts "Installing plugins: #{plugins_to_install.join(' ')}"
if system "vagrant plugin install #{plugins_to_install.join(' ')}"
exec "vagrant #{ARGV.join(' ')}"
else
abort "Installation of one or more plugins has failed. Aborting."
end
end
rescue
exec "vagrant #{ARGV.join(' ')}"
end
Here's what I am using on Vagrant 1.8 and it is working fine. Put this somewhere before the configure block in your Vagrantfile.
# install required plugins if necessary
if ARGV[0] == 'up'
# add required plugins here
required_plugins = %w( plugin1 plugin2 plugin3 )
missing_plugins = []
required_plugins.each do |plugin|
missing_plugins.push(plugin) unless Vagrant.has_plugin? plugin
end
if ! missing_plugins.empty?
install_these = missing_plugins.join(' ')
puts "Found missing plugins: #{install_these}. Installing using sudo..."
exec "sudo vagrant plugin install #{install_these}; vagrant up"
end
end

Getting started with chef, and running composer install on deploy

We're looking to deploy a few Laravel4 based PHP apps on amazon with OpsWorks, this requires a few things:
Grab code from git
Download composer.phar from getcomposer.com
Run php composer.phar install
Change permissions on a few specific folders
I'm completely fresh with it comes to chef, so initially looking for a place to get to grips with the basics of chef, and then how to achieve the tasks above, would appreciate any pointers.
I'm no Chef guru (I usually use Puppet) but try the following:
Grab code from git
You may want to execute a wget command (see examples below).
If you want something more sophisticated see http://docs.opscode.com/resource_deploy.html
deploy_revision "/path/to/application" do
repo 'ssh://name-of-git-repo/repos/repo.git'
migrate false
purge_before_symlink %w{one two folder/three}
create_dirs_before_symlink []
symlinks(
"one" => "one",
"two" => "two",
"three" => "folder/three"
)
before_restart do
# some Ruby code
end
notifies :restart, "service[foo]"
notifies :restart, "service[bar]"
end
Download composer.phar from getcomposer.com
I would execute a wget.
I lifted some code from here: http://cookingclouds.com/2012/06/23/chef-simple-cookbook-example/
It's basically just doing a wget in a specific folder, extracting the contents of the tar & updating some permissions on the new files. It only does this if the folder doesn't already exist.
# Run a bash shell - download and extract composer
bash "install_composer" do
user "root"
cwd "/folder/to/extact/to"
code <<-EOH
wget http://getcomposer.com/composer.tar.gz
tar -xzf composer.tar.gz
chown -R user:group /folder/to/extact/to
EOH
not_if "test -d /folder/to/extact/to"
end
Run php composer.phar install
http://docs.opscode.com/resource_execute.html
execute "composer install" do
command "php composer.phar install && touch /var/log/.php_composer_installed"
creates "/var/log/.php_composer_installed"
action :run
end
This will only run it once, otherwise you can remove the "creates" and it will run it each time.
Change permissions on a few specific folders
http://docs.opscode.com/resource.html
directory "/tmp/folder" do
owner "root"
group "root"
mode 0755
action :create
end
If the directory already exists, nothing will happen. If the directory was changed in any way, the resource is marked as updated.
Finally
I find the search handy, browsing stuff on the Chef site seems to be hopeless (too much stuff to dig through). http://docs.opscode.com/search.html
I would go pretty much with Drew Khoury's answer, with one change. To download compose.phar, you can use the remote_file resource instead of doing a wget in a bash script.
As composer.phar is already an executable, you could simply put it to a dir in your $PATH:
remote_file '/usr/bin/composer' do
source 'http://getcomposer.org/composer.phar'
mode '0755'
action :create_if_missing
end
You can configure your git hook post-receive to something like that:
GIT_WORK_TREE=/path/to/your/site
cd /path/to/your/site
curl -sS https://getcomposer.org/installer | php
php composer.phar install
# do your stuff here
And make sure to give executable permissions to the post-receive file.
Or you can just commit your vendor directory. We have a couple projects running on Laravel 4 and OpsWorks.
I'm in the same position with Laravel and OpsWorks. I was looking for a solution but then...
What happens if someone injects a security flaw into one of the sub modules? Does that mean we trust X number of external code-bases to be 100% secure all the time?
Either there is some fundamental flaw in my understanding or running composer at all on a production server is about the most serious WTF there is.
I've now made sure that the code in my project repo will be deployed 100% as is. No downloading external modules on the production server ever.

Resources