Vagrant is an easy way to spin up a development VM running Canvas.
There are a few prerequisites to meet before you can start.
- Virtualbox
- Vagrant
- Vagrant plugin: vagrant-hostmanager
- Ansible
You can install all of these individually using their GUI installer, or you can use the command line:
# install homebrew if you haven't already
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
# install brew/cask
brew install caskroom/cask/brew-cask
# install virtualbox
brew cask install virtualbox
# install vagrant and plugin(s)
brew cask install vagrant
vagrant plugin install vagrant-hostmanager
# install ansible
brew install ansible
During vagrant up
and vagrant halt
, vagrant will attempt to modify your /etc/hosts and /etc/exports files with sudo. This will prompt you for your administrator password. This is annoying. Add the following to the bottom of your /etc/sudoers file (use sudo visudo
, don't edit the file directly):
# Vagrant
Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD = /sbin/nfsd restart
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed
Cmnd_Alias VAGRANT_HOSTMANAGER_UPDATE = /bin/cp /Users/YOUR_USER_NAME/.vagrant.d/tmp/hosts.local /etc/hosts
%admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE, VAGRANT_HOSTMANAGER_UPDATE
Replace YOUR_USER_NAME with your actual username.
Placing a YAML file named vagrantrc.yml
at the root of the canvas directory allows you to customize the Vagrant configuration. The following features are customizable:
- Hostname: By default, the hostname is
canvas.dev
. Setting a:hostname
property will override this. - IP address: DHCP is used by default. Setting an
:ip_address
property will set a static IP. - Additional NFS mounts: By default, the canvas root directory is NFS exported and mounted at
/vagrant
on the guest. You can specify additional paths on the host filesystem to be exported and mounted on the guest in a:mount_directories
list. The:local_path
property must be the full path on your local disk. The:mount_at
property must be the full path where the exprort will be mounted. - Pre-provision shell script: You can specify shell commands to be called before the main Ansible provisioning starts in a
:pre_provision_script
property. - Post-provision shell script: You can specify shell commands to be called after the final shell provisioner in a
:post_provision_script
property.
vagrantrc.yml
should be ignored in either your global gitignore file or in .git/info/exclude
The following example sets a custom hostname (instead of canvas.dev
), a static IP address (instead of DHCP), mounts the Canvas Spaces plugins from the host and runs a pre-provisioner script to set up Canvas Spaces:
:hostname: canvas-spaces-test.dev
:ip_address: 10.0.5.5
:mount_directories:
-
:local_path: '/local/path/to/canvas_spaces'
:mount_at: '/vagrant/gems/plugins/canvas_spaces'
-
:local_path: '/local/path/to/canvas_spaces_client_app'
:mount_at: '/vagrant/client_apps/canvas_spaces'
:pre_provision_script: 'cd /vagrant/client_apps/canvas_spaces && npm install && script/canvas_setup'
cd /path/to/your/canvas/repository
vagrant up
Go grab lunch. When you come back, go to http://canvas.dev in your browser. Type vagrant ssh
from within your repo directory to ssh to the VM.
When you type vagrant up
for the first time, the following things happen:
- Vagrant downloads a "base box". In this case, it's a Ubuntu Trusty 14.04.1 LTS image, slightly customized to change the
vagrant
user's UID to 501 so that NFS mounts from a Mac work better. - Vagrant tells Virtualbox how to configure the VM (number of CPUs and memory, network settings, etc).
- Vagrant modifies your local /etc/exports file to export your current directory (e.g. your Canvas repository) over NFS
- Vagrant modifies your /etc/hosts file to point the VM's IP address at
canvas.dev
- Vagrant boots the VM
After the VM has booted, Vagrant starts the provisioning step. For details on what provisioning entails, see the Vagrant docs. In our case, we're using Ansible for provisioning, because it was far easier than getting Puppet to work. Ideally we'd use Puppet because Ansible has a host-side dependency, while Puppet doesn't.
Ansible uses "playbooks" for provisioning. These are all located in the ./provision
directory. Generally, the following happens during the provisioning phase:
- Dependencies are installed
- Bundler is installed
- Apache is installed and configured with a template config file
- Passenger is installed and configured with a template config file
- Postgres is installed and the Canvas databases are created
- Canvas-specific tasks run:
- bundle install
- npm install
- config files are copied
- compile assets
- initial db setup
- db migrate
- db load notifications
- symlink canvas_init script and start at boot
Finally, after the Ansible provisioning is complete, a shell script provisioner runs. This restarts both delayed jobs and apache. This is mostly for subsequent runs of vagrant up
-- apache and delayed jobs are set to run at boot, but because NFS gets mounted after the init.d scripts run, they need to be bounced.
At this point, you now have a generic Canvas installation with a fresh, empty database. You should be able to visit [http://canvas.dev] in your browser and log in as the admin user (vagrant@localhost / vagrant). You should also be able to ssh to the VM by typing vagrant ssh
from within your Canvas repo directory.
Vagrant mounts your canvas repo's working directory over NFS at /vagrant on the VM. You can edit code on your local workstation in whatever editor or IDE you like, or you can ssh to the VM (vagrant ssh
) and edit there with vim.
The vagrant VM is configured to run Canvas in development mode. In development mode, classes are reloaded on every HTTP request; while this is slow, it means that you don't need to restart the server after making a change. If you want to run in production mode; edit /etc/apache2/sites-available/canvas.conf
(on the VM) and change the RAILS_ENV variable to production
. Both production and development modes point at the same database.
If you need to restart passenger, you can touch tmp/restart.txt
(which you can do from your local machine or the VM) or you can restart Apache (sudo service apache2 restart
on the VM).
If you upgade the Canvas code, you'll need to rerun some of the provisioning steps (e.g. bundle install, compile_assets, db:migrate). The easiest way to do this is to run vagrant provision
from your local machine. This will re-run the provisioning steps that happened the first time you ran vagrant up
. Note that it will delete vendor/bundle
and Gemfile.lock
prior to re-running bundle install
. It will not re-run the initial DB setup unless /home/vagrant/CanvasDBSetupDone
is not present (this file gets created after the initial db setup runs the first time).
You can, of course, just ssh to the VM and run the normal upgrade steps yourself.
Running vagrant up
and some of the provisioning steps creates some files that should be ignored:
.vagrant
vendor/bundle
/vendor/plugins/*/public/*/compiled/
vagrantrc.yml
Editing the Canvas .gitignore
file often causes conflicts, so instead you should do one of the following:
You can create a global ignore file that will apply to all git repos on your local machine. This is a good place to put things like .DS_Store files, the .vagrant directory, etc. See here for instructions on creating a global ignore file.
You can add the exluded files to .git/info/excludes
(within the repo directory). These excludes are confined to that specific repo and are not pushed to any git remotes, so you will need to re-add them if you clone the repo elsewhere.