Skip to content

Instantly share code, notes, and snippets.

@ticean
Forked from fnichol/README.md
Created December 28, 2011 23:57
Show Gist options
  • Save ticean/1530538 to your computer and use it in GitHub Desktop.
Save ticean/1530538 to your computer and use it in GitHub Desktop.
Vagrantify: Create a chef-solo enabled Vagrant virtual machine for development

Installation

gem install thor
mkdir -p ~/vagrants && cd ~/vagrants
curl -LO https://raw.github.com/gist/1528832/vagrantify
chmod 755 vagrantify

Usage

./vagrantify init webserver

Creates a Vagrant VM project that looks like:

  webserver
  ├── Gemfile
  ├── Gemfile.lock
  ├── Vagrantfile
  └── chef-repo
      ├── Cheffile
      ├── Cheffile.lock
      ├── cookbooks
      │   ├── solo_data_bags
      │   │   ├── CHANGELOG.md
      │   │   ├── README.md
      │   │   ├── libraries
      │   │   ├── metadata.json
      │   │   ├── metadata.rb
      │   │   └── recipes
      │   └── user
      │       ├── CHANGELOG.md
      │       ├── README.md
      │       ├── attributes
      │       ├── metadata.json
      │       ├── metadata.rb
      │       ├── providers
      │       ├── recipes
      │       ├── resources
      │       └── templates
      ├── data_bags
      │   └── users
      │       └── fnichol.json
      └── roles
