diff --git a/vagrant/.gitignore b/vagrant/.gitignore
new file mode 100644
index 000000000000..0cbe0c9d527f
--- /dev/null
+++ b/vagrant/.gitignore
@@ -0,0 +1,5 @@
+.downloads
+.DS_STORE
+*.box
+.vagrant
+.bashrc
diff --git a/vagrant/LICENSE b/vagrant/LICENSE
new file mode 100644
index 000000000000..e138104ab753
--- /dev/null
+++ b/vagrant/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Binh Nguyen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vagrant/README.md b/vagrant/README.md
new file mode 100644
index 000000000000..0d4557f9066b
--- /dev/null
+++ b/vagrant/README.md
@@ -0,0 +1,19 @@
+Vagrant template with shell provision for Ubuntu Precise clusers with JDK 7.
+===========
+
+## Installation
+1. Install [vagrant](//www.vagrantup.com). *Tested with version 1.4.3*
+2. Install [virtualbox](//www.virtualbox.org). *Tested with version 4.2.16 but should work with any 4.+*
+3. Checkout this repo `git clone git@github.com:ngbinh/vagrant_jdk.git`
+4. Change to the directory `cd vagrant_jdk`
+5. Bring up the nodes `vagrant up`
+6. Wait a while, then make sure the nodes are up: `vagrant status`. You should see three nodes named `spark-master`, `spark-worker-1` and `spark-worker-2` running.
+7. Access the nodes with user `spark-user` and password `spark`.
+
+Note that it will take a while to download Ubuntu Precise image at the first run. Subsequent runs should not have to re-download.
+
+### Customization
+1. You can change the number of nodes, their basic parameters by modifying `Vagrantfile`.
+2. You can change the JDK version by modifying `scripts/setup.sh`
+
+
diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile
new file mode 100644
index 000000000000..e2d8f4f16b23
--- /dev/null
+++ b/vagrant/Vagrantfile
@@ -0,0 +1,65 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Using Vagrant shell scripts
+# https://github.com/StanAngeloff/vagrant-shell-scripts
+require File.join(File.dirname(__FILE__), 'scripts/vagrant-shell-scripts/vagrant')
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+Vagrant.require_version ">= 1.4.2"
+
+# the domain of all the nodes
+DOMAIN = 'local'
+
+# Ubuntu 12.04.4 LTS (Precise Pangolin) 64 bit
+BOX = 'precise64'
+BOX_URL = 'http://files.vagrantup.com/precise64.box'
+
+# define all the nodes here.
+# :host is the id in Vagrant of the node. It will also be its hostname
+# :ip the ip address of the node
+# :cpu the number of core for the node
+# :ram the amount of RAM allocated to the node in MBytes.
+NODES = [
+ { :host => 'spark-master', :ip => '192.168.2.10', :cpu => 1, :ram => '3072' },
+ { :host => 'spark-worker-1', :ip => '192.168.2.20', :cpu => 1, :ram => '2048' },
+ { :host => 'spark-worker-2', :ip => '192.168.2.21', :cpu => 1, :ram => '2048' }
+]
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ NODES.each do | node |
+ config.vm.define node[:host] do | node_config |
+ node_config.vm.box = BOX
+ node_config.vm.box_url = BOX_URL
+
+ node_config.vm.hostname = node[:host] + "." + DOMAIN
+ node_config.vm.network :private_network, ip: node[:ip]
+
+ # by default, the current folder is shared as /vagrant in the nodes
+ # you can also share an outside folder here
+ # node_config.vm.synced_folder "shared", "/shared"
+
+ memory = node[:ram] ? node[:ram] : 1024
+ cpu = node[:cpu] ? node[:cpu] : 1
+
+ node_config.vm.provider :virtualbox do | vbox |
+ vbox.gui = false
+ vbox.customize ['modifyvm', :id, '--memory', memory.to_s]
+ vbox.customize ['modifyvm', :id, '--cpus', cpu.to_s]
+
+ # fix the connection slow
+ # https://github.com/mitchellh/vagrant/issues/1807
+ vbox.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
+ vbox.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
+ end
+
+ node_config.vm.provision :shell do |shell|
+ vagrant_shell_scripts_configure(
+ shell,
+ File.dirname(__FILE__),
+ 'scripts/setup.sh')
+ end
+ end
+ end
+end
diff --git a/vagrant/copy-keys.sh b/vagrant/copy-keys.sh
new file mode 100755
index 000000000000..9889ed3bd271
--- /dev/null
+++ b/vagrant/copy-keys.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+# make sure all the nodes are up
+# vagrant up 1>/dev/null 2>&1
+
+source vagrant_nodes.sh
+
+sshpass -p "$VAGRANT_SPARK_PASSWORD" ssh-copy-id "$VAGRANT_SPARK_USER"@"$VAGRANT_SPARK_MASTER" 1>/dev/null 2>&1
+sshpass -p "$VAGRANT_SPARK_PASSWORD" ssh-copy-id "$VAGRANT_SPARK_USER"@"$VAGRANT_SPARK_WORKER_1" 1>/dev/null 2>&1
+sshpass -p "$VAGRANT_SPARK_PASSWORD" ssh-copy-id "$VAGRANT_SPARK_USER"@"$VAGRANT_SPARK_WORKER_2" 1>/dev/null 2>&1
+
diff --git a/vagrant/scripts/setup.sh b/vagrant/scripts/setup.sh
new file mode 100644
index 000000000000..cb359b8885fc
--- /dev/null
+++ b/vagrant/scripts/setup.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+<%= import 'scripts/vagrant-shell-scripts/ubuntu.sh' %>
+<%= import 'scripts/vagrant-shell-scripts/ubuntu-extras.sh' %>
+
+# }}}
+
+# Use Google Public DNS for resolving domain names.
+# The default is host-only DNS which may not be installed.
+# nameservers-local-purge
+# nameservers-append '8.8.8.8'
+# nameservers-append '8.8.4.4'
+
+# Update packages cache.
+apt-packages-update
+
+# Install VM packages.
+apt-packages-install \
+ rsync \
+ telnet \
+ wget \
+ git \
+ curl\
+ whois
+
+download_dir="/vagrant/.downloads/oracle-jdk-download"
+mkdir -p "$download_dir" && oracle-jdk-install "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com" "http://download.oracle.com/otn-pub/java/jdk/7u51-b13/jdk-7u51-linux-x64.tar.gz" "$download_dir"
+
+# create user spark if necessary
+if [ getent passwd spark-user > /dev/null 2>&1 ]; then
+ echo "user spark-user exists. Skipping create user"
+else
+ echo "creating (sudo) user spark-user"
+ sudo useradd -m -G `groups vagrant | cut -d" " -f4- | sed 's/ /,/g'` -s/bin/bash -p `mkpasswd spark` spark-user
+ echo "sucess"
+fi
+# done. Create user
diff --git a/vagrant/scripts/vagrant-shell-scripts/.gitignore b/vagrant/scripts/vagrant-shell-scripts/.gitignore
new file mode 100644
index 000000000000..72c908510186
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/.gitignore
@@ -0,0 +1,2 @@
+.bundle
+.vagrant
diff --git a/vagrant/scripts/vagrant-shell-scripts/.lvimrc b/vagrant/scripts/vagrant-shell-scripts/.lvimrc
new file mode 100644
index 000000000000..aa14f058597b
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/.lvimrc
@@ -0,0 +1,13 @@
+let s:roundup_command = 'bin/roundup'
+
+let VimuxResetSequence = "q C-c C-u"
+
+augroup runTestOnSave
+ au!
+ au BufWritePost *-test.sh call VimuxRunCommand(s:roundup_command . ' ' . expand('%:p:~:.'))
+augroup END
+
+augroup reloadLocalConfiguration
+ au!
+ au BufWritePost .lvimrc source %
+augroup END
diff --git a/vagrant/scripts/vagrant-shell-scripts/LICENSE.md b/vagrant/scripts/vagrant-shell-scripts/LICENSE.md
new file mode 100644
index 000000000000..63bc22b22453
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/LICENSE.md
@@ -0,0 +1,22 @@
+The MIT License
+===============
+
+> Copyright (c) 2011 Stan Angeloff
+>
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.
diff --git a/vagrant/scripts/vagrant-shell-scripts/README.md b/vagrant/scripts/vagrant-shell-scripts/README.md
new file mode 100644
index 000000000000..496cf802db3d
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/README.md
@@ -0,0 +1,739 @@
+vagrant-shell-scripts
+=====================
+
+A collection of scripts (Ubuntu-only at this time) to ease Vagrant box provisioning using the [shell][shell] method.
+
+ [shell]: http://vagrantup.com/v1/docs/provisioners/shell.html
+
+Usage
+-----
+
+1. Place on top of your `Vagrantfile` before `Vagrant.configure(..)`:
+
+ ```ruby
+ require File.join(File.dirname(__FILE__), 'path/to/vagrant-shell-scripts/vagrant')
+ ```
+
+2. Place at the end of your `Vagrantfile` before the last `end`:
+
+ ```ruby
+ config.vm.provision :shell do |shell|
+ vagrant_shell_scripts_configure(
+ shell,
+ File.dirname(__FILE__),
+ 'path/to/provisioning_script'
+ )
+ end
+ ```
+
+3. Place on top of your provisioning script:
+
+ ```bash
+ #!/usr/bin/env bash
+
+ <%= import 'ubuntu.sh' %>
+ ```
+
+Functions
+---------
+
+### Utility
+
+- `script-argument-create(value, expected)`
+
+ Return the value of the first argument or exit with an error message if empty.
+
+ Example:
+
+ ```bash
+ MYSQL_DBNAME=$( script-argument-create "$1" 'a MySQL database name as the first argument' )
+ ```
+
+### Nameservers
+
+- `nameservers-local-purge`
+
+ Drop all local `10.0.x.x` nameservers in `resolv.conf`.
+
+- `nameservers-append(ip)`
+
+ Set up an IP as a DNS name server if not already present in `resolv.conf`.
+
+ Example (set up Google DNS):
+
+ ```bash
+ nameservers-local-purge
+ nameservers-append '8.8.8.8'
+ nameservers-append '8.8.4.4'
+ ```
+
+### Aptitude
+
+- `apt-mirror-pick(iso2)`
+
+ Set up a specific two-letter country code as the preferred `aptitude` mirror.
+
+ Example (use Ubuntu Bulgaria as a mirror):
+
+ ```bash
+ apt-mirror-pick 'bg'
+ ```
+
+- `apt-packages-repository(repository[, repository[, ...]][, key[, server = 'keyserver.ubuntu.com']])`
+
+ Add a custom repository as a software source.
+
+ Each `repository` is a line as it would appear in your `/etc/apt/sources.list` file, e.g., `deb URL DISTRIBUTION CATEGORY`.
+
+ `key` and `server` are the signing key and server.
+ You need to add the key to your system so Ubuntu can verify the packages from the repository.
+
+ Example (install MongoDB from official repositories):
+
+ ```
+ apt-packages-repository 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' '7F0CEB10'
+ apt-packages-update
+ apt-packages-install mongodb-10gen
+ ```
+
+- `apt-packages-ppa(repository[, key[, server = 'keyserver.ubuntu.com']])`
+
+ Add a Launchpad PPA as a software source.
+
+ The `repository` is the Launchpad user and project name, e.g., `chris-lea/node.js`.
+
+ `key` and `server` are the signing key and server.
+ The key needs to added to your system so Ubuntu can verify the packages from the PPA.
+
+ Example (install Node.js from unofficial PPA):
+
+ ```bash
+ apt-packages-ppa 'chris-lea/node.js'
+ apt-packages-update
+ apt-packages-install \
+ nodejs \
+ npm
+ ```
+
+- `apt-packages-update`
+
+ Update `aptitude` packages without any prompts.
+
+- `apt-packages-install(package[, package[, ...]])`
+
+ Perform an unattended installation of package(s).
+
+ Example:
+
+ ```bash
+ apt-packages-update
+ apt-packages-install \
+ apache2-mpm-worker \
+ apache2-suexec-custom \
+ mysql-server-5.1 \
+ libapache2-mod-fastcgi \
+ php5-cgi
+ ```
+
+- `apt-packages-purge(package[, package[, ...]])`
+
+ Perform an unattended complete removal (purge) of package(s).
+
+ Example (purge `apache2` unnecessarily installed as part of the `php5` meta-package):
+
+ ```bash
+ apt-packages-update
+ apt-packages-install php5
+ apt-packages-purge 'apache2*'
+ ```
+
+### System
+
+- `system-upgrade()`
+
+ Run a complete system upgrade.
+ Be extremely careful as this operation can break packages, e.g., VirtualBox Guest Additions if a new kernel is installed.
+
+ Example:
+
+ ```bash
+ apt-packages-update
+ system-upgrade
+ ```
+
+- `system-service(name, action)`
+
+ Command a system service, e.g., `apache2`, `mysql`, etc.
+
+ Example:
+
+ ```bash
+ system-service php5-fpm restart
+ ```
+
+- `system-escape([glue = '-'])`
+
+ Escape and normalize a string so it can be used safely in file names, etc.
+ You can optionally specify `glue` to be a different character, e.g., an underscore `_` if you are using the result as part of a variable name.
+
+ Example:
+
+ ```bash
+ echo "Hello World!" | system-escape # prints 'hello-world'
+ ```
+
+### Default Commands
+
+- `alternatives-ruby-install(version[, bin_path = '/usr/bin/'[, man_path = '/usr/share/man/man1/'[, priority = 500]]])`
+
+ Update the Ruby binary link to point to a specific version.
+
+ Example:
+
+ ```bash
+ apt-packages-install \
+ ruby1.9.1 \
+ ruby1.9.1-dev \
+ rubygems1.9.1
+ alternatives-ruby-install 1.9.1
+ ```
+
+- `alternatives-ruby-gems()`
+
+ Create symbolic links to RubyGems binaries.
+
+ By default, RubyGems on Ubuntu does not create binaries on `$PATH`.
+ Using this function would create a symbolic link in the directory of your `ruby` binary which is assumed to be on `$PATH`.
+
+ Example (install stable versions of Sass and link it as `/usr/bin/sass`):
+
+ ```bash
+ apt-packages-install \
+ ruby1.9.1 \
+ ruby1.9.1-dev \
+ rubygems1.9.1
+ alternatives-ruby-install 1.9.1
+ github-gems-install 'nex3/sass'
+ alternatives-ruby-gems 'sass'
+ ```
+
+### Apache
+
+- `apache-modules-enable(module[, module[, ...]])`
+
+ Enable a list of Apache modules. This requires a server restart.
+
+- `apache-modules-disable(module[, module[, ...]])`
+
+ Disable a list of Apache modules. This requires a server restart.
+
+- `apache-sites-enable(name[, name[, ...]])`
+
+ Enable a list of Apache sites. This requires a server restart.
+
+- `apache-sites-disable(name[, name[, ...]])`
+
+ Disable a list of Apache sites. This requires a server restart.
+
+- `[PHP=/path/to/binary] apache-sites-create(name[, path = name[, user = name[, group = user[, verbosity = info]]]])`
+
+ Create a new Apache site and set up Fast-CGI components.
+
+ The function creates a new file under `sites-available/name` where `name` is the first argument to the function.
+
+ To set up Fact-CGI, a new directory `.cgi-bin` is created in `path` if it doesn't already exist.
+
+ The virtual host is pointed to `path` or `/name` if `path` is omitted.
+
+ **SuExec is required** and a user and group options are set up so permissions can work properly.
+
+ If you prefix the function with `PHP=/path/to/binary`, PHP will be enabled through a Fast-CGI script in `.cgi-bin`. You must have PHP installed.
+
+ Example (create a new `vagrant` website from `/vagrant` and enable PHP):
+
+ ```bash
+ PHP=/usr/bin/php-cgi apache-sites-create 'vagrant'
+ apache-sites-enable vagrant
+ apache-restart
+ ```
+
+- `apache-restart`
+
+ Restart the Apache server and reload with new configuration.
+
+ Example:
+
+ ```bash
+ apache-modules-enable actions rewrite fastcgi suexec
+ apache-restart
+ ```
+
+### Nginx
+
+- `nginx-sites-enable(name[, name[, ...]])`
+
+ Enable a list of Nginx sites. This requires a server restart.
+
+- `nginx-sites-disable(name[, name[, ...]])`
+
+ Disable a list of Nginx sites. This requires a server restart.
+
+- `[PHP=any-value] nginx-sites-create(name[, path = name[, user = name[, group = user[, index = 'index.html'[, verbosity = info]]]]])`
+
+ Create a new Nginx site and set up Fast-CGI components.
+
+ The function creates a new file under `sites-available/name` where `name` is the first argument to the function.
+
+ The virtual host is pointed to `path` or `/name` if `path` is omitted.
+
+ If you prefix the function with `PHP=any-value`, PHP will be enabled through a PHP-FPM. You must have `php5-fpm` installed.
+
+ The arguments `user` and `group` are used to re-configure PHP-FPM's default `www` pool to run under the given account.
+
+ You can optionally specify space-separated directory index files to look for if a file name wasn't specified in the request.
+
+ Example (create a new `vagrant` website from `/vagrant` and enable PHP):
+
+ ```bash
+ PHP=/usr/bin/php5-fpm nginx-sites-create 'vagrant'
+ nginx-sites-enable vagrant
+ nginx-restart
+ ```
+
+### PHP
+
+- `php-settings-update(name, value)`
+
+ Update a PHP setting value.
+ This function will look for all `php.ini` files in `/etc`.
+ For each file, a `conf.d` directory would be created in the parent directory (if one doesn't already exist) and inside a file specifying the setting name/value will be placed.
+
+ Example (create a default timezone):
+
+ ```bash
+ php-settings-update 'date.timezone' 'Europe/London'
+ ```
+
+- `php-pecl-install(extension[, extension[, ...]])`
+
+ Install (download, build, install) and enable a PECL extension.
+
+ You may optionally specify the state/version using '@version'.
+
+ Example (install MongoDB driver):
+
+ ```bash
+ apt-packages-install \
+ php5-dev \
+ php-pear
+ php-pecl-install mongo
+
+ # Install a specific version of 'proctitle'.
+ php-pecl-install proctitle@0.1.2
+ ```
+
+- `php-fpm-restart`
+
+ Restart the PHP5-FPM server.
+
+### MySQL
+
+- `mysql-database-create(name[, charset = 'utf8'[, collision = 'utf8_general_ci']])`
+
+ Create a database if one doesn't already exist.
+
+- `mysql-database-restore(name, path)`
+
+ Restore a MySQL database from an archived backup.
+
+ This function scans for files in `path` (non-recursive) that match the format:
+
+ ```
+ ^[0-9]{8}-[0-9]{4}.tar.bz2$
+ ```
+
+ e.g., `20120101-1200.tar.bz2`. The matching files are sorted based on the file name and the newest one is picked.
+
+ If the database `name` is empty, i.e., it doesn't contain any tables, the latest backup is piped to `mysql`.
+
+ Example (where `/database-backups` is shared from `Vagrantfile`):
+
+ ```bash
+ mysql-database-restore 'project' '/database-backups'
+ ```
+
+- `mysql-remote-access-allow`
+
+ Allow remote passwordless `root` access for anywhere.
+
+ This is only a good idea if the box is configured in 'Host-Only' network mode.
+
+- `mysql-restart`
+
+ Restart the MySQL server and reload with new configuration.
+
+### RubyGems
+
+- `ruby-gems-version(package)`
+
+ Check the installed version of a package, if any.
+
+ When a package is not installed, `0.0.0` is returned.
+
+- `ruby-gems-install(package[, arg[, ...]])`
+
+ Perform an unattended installation of a package.
+
+ If a package is already installed, it will not be re-installed or upgraded.
+
+ Example:
+
+ ```bash
+ apt-packages-install \
+ ruby1.9.1 \
+ ruby1.9.1-dev \
+ rubygems1.9.1
+ alternatives-ruby-install 1.9.1
+ ruby-gems-install pkg-config
+ ruby-gems-install sass --version '3.2.1'
+ ```
+
+### NPM (Node Package Manager)
+
+- `npm-packages-install(package[, package[, ...]])`
+
+ Perform an unattended **global** installation of package(s).
+
+ Example (install UglifyJS):
+
+ ```bash
+ apt-packages-ppa 'chris-lea/node.js'
+ apt-packages-update
+ apt-packages-install \
+ nodejs \
+ npm
+ npm-packages-install uglify-js
+ ```
+
+### GitHub
+
+- `github-gems-install(repository[, repository[, ...]])`
+
+ Download and install RubyGems from GitHub.
+
+ The format of each `repository` is `user/project[@branch]` where `branch` can be omitted and defaults to `master`.
+
+ If a package is already installed, it will not be re-installed or upgraded.
+
+ Example (install unstable versions of Sass and Compass):
+
+ ```bash
+ apt-packages-install \
+ ruby1.9.1 \
+ ruby1.9.1-dev \
+ rubygems1.9.1
+ alternatives-ruby-install 1.9.1
+ github-gems-install \
+ 'ttilley/fssm' \
+ 'nex3/sass@master' \
+ 'wvanbergen/chunky_png' \
+ 'chriseppstein/compass@master'
+ ```
+
+- `github-php-extension-install(specification[, specification[, ...]])`
+
+ Download and install PHP extensions from GitHub.
+
+ The `specification` is a string which contains the repository name (mandatory), version (optional) and `./configure` arguments (optional):
+ `repository@version --option --option argument`
+
+ Example (install native PHP Redis extension from GitHub):
+
+ ```bash
+ github-php-extension-install 'nicolasff/phpredis'
+
+ # Use a specific commit and pass arguments to `./configure`.
+ github-php-extension-install 'nicolasff/phpredis@5e5fa7895f --enable-redis-igbinary'
+ ```
+
+### Environment
+
+- `env-append(env_key, env_value[, env_comment])`
+
+ Append an environment line to the global Bash/Zsh profile.
+
+ `env_key` can be anything, but the following values have special meaning:
+
+ * `PATH` - extend the `PATH` environment variable with a new directory,
+ * `source` - include an external file (be careful not to `set -e`).
+
+ Any other key would be `export`ed when a new session is initialized.
+
+ Example (set `JAVA_HOME` for scripts that rely on it):
+
+ ```bash
+ env-append 'JAVA_HOME' "/usr/lib/jvm/java-7-openjdk-$( uname -i )"
+
+ # $ tail -2 /etc/profile
+ # # AUTO-GENERATED: JAVA_HOME.
+ # [ -z "$JAVA_HOME" ] && export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-i386'
+ ```
+
+Extras
+------
+
+The `ubuntu-extras.sh` file provides useful but rarely used commands.
+
+### Archives
+
+- `archive-file-unpack(file[, directory])`
+
+ Unpack the given archive `file` in `directory` (created if missing). The format is guessed from the file extension.
+
+ Example:
+
+ ```bash
+ archive-file-unpack 'rsync-HEAD.tar.gz' '/tmp/'
+ ```
+
+### Packages (e.g., ZIP distributions)
+
+- `package-ignore-preserve(package_name, package_path, preserved_path)`
+
+ Read a `.gitignore` file in the given `package_path` and remove matching files in `{preserved_path}/{package_name}-*`.
+ This is useful when the contents of an unpacked archive are to be copied over a version-controlled directory and certain files should **not** be overwritten.
+
+ Example:
+
+ ```bash
+ package-ignore-preserve 'hadoop' 'vendor/hadoop' '/tmp/hadoop-download'
+ ```
+
+- `package-uri-download(uri[, target])`
+
+ Download the file at `uri` to the given directory `target` or `STDOUT`.
+
+ Example:
+
+ ```bash
+ package-uri-download 'http://www.samba.org/ftp/rsync/nightly/rsync-HEAD.tar.gz' '/tmp'
+ ```
+
+- `package-uri-install(package_name, package_uri[, package_index[, package_path[, package_version]]])`
+
+ Download, unpack and install the package at `package_uri` to `package_path`.
+ This function does a lot internally and can be used to automate installations of certain ZIP distributions.
+ The URI and path support placeholders:
+
+ * `%name` will be substituted with the `package_name`,
+ * `%path` for `package_path`,
+ * `%version` for `package_version`.
+
+ `package_index` should be a file which determines if the package has already been installed. It would usually point to a binary file inside the distribution archive. If omitted, it defaults to `{package_path}/bin/{package_name}`.
+
+ If `package_path` is omitted, a variable `{PACKAGE_NAME}_PATH` is expected. E.g., if `package_name` is 'rsync' a variable named `RSYNC_PATH` must exist.
+ If `package_version` is omitted, a variable `{PACKAGE_NAME}_VERSION` is expected.
+
+ Requires `curl` to be installed.
+
+ Example (installing Node.js from binary distribution):
+
+ ```bash
+ # {{{ Configuration
+
+ NODE_PATH='/vagrant/vendor/node'
+ NODE_VERSION=0.8.22
+ NODE_PLATFORM=x86
+
+ PHANTOMJS_VERSION=1.8.1
+ PHANTOMJS_PATH='/vagrant/vendor/phantomjs'
+ PHANTOMJS_PLATFORM=i686
+
+ # }}}
+
+ # Download and install Node.js from the official website.
+ package-uri-install 'node' "http://nodejs.org/dist/v%version/node-v%version-linux-${NODE_PLATFORM}.tar.gz"
+
+ # Download and install PhantomJS from the official website.
+ package-uri-install 'phantomjs' "https://phantomjs.googlecode.com/files/phantomjs-%version-linux-${PHANTOMJS_PLATFORM}.tar.bz2"
+
+ # Node.js installed as: /vagrant/vendor/node/bin/node
+ # PhantomJS installed as: /vagrant/vendor/phantomjs/bin/phantomjs
+ ```
+
+### Temporary Files
+
+- `temporary-cleanup(tmp_path[, ...])`
+
+ Delete the contents of each `tmp_path` and halt script with the exit code of the last executed command.
+
+ Example (compile a project and clean up on failure):
+
+ ```bash
+ TMP_PATH="$( mktemp -d -t 'package-XXXXXXXX' )"
+ git clone 'git://github.com/project/package.git' "$TMP_PATH"
+ ( \
+ cd "$TMP_PATH" && \
+ ./configure && \
+ make && make install \
+ ) || temporary-cleanup "$TMP_PATH"
+ ```
+
+PostgreSQL
+----------
+
+The `ubuntu-postgres.sh` file provides functions for manipulating a PostgreSQL server instance.
+
+- `postgres-remote-access-allow()`
+
+ Allow remote access for the private `192.168.1.1/22` network (`192.168.0.1` through `192.168.3.254`).
+
+ This is only a good idea if the box is configured in 'Host-Only' network mode.
+
+- `postgres-password-reset(password)`
+
+ Reset the `postgres` user server password. This also allows password-based authentication.
+
+ Example:
+
+ ```bash
+ postgres-password-reset 'password'
+ ```
+
+- `postgres-autovacuum-on()`
+
+ Turn [autovacuuming](http://www.postgresql.org/docs/9.2/static/runtime-config-autovacuum.html) on.
+
+- `postgres-template-encoding(encoding = 'UTF8'[, ctype = 'en_GB.utf8'[, collate = ctype]])`
+
+ Set the default database encoding and collision.
+ Newly created databases will inherit those properties.
+
+ Example (use UTF-8 for all new databases):
+
+ ```bash
+ postgres-template-encoding 'UTF8' 'en_GB.utf8'
+ ```
+
+Postfix
+-------
+
+The `ubuntu-postfix.sh` file provides functions for manipulating an SMTP server instance using Postfix.
+
+- `smtp-sink-install(directory[, template = '%Y%m%d/%H%M.'[, port = 25[, user = 'vagrant'[, service = 'smtp-sink'[, backlog = 10]]]]])`
+
+ Hassle-free SMTP in development. Create a new system service which logs all outgoing e-mails to disk.
+
+ > `directory` specifies the process root directory.
+ > The single-message files are created by expanding the `template` via strftime(3) and appending a pseudo-random hexadecimal number (example: "%Y%m%d%H/%M." expands into "2006081203/05.809a62e3"). If the template contains "/" characters, missing directories are created automatically.
+
+ `port` specifies the port on which to listen.
+ `user` switches the user privileges after opening the network socket. The user must have permissions to write in `directory`.
+
+ `service` is an optional name of the system Upstart service. A file with this name is created under `/etc/init/`.
+
+ `backlog` specifies the maximum length the queue of pending connections, as defined by the listen(2) system call.
+
+ Example (log all messages to the `mail/` directory in the project root):
+
+ ```bash
+ smtp-sink-install '/vagrant/mail'
+ ```
+
+ The logged messages can be read using Thunderbird (append `.eml` to the file name).
+
+Environment
+-----------
+
+The following variables can be defined before including the `ubuntu.sh` script:
+
+- `SUDO[ = 'sudo']`
+
+ Specify the prefix for all super-user commands. If your system is configured with no `sudo` command, use an empty value.
+
+ Example (set up Google DNS on a system with no `sudo` command):
+
+ ```bash
+ SUDO=
+
+ nameservers-local-purge
+ nameservers-append '8.8.8.8'
+ nameservers-append '8.8.4.4'
+ ```
+
+- `COLORS[ = 'always']`
+
+ Use terminal escape codes to print colourised output. If you wish to disable this, use a value other than `{always,yes,true,1}`.
+
+ Example (turn off colours in output):
+
+ ```bash
+ COLORS=never
+
+ apt-packages-update
+ ```
+
+Goal
+----
+
+As I explore different OSes, I hope to add support for more platforms.
+
+The functions should remain the same, so provisioning scripts are somewhat 'portable'.
+
+Full Example
+------------
+
+The provisioning script below sets up Apache, SuExec, a virtual host for `/vagrant` (the default share) and remote `root` access to MySQL.
+
+```bash
+#!/usr/bin/env bash
+
+# {{{ Ubuntu utilities
+
+<%= import 'vagrant-shell-scripts/ubuntu.sh' %>
+
+# }}}
+
+# Use Google Public DNS for resolving domain names.
+# The default is host-only DNS which may not be installed.
+nameservers-local-purge
+nameservers-append '8.8.8.8'
+nameservers-append '8.8.4.4'
+
+# Use a local Ubuntu mirror, results in faster downloads.
+apt-mirror-pick 'bg'
+
+# Update packages cache.
+apt-packages-update
+
+# Install VM packages.
+apt-packages-install \
+ apache2-mpm-worker \
+ apache2-suexec-custom \
+ mysql-server-5.1 \
+ libapache2-mod-fastcgi \
+ php5-cgi \
+ php5-gd \
+ php5-mysql
+
+# Allow modules for Apache.
+apache-modules-enable actions rewrite fastcgi suexec
+
+# Replace the default Apache site.
+PHP=/usr/bin/php-cgi apache-sites-create 'vagrant'
+apache-sites-disable default default-ssl
+apache-sites-enable vagrant
+
+# Restart Apache web service.
+apache-restart
+
+# Allow unsecured remote access to MySQL.
+mysql-remote-access-allow
+
+# Restart MySQL service for changes to take effect.
+mysql-restart
+```
+
+### Copyright
+
+> Copyright (c) 2012 Stan Angeloff. See [LICENSE.md](https://github.com/StanAngeloff/vagrant-shell-scripts/blob/master/LICENSE.md) for details.
diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh
new file mode 100644
index 000000000000..752fab324210
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh
@@ -0,0 +1,142 @@
+#!/usr/bin/env bash
+
+set -e
+
+# {{{ Archives
+
+archive-file-unpack() {
+ log-operation "$FUNCNAME" "$@"
+ if [ $# -lt 1 ]; then
+ echo 'Usage: '"$0"' FILE [DIRECTORY]' >/dev/stderr
+ return 1
+ fi
+ local file
+ local directory
+ local command
+ local dependency
+ file="$( readlink -f "$1" )"
+ directory="${2:-.}"
+ case "$file" in
+ *.tar.gz | *.tgz ) command='tar -zxf' ;;
+ *.tar.bz2 | *.tbz2 ) command='tar -jxf' ;;
+ *.tar.xz ) command='tar -Jxf' ;;
+ *.tar ) command='tar -xf' ;;
+ *.zip ) command='unzip -q' ; dependency='unzip' ;;
+ *.7z ) command='7za x' ;;
+ *.gzip | *.gz ) command='gunzip -q' ;;
+ *.bzip2 | *.bz2 ) command='bunzip2 -q' ; dependency='bzip2' ;;
+ * )
+ echo "$0: Unsupported file format: $file" >/dev/stderr ;
+ return 2
+ ;;
+ esac
+ if [ ! -d "$directory" ]; then
+ mkdir -p "$directory"
+ fi
+ if [ -n "$dependency" ]; then
+ dependency-install "$dependency"
+ fi
+ ( cd "$directory" && eval $command \"\$file\" )
+}
+
+# }}}
+
+# {{{ Packages (e.g., ZIP distributions)
+
+package-ignore-preserve() {
+ local package_name="$1" package_path="$2" preserved_path="$3"
+ if [ -f "${package_path}/.gitignore" ]; then
+ for preserve in `cat "${package_path}/.gitignore" | grep '^!' | grep -v '/$' | sed -e 's#^!##g'`; do
+ eval "rm -f \"${preserved_path}/${package_name}-\"*\"/\"${preserve}"
+ done
+ fi
+}
+
+package-uri-download() {
+ local uri
+ local target
+ dependency-install 'curl'
+ uri="$1"
+ shift
+ if [ -z "$1" ]; then
+ target="-s"
+ else
+ target="-o $1"
+ shift
+ fi
+ curl '-#' --insecure -L "$@" $target "$uri"
+}
+
+package-uri-install() {
+ local package_name
+ local package_uri
+ local package_path
+ local package_version
+ local package_index
+ package_name="$1"
+ package_uri="$2"
+ package_index="$3"
+ package_path="$4"
+ package_version="$5"
+ if [ -z "$package_path" ]; then
+ package_path="$( echo "$package_name" | tr '-' '_' | tr 'a-z' 'A-Z' )_PATH"
+ package_path="${!package_path}"
+ fi
+ if [ -z "$package_version" ]; then
+ package_version="$( echo "$package_name" | tr '-' '_' | tr 'a-z' 'A-Z' )_VERSION"
+ package_version="${!package_version}"
+ fi
+ if [ -z "$package_index" ]; then
+ package_index="${package_path}/bin/${package_name}"
+ fi
+ for variable_name in 'package_uri' 'package_index'; do
+ eval "$variable_name"=\""$( \
+ echo "${!variable_name}" | \
+ sed -e 's#%name#'"$package_name"'#g' | \
+ sed -e 's#%version#'"$package_version"'#g' |
+ sed -e 's#%path#'"$package_path"'#g' \
+ )"\"
+ done
+ log-operation "$FUNCNAME" \
+ "$package_name" \
+ "$package_uri" \
+ "$package_index" \
+ "$package_path" \
+ "$package_version"
+ if [ ! -f "$package_index" ]; then
+ dependency-install 'rsync'
+ TMP_PATH="$( mktemp -d -t "${package_name}-XXXXXXXX" )"
+ TMP_FILE="$TMP_PATH/$( basename "$package_uri" )"
+ package-uri-download "$package_uri" "$TMP_FILE" -f || return $?
+ archive-file-unpack "$TMP_FILE" "$TMP_PATH"
+ rm -f "$TMP_FILE"
+ package-ignore-preserve "$package_name" "$package_path" "$TMP_PATH"
+ rsync -rlptDP "$TMP_PATH/${package_name}-"*'/' "${package_path}/"
+ rm -Rf "$TMP_PATH"
+ fi
+}
+
+# }}}
+
+# {{{ Temporary Files
+
+temporary-cleanup() {
+ local exit_code=$? tmp_path
+ for tmp_path in "$@"; do
+ if [ -d "$tmp_path" ]; then
+ rm -Rf "$tmp_path"
+ fi
+ done
+ exit $exit_code
+}
+
+# }}}
+
+# {{{ Dependency Management
+
+# Create associations for packages we are going to install.
+dependency-package-associate 'unzip' 'unzip'
+dependency-package-associate 'bzip2' 'bzip2'
+dependency-package-associate 'rsync' 'rsync'
+
+# }}}
diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh
new file mode 100644
index 000000000000..1f4010a93158
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+set -e
+
+# {{{ SMTP
+
+# Install an SMTP sink service which logs all outgoing e-mails to disk.
+smtp-sink-install() {
+ log-operation "$FUNCNAME" "$@"
+ local smtp_sink_directory="$1" \
+ smtp_sink_template="${2:-%Y%m%d/%H%M.}" \
+ smtp_port="${3:-25}" \
+ smtp_user="${4:-vagrant}" \
+ smtp_service="${5:-smtp-sink}" \
+ smtp_hard_bounce_reply="550 5.3.0 Sink'd." \
+ smtp_hostname='localhost.localdomain' \
+ smtp_backlog="${6:-10}"
+ if [ -z "$smtp_sink_directory" ]; then
+ echo -e "${ERROR_BOLD}E: ${ERROR_NORMAL}You must specify 'smtp_sink_directory' to '${FUNCNAME}' at position '1'.${RESET}" 1>&2
+ exit 1
+ fi
+ dependency-install 'postfix'
+ # If Postfix is currently running, stop it.
+ QUIET=1 system-service postfix status && system-service postfix stop || :
+ # Stop Postfix from running at start up.
+ $SUDO update-rc.d -f 'postfix' remove 1>/dev/null
+ # Kill any running smtp-sink services, try graceful shutdown first.
+ QUIET=1 system-service "$smtp_service" stop 1>/dev/null 2>&1 || :
+ $SUDO killall -q -9 smtp-sink || :
+ # Create a new service to log all e-mails to disk.
+ cat <<-EOD | $SUDO tee "/etc/init/${smtp_service}.conf" 1>/dev/null
+# ${smtp_service}
+#
+# SMTP server which logs all outgoing e-mails to disk.
+
+description "${smtp_service}, logs all outgoing e-mails"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+console log
+
+respawn
+respawn limit 3 5
+
+pre-start exec mkdir -p "$smtp_sink_directory"
+
+exec start-stop-daemon --start --exec "$( which smtp-sink )" -- \\
+ -u "$smtp_user" \\
+ -R "$( echo "$smtp_sink_directory" | sed -e 's#/$##' )/" -d "$smtp_sink_template" \\
+ -f '.' -B "$smtp_hard_bounce_reply" \\
+ -h "$smtp_hostname" "$smtp_port" "$smtp_backlog"
+EOD
+ # Start the service. It will also run on next start up
+ system-service "$smtp_service" start
+}
+
+# }}}
+
+# {{{ Dependency Management
+
+# Create associations for packages we are going to install.
+dependency-package-associate 'postfix' 'postfix'
+
+# }}}
diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh
new file mode 100644
index 000000000000..65f20681396c
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+set -e
+
+# {{{ PostgreSQL
+
+postgres-remote-access-allow() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO sed -e "s/[#]\?listen_addresses = .*/listen_addresses = '*'/g" -i '/etc/postgresql/'*'/main/postgresql.conf'
+ $SUDO grep '192.168.1.1' '/etc/postgresql/'*'/main/pg_hba.conf' | \
+ ( echo 'host all all 192.168.1.1/22 md5' | $SUDO tee -a '/etc/postgresql/'*'/main/pg_hba.conf' >/dev/null )
+}
+
+postgres-password-reset() {
+ log-operation "$FUNCNAME"
+ $SUDO -u 'postgres' psql -c "ALTER ROLE postgres WITH ENCRYPTED PASSWORD '$1'" 1>/dev/null
+}
+
+postgres-autovacuum-on() {
+ log-operation "$FUNCNAME"
+ $SUDO sed -e "s/[#]\?autovacuum = .*/autovacuum = on/g" -i '/etc/postgresql/'*'/main/postgresql.conf'
+ $SUDO sed -e "s/[#]\?track_counts = .*/track_counts = on/g" -i '/etc/postgresql/'*'/main/postgresql.conf'
+}
+
+postgres-template-encoding() {
+ local encoding
+ local ctype
+ local collate
+ encoding="${1:-UTF8}"
+ ctype="${2:-en_GB.$( echo "$encoding" | tr 'A-Z' 'a-z' )}"
+ collate="${3:-$ctype}"
+ log-operation "$FUNCNAME" "$@"
+ SQL_TMP_FILE="$( mktemp -t 'sql-XXXXXXXX' )"
+ cat > "$SQL_TMP_FILE" <<-EOD
+UPDATE pg_database SET datallowconn = TRUE WHERE datname = 'template0';
+\\c template0;
+UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1';
+DROP DATABASE template1;
+CREATE DATABASE template1 WITH template = template0 ENCODING = '${encoding}' LC_CTYPE = '${ctype}' LC_COLLATE = '${collate}';
+UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1';
+\\c template1;
+UPDATE pg_database SET datallowconn = FALSE WHERE datname = 'template0';
+EOD
+ $SUDO chmod 0777 "$SQL_TMP_FILE"
+ $SUDO -u 'postgres' psql -f "$SQL_TMP_FILE" 1>/dev/null || {
+ EXIT_CODE=$?
+ rm "$SQL_TMP_FILE"
+ exit $EXIT_CODE
+ }
+ rm "$SQL_TMP_FILE"
+}
+
+# }}}
diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu.sh
new file mode 100644
index 000000000000..68020c9a71c2
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu.sh
@@ -0,0 +1,796 @@
+#!/usr/bin/env bash
+
+set -e
+
+[ -n "${SUDO-x}" ] && SUDO='sudo'
+
+ERROR_BOLD="\e[1;31m"
+ERROR_NORMAL="\e[0;31m"
+DEBUG_BOLD="\e[1;35m"
+DEBUG_NORMAL="\e[0;35m"
+RESET="\e[00m"
+
+if [[ -n "$COLORS" ]] && [[ ! "$COLORS" =~ ^(always|yes|true|1)$ ]]; then
+ unset ERROR_BOLD
+ unset ERROR_NORMAL
+ unset DEBUG_BOLD
+ unset DEBUG_NORMAL
+ unset RESET
+fi
+
+# {{{ Utils
+
+# Return the value of the first argument or exit with an error message if empty.
+script-argument-create() {
+ [ -z "$1" ] && {
+ echo -e "${ERROR_BOLD}E: ${ERROR_NORMAL}You must specify $2 to '${BASH_SOURCE[0]}'.${RESET}" 1>&2
+ exit 1
+ }
+ echo "$1"
+}
+
+# Log an operation
+log-operation() {
+ local function_name
+ local function_values
+ local arg
+ function_name="$1"
+ shift
+ for arg in "$@"; do
+ function_values="$function_values ""'$( echo "$arg" | sed -e 's#\s\+# #g' )'"
+ done
+ [ -z "$QUIET" ] && echo -e "${DEBUG_BOLD}$function_name${DEBUG_NORMAL}(""$( echo "$function_values" | sed -e 's#^ ##' -e "s#\s\+''\$##g" )"")...${RESET}"
+}
+
+# }}}
+
+# {{{ Nameservers
+
+# Drop all local 10.0.x.x nameservers in 'resolv.conf'.
+nameservers-local-purge() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO sed -e 's#nameserver\s*10\.0\..*$##g' -i '/etc/resolv.conf'
+}
+
+# Set up an IP as a DNS name server if not already present in 'resolv.conf'.
+nameservers-append() {
+ log-operation "$FUNCNAME" "$@"
+ grep "$1" '/etc/resolv.conf' >/dev/null || \
+ ( echo "nameserver $1" | $SUDO tee -a '/etc/resolv.conf' >/dev/null )
+}
+
+# }}}
+
+# {{{ Aptitude
+
+# Set up a specific two-letter country code as the preferred `aptitude` mirror.
+apt-mirror-pick() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO sed -i \
+ -e "s#\w\+\.archive\.ubuntu\.com#$1.archive.ubuntu.com#g" \
+ -e "s#security\.ubuntu\.com#$1.archive.ubuntu.com#g" \
+ '/etc/apt/sources.list'
+}
+
+# Add a custom repository as a software source.
+apt-packages-repository() {
+ log-operation "$FUNCNAME" "$@"
+ dependency-install 'add-apt-repository'
+ while [[ "$1" =~ ^deb ]] || [[ "$1" =~ ^ppa ]]; do
+ $SUDO add-apt-repository -y "$( echo "$1" | sed -e 's#^deb-src\b#deb#' )" 1>/dev/null
+ # See https://bugs.launchpad.net/ubuntu/+source/software-properties/+bug/972617
+ if [[ "$1" =~ ^deb ]] && [[ ! "$1" =~ ^deb-src ]]; then
+ $SUDO add-apt-repository --remove -y "$( echo "$1" | sed -e 's#^deb\b#deb-src#' )" 1>/dev/null
+ fi
+ shift
+ done
+ if [ -n "$1" ] && ! $SUDO apt-key list | grep -q "$1"; then
+ $SUDO apt-key adv -q --keyserver "${2:-keyserver.ubuntu.com}" --recv-keys "$1" 1>/dev/null
+ fi
+}
+
+# Add a Launchpad PPA as a software source.
+apt-packages-ppa() {
+ local ppa_repository="$1"
+ shift
+ # If the repository is already set up, don't re-add it.
+ if ! apt-cache policy | grep "$ppa_repository" 1>/dev/null 2>&1; then
+ apt-packages-repository "ppa:${ppa_repository}" "$@"
+ fi
+}
+
+# Perform a non-interactive `apt-get` command.
+apt-non-interactive() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO \
+ DEBIAN_FRONTEND=noninteractive \
+ apt-get \
+ -o Dpkg::Options::='--force-confdef' \
+ -o Dpkg::Options::='--force-confold' \
+ -f -y -qq \
+ --no-install-recommends \
+ "$@"
+}
+
+# Update `aptitude` packages without any prompts.
+apt-packages-update() {
+ apt-non-interactive update
+}
+
+# Perform an unattended installation of package(s).
+apt-packages-install() {
+ apt-non-interactive install "$@"
+}
+
+# Perform an unattended complete removal (purge) of package(s).
+apt-packages-purge() {
+ local result
+ local code
+ result=$( apt-non-interactive -q purge "$@" 2>&1 ) || {
+ code=$?
+ # If no packages matched, it's OK.
+ if [[ ! "$result" =~ "E: Couldn't find package" ]]; then
+ echo "$result" 1>&2
+ exit $code
+ fi
+ }
+ # Take care of any leftovers.
+ apt-non-interactive autoremove
+}
+
+# }}}
+
+# {{{ System
+
+# Run a complete system upgrade.
+system-upgrade() {
+ apt-non-interactive upgrade
+}
+
+# Command a system service, e.g., apache2, mysql, etc.
+system-service() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO service "$1" "$2" 1>/dev/null
+}
+
+# Escape and normalize a string so it can be used safely in file names, etc.
+system-escape() {
+ local glue
+ glue=${1:--}
+ while read arg; do
+ echo "${arg,,}" | sed -e 's#[^[:alnum:]]\+#'"$glue"'#g' -e 's#^'"$glue"'\+\|'"$glue"'\+$##g'
+ done
+}
+
+# }}}
+
+# {{{ Default Commands
+
+# Update the Ruby binary link to point to a specific version.
+alternatives-ruby-install() {
+ log-operation "$FUNCNAME" "$@"
+ local bin_path
+ local man_path
+ bin_path="${2:-/usr/bin/}"
+ man_path="${3:-/usr/share/man/man1/}"
+ $SUDO update-alternatives \
+ --install "${bin_path}ruby" ruby "${bin_path}ruby$1" "${4:-500}" \
+ --slave "${man_path}ruby.1.gz" ruby.1.gz "${man_path}ruby$1.1.gz" \
+ --slave "${bin_path}ri" ri "${bin_path}ri$1" \
+ --slave "${bin_path}irb" irb "${bin_path}irb$1" \
+ --slave "${bin_path}rdoc" rdoc "${bin_path}rdoc$1"
+ $SUDO update-alternatives --verbose \
+ --set ruby "${bin_path}ruby$1"
+}
+
+# Create symbolic links to RubyGems binaries.
+alternatives-ruby-gems() {
+ log-operation "$FUNCNAME" "$@"
+ local ruby_binary
+ local ruby_version
+ local binary_name
+ local binary_path
+ ruby_binary=$( $SUDO update-alternatives --query 'ruby' | grep 'Value:' | cut -d' ' -f2- )
+ ruby_version="${ruby_binary#*ruby}"
+ if grep -v '^[0-9.]*$' <<< "$ruby_version"; then
+ echo "E: Could not determine version of RubyGems."
+ fi
+ for binary_name in "$@"; do
+ binary_path="/var/lib/gems/$ruby_version/bin/$binary_name"
+ $SUDO update-alternatives --install "$( dirname "$ruby_binary" )/$binary_name" "$binary_name" "$binary_path" 500
+ $SUDO update-alternatives --verbose --set "$binary_name" "$binary_path"
+ done
+}
+
+# }}}
+
+# {{{ Apache
+
+# Enable a list of Apache modules. This requires a server restart.
+apache-modules-enable() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO a2enmod $* 1>/dev/null
+}
+
+# Disable a list of Apache modules. This requires a server restart.
+apache-modules-disable() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO a2dismod $* 1>/dev/null
+}
+
+# Enable a list of Apache sites. This requires a server restart.
+apache-sites-enable() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO a2ensite $* 1>/dev/null
+}
+
+# Disable a list of Apache sites. This requires a server restart.
+apache-sites-disable() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO a2dissite $* 1>/dev/null
+}
+
+# Create a new Apache site and set up Fast-CGI components.
+apache-sites-create() {
+ log-operation "$FUNCNAME" "$@"
+ local apache_site_name
+ local apache_site_path
+ local apache_site_user
+ local apache_site_group
+ local apache_site_config
+ local apache_verbosity
+ local cgi_action
+ local cgi_apache_path
+ local cgi_system_path
+ local code_block
+ apache_site_name="$1"
+ apache_site_path="${2:-/$apache_site_name}"
+ apache_site_user="${3:-$apache_site_name}"
+ apache_site_group="${4:-$apache_site_user}"
+ apache_verbosity="${5:-info}"
+ apache_site_config="/etc/apache2/sites-available/$apache_site_name"
+ cgi_apache_path="/cgi-bin/"
+ cgi_system_path="$apache_site_path/.cgi-bin/"
+ # Create the /.cgi-bin/ directory and set permissions for SuExec.
+ $SUDO mkdir -p "$cgi_system_path"
+ $SUDO chmod 0755 "$cgi_system_path"
+ # Define a new virtual host with mod_fastcgi configured to use SuExec.
+ code_block=$( cat <<-EOD
+
+ FastCgiWrapper /usr/lib/apache2/suexec
+ FastCgiConfig -pass-header HTTP_AUTHORIZATION -autoUpdate -killInterval 120 -idle-timeout 30
+
+
+
+ DocumentRoot ${apache_site_path}
+
+ LogLevel ${apache_verbosity}
+ ErrorLog /var/log/apache2/error.${apache_site_name}.log
+ CustomLog /var/log/apache2/access.${apache_site_name}.log combined
+
+ SuexecUserGroup ${apache_site_user} ${apache_site_group}
+ ScriptAlias ${cgi_apache_path} ${cgi_system_path}
+
+ # Do not use kernel sendfile to deliver files to the client.
+ EnableSendfile Off
+
+
+ Options All
+ AllowOverride All
+
+EOD
+ )
+ # Is PHP required?
+ if [ ! -z "$PHP" ]; then
+ cgi_action="php-fcgi"
+ code_block=$( cat <<-EOD
+${code_block}
+
+
+
+ SetHandler fastcgi-script
+ Options +ExecCGI +FollowSymLinks
+ Order Allow,Deny
+ Allow from all
+
+ AddHandler ${cgi_action} .php
+ Action ${cgi_action} ${cgi_apache_path}${cgi_action}
+
+EOD
+ )
+ $SUDO cat > "$cgi_system_path$cgi_action" <<-EOD
+#!/bin/bash
+
+export PHP_FCGI_CHILDREN=4
+export PHP_FCGI_MAX_REQUESTS=200
+
+export PHPRC="${cgi_system_path}php.ini"
+
+exec ${PHP}
+EOD
+ $SUDO chmod 0755 "$cgi_system_path$cgi_action"
+ fi
+ code_block=$( cat <<-EOD
+${code_block}
+${EXTRA}
+
+EOD
+ )
+ # Write site configuration to Apache.
+ echo "$code_block" | $SUDO tee "$apache_site_config" >/dev/null
+ # Configure permissions for /.cgi-bin/ and SuExec.
+ $SUDO chown -R "$apache_site_user":"$apache_site_group" "$cgi_system_path"
+ # Update SuExec to accept the new document root for this website.
+ grep "$apache_site_path" '/etc/apache2/suexec/www-data' >/dev/null || \
+ ( $SUDO sed -e '1s#^#'"$apache_site_path""\n"'#' -i '/etc/apache2/suexec/www-data' >/dev/null )
+}
+
+# Restart the Apache server and reload with new configuration.
+apache-restart() {
+ system-service apache2 restart
+}
+
+# }}}
+
+# {{{ Nginx
+
+# Figure out the path to a particular Nginx site.
+nginx-sites-path() {
+ echo "/etc/nginx/sites-${2:-available}/$1"
+}
+
+# Enable a list of Nginx sites. This requires a server restart.
+nginx-sites-enable() {
+ log-operation "$FUNCNAME" "$@"
+ local name
+ local file
+ for name in "$@"; do
+ file="$( nginx-sites-path "$name" 'enabled' )"
+ if [ ! -L "$file" ]; then
+ # '-f'orce because '! -L' above would still evaluate for broken symlinks.
+ $SUDO ln -fs "$( nginx-sites-path "$name" 'available' )" "$file"
+ fi
+ done
+}
+
+# Disable a list of Nginx sites. This requires a server restart.
+nginx-sites-disable() {
+ log-operation "$FUNCNAME" "$@"
+ local name
+ local file
+ for name in "$@"; do
+ file="$( nginx-sites-path "$name" 'enabled' )"
+ if [ -L "$file" ]; then
+ $SUDO unlink "$file"
+ fi
+ done
+}
+
+# Create a new Nginx site and set up Fast-CGI components.
+nginx-sites-create() {
+ log-operation "$FUNCNAME" "$@"
+ local nginx_site_name
+ local nginx_site_path
+ local nginx_site_index
+ local nginx_site_user
+ local nginx_site_group
+ local nginx_verbosity
+ local nginx_site_config
+ local code_block
+ nginx_site_name="$1"
+ nginx_site_path="${2:-/$nginx_site_name}"
+ nginx_site_user="${3:-$nginx_site_name}"
+ nginx_site_group="${4:-$nginx_site_user}"
+ nginx_site_index="${5:-index.html}"
+ nginx_verbosity="${6:-info}"
+ nginx_site_config="$( nginx-sites-path "$nginx_site_name" 'available' )"
+ # Is PHP required?
+ if [ ! -z "$PHP" ]; then
+ if ! which php5-fpm >/dev/null; then
+ echo 'E: You must install php5-fpm to use PHP in Nginx.' 1>&2
+ exit 1
+ fi
+ nginx_site_index="index.php $nginx_site_index"
+ fi
+ code_block=$( cat <<-EOD
+server {
+ listen 80;
+
+ root ${nginx_site_path};
+
+ error_log /var/log/nginx/error.${nginx_site_name}.log ${nginx_verbosity};
+ access_log /var/log/nginx/access.${nginx_site_name}.log combined;
+
+ index ${nginx_site_index};
+
+ # Do not use kernel sendfile to deliver files to the client.
+ sendfile off;
+
+ # Prevent access to hidden files.
+ location ~ /\. {
+ access_log off;
+ log_not_found off;
+ deny all;
+ }
+EOD
+ )
+ # Is PHP required?
+ if [ ! -z "$PHP" ]; then
+ code_block=$( cat <<-EOD
+${code_block}
+
+ # Pass PHP scripts to PHP-FPM.
+ location ~ \.php\$ {
+ include fastcgi_params;
+ fastcgi_pass unix:/var/run/php5-fpm.${nginx_site_name}.sock;
+ fastcgi_index index.php;
+ fastcgi_split_path_info ^((?U).+\.php)(/?.+)\$;
+ fastcgi_param PATH_INFO \$fastcgi_path_info;
+ fastcgi_param PATH_TRANSLATED \$document_root\$fastcgi_path_info;
+ fastcgi_param HTTP_AUTHORIZATION \$http_authorization;
+ }
+EOD
+ )
+ # Run PHP-FPM as the selected user and group.
+ $SUDO sed \
+ -e 's#^\[www\]$#['"$nginx_site_name"']#g' \
+ -e 's#^\(user\)\s*=\s*[A-Za-z0-9-]\+#\1 = '"$nginx_site_user"'#g' \
+ -e 's#^\(group\)\s*=\s*[A-Za-z0-9-]\+#\1 = '"$nginx_site_group"'#g' \
+ -e 's#^\(listen\)\s*=\s*.\+$#\1 = /var/run/php5-fpm.'"$nginx_site_name"'.sock#g' \
+ < '/etc/php5/fpm/pool.d/www.conf' | $SUDO tee '/etc/php5/fpm/pool.d/'"$nginx_site_name"'.conf' >/dev/null
+ fi
+ code_block=$( cat <<-EOD
+${code_block}
+${EXTRA}
+}
+EOD
+ )
+ # Write site configuration to Nginx.
+ echo "$code_block" | $SUDO tee "$nginx_site_config" >/dev/null
+}
+
+# Restart the Nginx server and reload with new configuration.
+nginx-restart() {
+ system-service nginx restart
+}
+
+# }}}
+
+# {{{ PHP
+
+# Update a PHP setting value in all instances of 'php.ini'.
+php-settings-update() {
+ log-operation "$FUNCNAME" "$@"
+ local args
+ local settings_name
+ local php_ini
+ local php_extra
+ args=( "$@" )
+ PREVIOUS_IFS="$IFS"
+ IFS='='
+ args="${args[*]}"
+ IFS="$PREVIOUS_IFS"
+ settings_name="$( echo "$args" | system-escape )"
+ for php_ini in $( $SUDO find /etc -type f -iname 'php*.ini' ); do
+ php_extra="$( dirname "$php_ini" )/conf.d"
+ $SUDO mkdir -p "$php_extra"
+ echo "$args" | $SUDO tee "$php_extra/0-$settings_name.ini" >/dev/null
+ done
+}
+
+# Install (download, build, install) and enable a PECL extension.
+php-pecl-install() {
+ log-operation "$FUNCNAME" "$@"
+ local specification extension
+ local mode
+ dependency-install 'make'
+ dependency-install 'pecl'
+ dependency-install 'phpize'
+ for specification in "$@"; do
+ extension="${specification%@*}"
+ if ! $SUDO pecl list | grep "^${extension}" >/dev/null; then
+ $SUDO pecl install -s "${specification/@/-}" 1>/dev/null
+ fi
+ # Special case for Zend extensions.
+ if [[ "$extension" =~ ^(xdebug)$ ]]; then
+ mode="zend_extension"
+ extension="$( php-config --extension-dir )/${extension}"
+ else
+ mode="extension"
+ fi
+ php-settings-update "$mode" "${extension}.so"
+ done
+}
+
+# Restart the PHP5-FPM server.
+php-fpm-restart() {
+ system-service php5-fpm restart
+}
+
+# }}}
+
+# {{{ MySQL
+
+# Create a database if one doesn't already exist.
+mysql-database-create() {
+ log-operation "$FUNCNAME" "$@"
+ mysql -u root -e "CREATE DATABASE IF NOT EXISTS \`$1\` CHARACTER SET ${2:-utf8} COLLATE '${3:-utf8_general_ci}'"
+}
+
+# Restore a MySQL database from an archived backup.
+mysql-database-restore() {
+ log-operation "$FUNCNAME" "$@"
+ local backups_database
+ local backups_path
+ local backups_file
+ local tables_length
+ backups_database="$1"
+ backups_path="$2"
+ if [ -d "$backups_path" ]; then
+ tables_length=$( mysql -u root --skip-column-names -e "USE '$backups_database'; SHOW TABLES" | wc -l )
+ if [ "$tables_length" -lt 1 ]; then
+ backups_file=$( find "$backups_path" -maxdepth 1 -type f -regextype posix-basic -regex '^.*[0-9]\{8\}-[0-9]\{4\}.tar.bz2$' | \
+ sort -g | \
+ tail -1 )
+ if [ ! -z "$backups_file" ]; then
+ tar -xjf "$backups_file" -O | mysql -u root "$backups_database"
+ fi
+ fi
+ fi
+}
+
+# Allow remote passwordless 'root' access for anywhere.
+# This is only a good idea if the box is configured in 'Host-Only' network mode.
+mysql-remote-access-allow() {
+ log-operation "$FUNCNAME" "$@"
+ mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '' WITH GRANT OPTION; FLUSH PRIVILEGES;"
+ $SUDO sed -e 's#127.0.0.1#0.0.0.0#g' -i '/etc/mysql/my.cnf'
+}
+
+# Restart the MySQL server and reload with new configuration.
+mysql-restart() {
+ system-service mysql restart
+}
+
+# }}}
+
+# {{{ RubyGems
+
+# Check the installed version of a package.
+ruby-gems-version() {
+ $SUDO ruby -rubygems -e "puts Gem::Specification::find_by_name('$1').version" 2>/dev/null || \
+ echo '0.0.0'
+}
+
+# Perform an unattended installation of a package.
+ruby-gems-install() {
+ log-operation "$FUNCNAME" "$@"
+ local gem_version
+ gem_version="$( ruby-gems-version "$1" )"
+ if [[ "$gem_version" = '0.0.0' ]]; then
+ $SUDO gem install --no-ri --no-rdoc "$@"
+ fi
+}
+
+# }}}
+
+# {{{ NPM (Node Package Manager)
+
+# Perform an unattended **global** installation of package(s).
+npm-packages-install() {
+ log-operation "$FUNCNAME" "$@"
+ $SUDO npm config set yes true
+ $SUDO npm install -g $*
+}
+
+# }}}
+
+# {{{ Oracle JDK (Oracle Java Development Kit)
+
+# Install Oracle JDK to /opt/java, update defaults and add it to PATH
+oracle-jdk-install() {
+ log-operation "$FUNCNAME" "$@"
+ dependency-install 'curl'
+ local cookie
+ local jdk_link
+ local target
+ cookie="$1"
+ jdk_link="$2"
+ temp_dir="$3"
+ temp_out_file="$temp_dir"/oracle_jdk.tar.gz
+ # download if the file is not exists
+ if [ ! -f "$temp_out_file" ]; then
+ curl -L --progress-bar --header "$cookie" "$jdk_link" -z "$temp_out_file" -o "$temp_out_file"
+ fi
+
+ tar -xf "$temp_out_file" -C "$temp_dir"
+ $SUDO mkdir -p /opt/
+ $SUDO mv "$temp_dir"/jdk* /opt/java
+
+ $SUDO update-alternatives --install "/usr/bin/java" "java" "/opt/java/bin/java" 1
+ $SUDO update-alternatives --install "/usr/bin/javac" "javac" "/opt/java/bin/javac" 1
+ $SUDO update-alternatives --install "/usr/bin/javaws" "javaws" "/opt/java/bin/javaws" 1
+
+ env-append 'JAVA_HOME' "/opt/java/"
+ env-append 'PATH' "/opt/java/bin/"
+}
+
+# }}}
+
+# {{{ GitHub
+
+# Download and install RubyGems from GitHub.
+github-gems-install() {
+ log-operation "$FUNCNAME" "$@"
+ local repository
+ local clone_path
+ local configuration
+ local gem_version
+ dependency-install 'git'
+ which 'gem' >/dev/null || {
+ echo 'E: Please install RubyGems to continue.' 1>&2
+ exit 1
+ }
+ for repository in "$@"; do
+ configuration=(${repository//@/"${IFS}"})
+ gem_version="$( ruby-gems-version "${configuration[0]#*\/}" )"
+ if [[ "$gem_version" = '0.0.0' ]]; then
+ clone_path="$( mktemp -d -t 'github-'$( echo "${configuration[0]}" | system-escape )'-XXXXXXXX' )"
+ git clone --progress "git://github.com/${configuration[0]}" "$clone_path"
+ ( \
+ cd "$clone_path" && \
+ git checkout -q "${configuration[1]:-master}" && \
+ gem build *.gemspec && \
+ ruby-gems-install *.gem \
+ )
+ rm -Rf "$clone_path"
+ fi
+ done
+}
+
+# Install (download, build, install) and enable a PECL extension.
+github-php-extension-install() {
+ log-operation "$FUNCNAME" "$@"
+ local specification repository version arguments extension
+ local raw_config_uri clone_path
+ # We must have 'phpize' available when compiling extensions from source.
+ dependency-install 'git'
+ dependency-install 'curl'
+ dependency-install 'phpize'
+ for specification in "$@"; do
+ repository="$specification"
+ version='master'
+ # If we have a space anywhere in the string, assume `configure` arguments.
+ if [[ "$repository" =~ ' ' ]]; then
+ arguments=( ${repository#* } )
+ repository="${repository%% *}"
+ fi
+ # If we have a version specified, split the repository name and version.
+ if [[ "$repository" =~ '@' ]]; then
+ version="${repository#*@}"
+ repository="${repository%@*}"
+ fi
+ # Let's figure out the extension name by looking at the autoconf file.
+ raw_config_uri="https://raw.github.com/${repository}/${version}/config.m4"
+ extension="$( curl --insecure --silent "$raw_config_uri" | grep -e 'PHP_NEW_EXTENSION' | cut -d'(' -f2 | cut -d',' -f1 | tr -d ' ' )"
+ if [ -z "$extension" ]; then
+ echo -e "${ERROR_BOLD}E: ${ERROR_NORMAL}Cannot find extension name in ${raw_config_uri}, expected 'PHP_NEW_EXTENSION'.${RESET}" 1>&2
+ exit 1
+ fi
+ # We can't use PECL to determine if the extension is installed
+ # so let's look for the .so file in the PHP extensions directory.
+ if ! $SUDO ls -1 "$( php-config --extension-dir )" | grep "^${extension}.so$" >/dev/null; then
+ clone_path="$( mktemp -d -t 'github-'$( echo "${repository}" | system-escape )'-XXXXXXXX' )"
+ # Clone, configure, make, install... the usual.
+ git clone --progress "git://github.com/${repository}" "$clone_path"
+ ( \
+ cd "$clone_path" && \
+ git checkout -q "$version" && \
+ phpize && \
+ ./configure "${arguments[@]}" && \
+ make && $SUDO make install \
+ )
+ # Clean up and explicitly load the extension.
+ rm -Rf "$clone_path"
+ php-settings-update 'extension' "${extension}.so"
+ fi
+ done
+}
+
+# }}}
+
+# {{{ Environment
+
+env-append() {
+ local env_key="$1" env_lookup=1 env_value="$2" env_comment="$3" env_line
+ log-operation "$FUNCNAME" "$@"
+ for profile_env in '/etc/profile' '/etc/zsh/zshenv'; do
+ if [ -f "$profile_env" ]; then
+ if [ "$env_key" == 'PATH' ]; then
+ env_line="export ${env_key}='${env_value}':"'"$PATH"'
+ elif [[ "$env_key" =~ ^(source|eval)$ ]]; then
+ env_line="${env_key} ${env_value} || :"
+ else
+ env_line="[ -z "'"$'"$env_key"'"'" ] && export ${env_key}='${env_value}'"
+ fi
+ eval "$env_line" || :
+ if ! grep "${env_key}.*${env_value}" "$profile_env" &>/dev/null; then
+ echo -e "\n# AUTO-GENERATED: ${env_key}$( echo ", ${env_comment}" | sed -e 's/^,\s*$//' ).\n${env_line}" | $SUDO tee -a "$profile_env" 1>/dev/null
+ fi
+ fi
+ done
+}
+
+# }}}
+
+# {{{ Dependency Management
+
+# Associate a package name with a command, e.g., 'git' <- 'git-core'.
+dependency-package-associate() {
+ local variable_name
+ variable_name="DEPENDENCY_$(echo "$1" | system-escape '_' | tr '[a-z]' '[A-Z]' )"
+ # If a second argument was specified...
+ if [ -n "$2" ]; then
+ # ...and a package name hasn't been associated with the command yet...
+ if [ -z "${!variable_name}" ]; then
+ # ...create a new association.
+ eval $variable_name=\""$2"\"
+ fi
+ else
+ echo "${!variable_name}"
+ fi
+}
+
+# Satisfy a dependency by installing the associated package.
+dependency-install() {
+ local binary_name
+ local package_name
+ local apt_update_required=0
+ local apt_update_performed=0
+ local apt_update_datetime apt_update_timestamp apt_update_ago
+ local timestamp_now
+ for binary_name in "$@"; do
+ which "$binary_name" >/dev/null || {
+ package_name="$( dependency-package-associate "$binary_name" )"
+ # If we cannot find the package name in the cache, request an update.
+ # This may happen if `apt-get update` was not run on the machine before.
+ if ! $SUDO apt-cache pkgnames | grep "$package_name" 1>/dev/null 2>&1; then
+ apt_update_required=1
+ fi
+ # If the last time we updated the cache was more than a day ago, request an update.
+ # This is needed to prevent errors when trying to install an out-of-date package from the cache.
+ if [[ $apt_update_required -lt 1 ]] && [[ $apt_update_performed -lt 1 ]]; then
+ # Determine the last date/time any lists files were modified, newest first.
+ apt_update_datetime="$( \
+ ls -lt --time-style='long-iso' '/var/lib/apt/lists/' 2>/dev/null | grep -o '\([0-9]\{2,4\}[^0-9]\)\{3\}[0-9]\{2\}:[0-9]\{2\}' -m 1 || \
+ date +'%Y-%m-%d %H:%M'
+ )"
+ # Convert the YYYY-MM-DD HH:MM format to a Unix timestamo.
+ apt_update_timestamp=$( date --date="$apt_update_datetime" +'%s' 2>/dev/null || echo 0 )
+ # Calculate the number of seconds that have passed since the newest update.
+ timestamp_now=$( date +'%s' )
+ apt_update_ago=$(( $timestamp_now-$apt_update_timestamp ))
+ if [ $apt_update_ago -gt 86400 ]; then
+ apt_update_required=1
+ fi
+ fi
+ # If the cache needs updating, do so before installing the package (once per call only).
+ if [[ $apt_update_required -gt 0 ]] && [[ $apt_update_performed -lt 1 ]]; then
+ apt_update_required=0
+ apt_update_performed=1
+ apt-packages-update
+ fi
+ apt-packages-install "$package_name"
+ }
+ done
+}
+
+# Create associations for packages we are going to install.
+dependency-package-associate 'add-apt-repository' 'python-software-properties'
+dependency-package-associate 'curl' 'curl'
+dependency-package-associate 'git' 'git-core'
+dependency-package-associate 'make' 'build-essential'
+dependency-package-associate 'pecl' 'php-pear'
+dependency-package-associate 'phpize' 'php5-dev'
+
+# }}}
diff --git a/vagrant/scripts/vagrant-shell-scripts/vagrant.rb b/vagrant/scripts/vagrant-shell-scripts/vagrant.rb
new file mode 100644
index 000000000000..aef95a52b291
--- /dev/null
+++ b/vagrant/scripts/vagrant-shell-scripts/vagrant.rb
@@ -0,0 +1,26 @@
+require 'erb'
+
+def vagrant_shell_scripts_configure(shell, scripts_path, script_name = 'provision')
+ shell.privileged = false
+ shell.inline = ERB.new(<<-eos
+<%
+
+def import(file)
+ ['#{ scripts_path }', '#{ File.dirname(__FILE__) }'].each do |path|
+ if File.file?(File.join(path, file))
+ return ERB.new(
+ File.read(
+ File.join(path, file)
+ )
+ ).result(binding)
+ end
+ end
+ raise ArgumentError, 'The file "' + file + '" cannot be imported.'
+end
+
+%>
+
+<%= import '#{ script_name }' %>
+ eos
+ ).result
+end
\ No newline at end of file
diff --git a/vagrant/vagrant_nodes.sh b/vagrant/vagrant_nodes.sh
new file mode 100644
index 000000000000..bd6fa7740c33
--- /dev/null
+++ b/vagrant/vagrant_nodes.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+# user
+export VAGRANT_SPARK_USER="spark-user"
+
+# password
+export VAGRANT_SPARK_PASSWORD="spark"
+
+# master ip
+export VAGRANT_SPARK_MASTER="192.168.2.10"
+
+# worker 1 ip
+export VAGRANT_SPARK_WORKER_1="192.168.2.20"
+
+# worker 2 ip
+export VAGRANT_SPARK_WORKER_2="192.168.2.21"