A collection of scripts (Ubuntu-only at this time) to ease Vagrant box provisioning using the shell method.
-
Place on top of your
VagrantfilebeforeVagrant.configure(..):require File.join(File.dirname(__FILE__), 'path/to/vagrant-shell-scripts/vagrant')
-
Place at the end of your
Vagrantfilebefore the lastend:config.vm.provision :shell do |shell| vagrant_shell_scripts_configure( shell, File.dirname(__FILE__), 'path/to/provisioning_script' ) end
-
Place on top of your provisioning script:
#!/usr/bin/env bash <%= import 'ubuntu.sh' %>
-
script-argument-create(value, expected)Return the value of the first argument or exit with an error message if empty.
Example:
MYSQL_DBNAME=$( script-argument-create "$1" 'a MySQL database name as the first argument' )
-
nameservers-local-purgeDrop all local
10.0.x.xnameservers inresolv.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):
nameservers-local-purge nameservers-append '8.8.8.8' nameservers-append '8.8.4.4'
-
apt-mirror-pick(iso2)Set up a specific two-letter country code as the preferred
aptitudemirror.Example (use Ubuntu Bulgaria as a mirror):
apt-mirror-pick 'bg' -
apt-packages-repository(repository[, repository[, ...]][, key[, server = 'keyserver.ubuntu.com']])Add a custom repository as a software source.
Each
repositoryis a line as it would appear in your/etc/apt/sources.listfile, e.g.,deb URL DISTRIBUTION CATEGORY.keyandserverare 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
repositoryis the Launchpad user and project name, e.g.,chris-lea/node.js.keyandserverare 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):
apt-packages-ppa 'chris-lea/node.js' apt-packages-update apt-packages-install \ nodejs \ npm -
apt-packages-updateUpdate
aptitudepackages without any prompts. -
apt-packages-install(package[, package[, ...]])Perform an unattended installation of package(s).
Example:
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
apache2unnecessarily installed as part of thephp5meta-package):apt-packages-update apt-packages-install php5 apt-packages-purge 'apache2*'
-
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:
apt-packages-update system-upgrade
-
system-service(name, action)Command a system service, e.g.,
apache2,mysql, etc.Example:
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
glueto be a different character, e.g., an underscore_if you are using the result as part of a variable name.Example:
echo "Hello World!" | system-escape # prints 'hello-world'
-
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:
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 yourrubybinary which is assumed to be on$PATH.Example (install stable versions of Sass and link it as
/usr/bin/sass):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-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/namewherenameis the first argument to the function.To set up Fact-CGI, a new directory
.cgi-binis created inpathif it doesn't already exist.The virtual host is pointed to
pathor/nameifpathis 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
vagrantwebsite from/vagrantand enable PHP):PHP=/usr/bin/php-cgi apache-sites-create 'vagrant' apache-sites-enable vagrant apache-restart -
apache-restartRestart the Apache server and reload with new configuration.
Example:
apache-modules-enable actions rewrite fastcgi suexec apache-restart
-
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/namewherenameis the first argument to the function.The virtual host is pointed to
pathor/nameifpathis omitted.If you prefix the function with
PHP=any-value, PHP will be enabled through a PHP-FPM. You must havephp5-fpminstalled.The arguments
userandgroupare used to re-configure PHP-FPM's defaultwwwpool 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
vagrantwebsite from/vagrantand enable PHP):PHP=/usr/bin/php5-fpm nginx-sites-create 'vagrant' nginx-sites-enable vagrant nginx-restart
-
php-settings-update(name, value)Update a PHP setting value. This function will look for all
php.inifiles in/etc. For each file, aconf.ddirectory 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):
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):
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-restartRestart the PHP5-FPM server.
-
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
nameis empty, i.e., it doesn't contain any tables, the latest backup is piped tomysql.Example (where
/database-backupsis shared fromVagrantfile):mysql-database-restore 'project' '/database-backups'
-
mysql-remote-access-allowAllow remote passwordless
rootaccess for anywhere.This is only a good idea if the box is configured in 'Host-Only' network mode.
-
mysql-restartRestart the MySQL server and reload with new configuration.
-
ruby-gems-version(package)Check the installed version of a package, if any.
When a package is not installed,
0.0.0is 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:
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-packages-install(package[, package[, ...]])Perform an unattended global installation of package(s).
Example (install UglifyJS):
apt-packages-ppa 'chris-lea/node.js' apt-packages-update apt-packages-install \ nodejs \ npm npm-packages-install uglify-js
-
github-gems-install(repository[, repository[, ...]])Download and install RubyGems from GitHub.
The format of each
repositoryisuser/project[@branch]wherebranchcan be omitted and defaults tomaster.If a package is already installed, it will not be re-installed or upgraded.
Example (install unstable versions of Sass and Compass):
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
specificationis a string which contains the repository name (mandatory), version (optional) and./configurearguments (optional):repository@version --option --option argumentExample (install native PHP Redis extension from GitHub):
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'
-
env-append(env_key, env_value[, env_comment])Append an environment line to the global Bash/Zsh profile.
env_keycan be anything, but the following values have special meaning:PATH- extend thePATHenvironment variable with a new directory,source- include an external file (be careful not toset -e).
Any other key would be
exported when a new session is initialized.Example (set
JAVA_HOMEfor scripts that rely on it):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'
The ubuntu-extras.sh file provides useful but rarely used commands.
-
archive-file-unpack(file[, directory])Unpack the given archive
fileindirectory(created if missing). The format is guessed from the file extension.Example:
archive-file-unpack 'rsync-HEAD.tar.gz' '/tmp/'
-
package-ignore-preserve(package_name, package_path, preserved_path)Read a
.gitignorefile in the givenpackage_pathand 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:
package-ignore-preserve 'hadoop' 'vendor/hadoop' '/tmp/hadoop-download'
-
package-uri-download(uri[, target])Download the file at
urito the given directorytargetorSTDOUT.Example:
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_uritopackage_path. This function does a lot internally and can be used to automate installations of certain ZIP distributions. The URI and path support placeholders:%namewill be substituted with thepackage_name,%pathforpackage_path,%versionforpackage_version.
package_indexshould 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_pathis omitted, a variable{PACKAGE_NAME}_PATHis expected. E.g., ifpackage_nameis 'rsync' a variable namedRSYNC_PATHmust exist. Ifpackage_versionis omitted, a variable{PACKAGE_NAME}_VERSIONis expected.Requires
curlto be installed.Example (installing Node.js from binary distribution):
# {{{ 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-cleanup(tmp_path[, ...])Delete the contents of each
tmp_pathand halt script with the exit code of the last executed command.Example (compile a project and clean up on failure):
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"
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/22network (192.168.0.1through192.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
postgresuser server password. This also allows password-based authentication.Example:
postgres-password-reset 'password' -
postgres-autovacuum-on()Turn autovacuuming 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):
postgres-template-encoding 'UTF8' 'en_GB.utf8'
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.
directoryspecifies the process root directory.
The single-message files are created by expanding thetemplatevia 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.portspecifies the port on which to listen.
userswitches the user privileges after opening the network socket. The user must have permissions to write indirectory.serviceis an optional name of the system Upstart service. A file with this name is created under/etc/init/.backlogspecifies 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):smtp-sink-install '/vagrant/mail'The logged messages can be read using Thunderbird (append
.emlto the file name).
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
sudocommand, use an empty value.Example (set up Google DNS on a system with no
sudocommand):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):
COLORS=never apt-packages-update
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'.
The provisioning script below sets up Apache, SuExec, a virtual host for /vagrant (the default share) and remote root access to MySQL.
#!/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-restartCopyright (c) 2012 Stan Angeloff. See LICENSE.md for details.