#!/usr/bin/env ruby
require 'rubygems'
require 'thor'
class Vagrantify < Thor
include Thor::Actions
desc "init VM_NAME", "Initializes a Vagrant VM Project"
def init(name)
@vm_name = name
@chef_repo = "#{vm_name}/chef-repo"
empty_directory vm_name
bundlerize
create_chef_repo
create_vagrantfile
end
private
attr_reader :vm_name
attr_reader :chef_repo
def bundlerize
create_gemfile
install_bundler
inside vm_name do
run "bundle install"
end
git_init
end
def create_gemfile
create_file "#{vm_name}/Gemfile", <<-GEMFILE.gsub(/^ {6}/, '')
source "http://rubygems.org"
gem 'vagrant'
gem 'vagrant-butter'
gem 'librarian'
GEMFILE
end
def install_bundler
run "gem install bundler" unless %x[gem list --no-versions] =~ /^bundler$/
end
def create_chef_repo
empty_directory chef_repo
%w{.chef cookbooks data_bags roles tmp}.each do |dir|
empty_directory "#{chef_repo}/#{dir}"
end
create_rvmrc
create_knife_rb
create_cheffile
create_user_json
inside chef_repo do
run "librarian-chef install --clean"
end
end
def create_rvmrc
create_file "#{chef_repo}/.rvmrc", <<-RVMRC.gsub(/^ {6}/, '')
#!/usr/bin/env bash
# This is an RVM Project .rvmrc file, used to automatically load the ruby
# development environment upon cd'ing into the directory
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
environment_id="default"
#
# Uncomment following line if you want options to be set only for given project.
#
# PROJECT_JRUBY_OPTS=( --1.9 )
#
# First we attempt to load the desired environment directly from the environment
# file. This is very fast and efficient compared to running through the entire
# CLI and selector. If you want feedback on which environment was used then
# insert the word 'use' after --create as this triggers verbose mode.
#
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
then
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
then
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
fi
else
# If the environment file has not yet been created, use the RVM CLI to select.
if ! rvm --create "$environment_id"
then
echo "Failed to create RVM environment '${environment_id}'."
exit 1
fi
fi
for f in ${HOME}/.chef.d/env-opscode.sh ${HOME}/.aws/env.sh ; do
if [[ -f "${f}" ]] ; then
source "$f"
fi
done ; unset f
RVMRC
end
def create_cheffile
create_file "#{chef_repo}/Cheffile", <<-CHEFFILE.gsub(/^ {6}/, '')
#!/usr/bin/env ruby
site 'http://community.opscode.com/api/v1'
cookbook 'solo_data_bags'
cookbook 'user'
CHEFFILE
end
def create_knife_rb
create_file "#{chef_repo}/.chef/knife.rb", <<-'KNIFE_RB'.gsub(/^ {6}/, '')
### Chef Solo
#
#
### Opscode Hosted Chef Server
#
# export KNIFE_USER="jdoe"
# export KNIFE_ORGNAME="acmeco"
#
# * Your Opscode client key should be at `~/.chef.d/opscode-jdoe.pem`.
# * Your Opscode validation key should be at `~/.chef.d/opscode-acmeco-validator.pem`.
#
### Chef Server
#
# export KNIFE_USER="hsolo"
# export KNIFE_SERVER_NAME="widgetinc"
# export KNIFE_SERVER_URL="https://chef.widgetinc.com"
#
# * Your Chef Server client key should be at `~/.chef.d/widgetinc-hsolo.pem`.
# * Your Chef Server validation key should be at `~/.chef.d/widgetinc-validator.pem`.
#
current_dir = File.dirname(__FILE__)
home_dir = ENV['HOME']
chef_dir = "#{home_dir}/.chef.d"
user = ENV['KNIFE_USER'] || ENV['USER']
orgname = ENV['KNIFE_ORGNAME']
server_name = ENV['KNIFE_SERVER_NAME']
server_url = ENV['KNIFE_SERVER_URL']
# path to cookbooks
cookbook_path ["#{current_dir}/../cookbooks",
"#{current_dir}/../site-cookbooks"]
# logging details
log_level :info
log_location STDOUT
# user/client and private key to authenticate to a Chef Server, if needed
node_name user
if orgname
# if KNIFE_ORGNAME is given, then we're talking to the Opscode Hosted Chef
# Server
validation_client_name "#{orgname}-validator"
client_key "#{chef_dir}/opscode-#{user}.pem"
validation_key "#{chef_dir}/opscode-#{orgname}-validator.pem"
chef_server_url "https://api.opscode.com/organizations/#{orgname}"
elsif server_name
# if KNIFE_SERVER_NAME is defined, then we're talking to a Chef Server
validation_client_name "#{server_name}-validator"
client_key "#{chef_dir}/#{server_name}-#{user}.pem"
validation_key "#{chef_dir}/#{server_name}-validator.pem"
chef_server_url server_url
end
# caching options
cache_type 'BasicFile'
cache_options( :path => "#{home_dir}/.chef/checksums" )
# new cookbook defaults
cookbook_copyright ENV['KNIFE_COOKBOOK_COPYRIGHT'] ||
%x{git config --get user.name}.chomp
cookbook_email ENV['KNIFE_COOKBOOK_EMAIL'] ||
%x{git config --get user.email}.chomp
cookbook_license "apachev2"
KNIFE_RB
end
def create_user_json
json_file = "#{chef_repo}/data_bags/users/#{ENV['USER']}.json"
empty_directory File.dirname(json_file)
create_file json_file, %[{ "id": "#{ENV['USER']}" }]
end
def create_vagrantfile
create_file "#{vm_name}/Vagrantfile", <<-VAGRANTFILE.gsub(/^ {6}/, '')
#!/usr/bin/env ruby
# coding: utf-8
include Vagrant::Butter::Helpers
Vagrant::Config.run do |config|
#{vm_boxes}
# config.vm.customize { |vm| vm.memory_size = 256 }
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = "chef-repo/cookbooks"
chef.roles_path = "chef-repo/roles"
chef.data_bags_path = "chef-repo/data_bags"
chef.log_level = :debug if ENV['vdb']
# patches
chef.add_recipe "solo_data_bags"
# LWRPs
chef.add_recipe "user"
# recipes
# chef.add_recipe "apt::cacher-client"
# chef.add_recipe "apt"
# chef.add_recipe "user::data_bag"
chef.json = {
# 'apt' => {
# 'server' => {
# 'ipaddress' => local_ip
# }
# },
# 'users' => [
# '#{ENV['USER']}'
# ]
}
end
end
VAGRANTFILE
end
def vm_boxes
other_boxes = %x[vagrant box list].split("\n").sort
default_box = other_boxes.shift
boxes = Array(%{ config.vm.box = "#{default_box}"})
other_boxes.each { |box| boxes << %{ # config.vm.box = "#{box}"} }
boxes.join("\n")
end
def git_init
create_file "#{vm_name}/.gitignore", <<-GITIGNORE.gsub(/^ {6}/, '')
/Gemfile.lock
/chef-repo/cookbooks/
/chef-repo/tmp/
GITIGNORE
inside vm_name do
run "git init" unless File.directory? ".git"
end
end
end
Vagrantify.start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment