Skip to content

Commit 34c70c8

Browse files
tombhmboersma
authored andcommitted
Full Vagrant provider. Squashed commits
1 parent 5f8d83b commit 34c70c8

15 files changed

Lines changed: 611 additions & 148 deletions

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,18 @@ htmlcov/
5050
.ruby-version
5151
venv/
5252
.vagrant
53+
Vagrantfile.local
5354
*.swp
55+
.bundle
5456

57+
# Chef setup
58+
.chef
59+
contrib/vagrant/knife-config/admin.pem
60+
contrib/vagrant/knife-config/chef-validator.pem
61+
contrib/vagrant/nodes/
62+
63+
# Broken symlinks that appear when mounting the codebase onto a vagrant VM
64+
# See Vagrantfile.local.example
65+
logs
66+
static
67+
venv

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
22

33
gem 'chef'
44
gem 'foodcritic'
5-
gem 'berkshelf'
5+
gem 'berkshelf', '3.0.0.beta3' # needed for --ssl-verify=false support
66

77
gem 'knife-ec2'
88
gem 'knife-rackspace'

Gemfile.lock

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ GEM
4949
ohai (>= 0.6.0, < 7.0.0)
5050
rest-client (>= 1.0.4, < 1.7.0)
5151
yajl-ruby (~> 1.1)
52-
chozo (0.6.1)
53-
activesupport (>= 3.2.0)
54-
hashie (>= 2.0.2)
55-
multi_json (>= 1.3.0)
5652
digital_ocean (1.2.0)
5753
faraday (~> 0.8.7)
5854
faraday_middleware (~> 0.9.0)
@@ -92,7 +88,6 @@ GEM
9288
httpclient (2.3.4.1)
9389
httpi (0.9.7)
9490
rack
95-
i18n (0.6.5)
9691
ipaddress (0.8.0)
9792
json (1.7.7)
9893
knife-digital_ocean (0.2.0)
@@ -206,7 +201,7 @@ PLATFORMS
206201
ruby
207202

208203
DEPENDENCIES
209-
berkshelf
204+
berkshelf (= 3.0.0.beta3)
210205
chef
211206
foodcritic
212207
knife-digital_ocean

Vagrantfile

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,47 @@
1-
# -*- mode: ruby -*-
2-
# vi: set ft=ruby :
31

4-
VAGRANTFILE_API_VERSION = "2"
5-
6-
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
7-
8-
# Give each controller and node additional memory
9-
config.vm.provider :virtualbox do |v|
10-
v.customize ["modifyvm", :id, "--memory", 2048]
11-
end
2+
Vagrant.configure("2") do |config|
3+
config.vm.box = "deis-node"
124

13-
# Deis Nodes
5+
# This is the vanilla Ubunutu 12.04 Precise box. It's about 350MB
146
config.vm.box_url = "https://s3-us-west-2.amazonaws.com/opdemand/deis-node.box"
15-
config.vm.box = "deis-node"
167

17-
# Deis Controller
18-
config.vm.define "deis-controller", primary: true do |controller|
19-
controller.vm.hostname = "deis-controller"
20-
controller.vm.network "private_network", ip: "192.168.61.100"
21-
end
8+
# This is a premade Deis controller box, probably 12.04, need to check. It's about 1.1GB
9+
# config.vm.box_url = "https://s3-us-west-2.amazonaws.com/opdemand/deis-controller.box"
2210

23-
# Node 1
24-
config.vm.define "deis-node-1" do |node1|
25-
node1.vm.hostname = "deis-node-1"
26-
node1.vm.network "private_network", ip: "192.168.61.101"
27-
end
11+
# Avahi-daemon will broadcast the server's address as deis-controller.local
12+
config.vm.host_name = "deis-controller"
2813

29-
# Node 2
30-
config.vm.define "deis-node-2" do |node2|
31-
node2.vm.hostname = "deis-node-2"
32-
node2.vm.network "private_network", ip: "192.168.61.102"
14+
# Create a public network, which generally matched to bridged network.
15+
# Bridged networks make the machine appear as another physical device on
16+
# your network. IP will be fetched via DCHP and associated to 'chefserver.local'
17+
# using avahi-daemon
18+
config.vm.network :public_network
19+
20+
# Chef Server requires at least 1G of RAM to install.
21+
# You may be able to run it with less once it's installed.
22+
config.vm.provider :virtualbox do |vb|
23+
vb.customize ["modifyvm", :id, "--memory", "1024"]
3324
end
3425

26+
# 'deis provider:discover' detects the host machine's user and IP address, however, that command cannot
27+
# be guareteed to run inside the deis codebase. Therefore we can't use that opportunity to discover
28+
# the path of the codebase on the host machine. Therefore we do it now as this Vagrantfile has to exist
29+
# inside the codebase.
30+
nodes_dir = File.dirname(__FILE__) + '/contrib/vagrant/nodes'
31+
32+
config.vm.provision :shell, inline: <<-SCRIPT
33+
# Avahi-daemon broadcasts the machine's hostname to local DNS.
34+
# Therefore 'deis-controller.local' in this case.
35+
sudo service avahi-daemon restart
36+
# Make a record of where the deis code base is on the host machine
37+
echo "#{nodes_dir}" > /home/vagrant/.host_nodes_dir
38+
SCRIPT
3539
end
40+
41+
# If you want to do some funky custom stuff to your box, but don't want those things tracked by git,
42+
# add a Vagrantfile.local and it will be included. You can use the exact same syntax as above. For
43+
# example you could mount your dev version of deis onto the VM and hack live on the VM;
44+
# `config.vm.share_folder "deis", "/opt/deis", "~/myworkspace/deis"
45+
# Or if you're low on RAM you can boot the VM with less RAM. Note that at least 1GB is needed for
46+
# installation, but you may be able to get away with 512MB once everything is installed.
47+
load "Vagrantfile.local" if File.exists? "Vagrantfile.local"

Vagrantfile.local.example

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
=begin
2+
This file augments the standard Vagrantfile with some developer-specific settings.
3+
You can override any settings you want. This file is in .gitignore, so can be specific
4+
to your own environment.
5+
6+
By default this file mounts your local development version of the Deis codebase onto the
7+
Deis Controller. It does this by mounting your code onto the VM at /vagrant, then moving
8+
the original installed code base to /opt/deis/controller_ORIG and symlinking
9+
/opt/deis/controller to the mounted code at /vagrant.
10+
11+
Because the deployed environment creates some extra files, like /deis/local_settings.py
12+
for example, these need to be then symlinked into the symlinked mount. Sound complicated?
13+
Yo dawg, I heard you like symlinks.
14+
=end
15+
16+
HOST_CODE_PATH = '/opt/deis/controller'
17+
HOST_BAK_PATH = "#{HOST_CODE_PATH}_ORIG"
18+
19+
# These paths are either in .gitignore or created after installation.
20+
# Therefore they need to be linked into the dev codebase.
21+
symlinks = [
22+
'deis/local_settings.py',
23+
'.secret_key',
24+
'logs',
25+
'static',
26+
'venv'
27+
].map { |path|
28+
"ln -s #{HOST_BAK_PATH}/#{path} #{HOST_CODE_PATH}/#{path}"
29+
}.join("\n")
30+
31+
Vagrant.configure("2") do |config|
32+
33+
config.vm.provider :virtualbox do |vb|
34+
#vb.customize ["modifyvm", :id, "--memory", "512"]
35+
end
36+
37+
# Mount the entire Deis codebase onto the VM at /vagrant
38+
# The first param is relative to the location of this file
39+
config.vm.synced_folder "../../../", "/vagrant", owner: 'deis', group: 'deis'
40+
41+
config.vm.provision :shell, inline: <<-SCRIPT
42+
if [ ! -d #{HOST_BAK_PATH} ]; then
43+
mv #{HOST_CODE_PATH} #{HOST_BAK_PATH}
44+
ln -s /vagrant #{HOST_CODE_PATH}
45+
46+
# Paths added after installation need linking into the codebase
47+
#{symlinks}
48+
49+
chown -R deis:deis #{HOST_CODE_PATH}
50+
fi
51+
SCRIPT
52+
53+
end

api/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class Provider(UuidAuditedModel):
110110
('rackspace', 'Rackspace Open Cloud'),
111111
('static', 'Static Node'),
112112
('digitalocean', 'Digital Ocean'),
113+
('vagrant', 'Local Vagrant VMs'),
113114
)
114115

115116
owner = models.ForeignKey(settings.AUTH_USER_MODEL)

client/deis.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,51 @@ def providers_discover(self, args):
17541754
else:
17551755
print('No Digitalocean credentials discovered.')
17561756

1757+
# Check for locally booted Deis Controller VM
1758+
try:
1759+
running_vms = subprocess.check_output(
1760+
['vboxmanage', 'list', 'runningvms'],
1761+
stderr=subprocess.PIPE)
1762+
except subprocess.CalledProcessError:
1763+
running_vms = ""
1764+
# Vagrant internally names a running VM using the folder name in which the Vagrantfile resides, eg;
1765+
# my-deis-code-folder_default_1383326629
1766+
deis_codebase_folder = self._session.git_root().split('/')[-1]
1767+
if deis_codebase_folder in running_vms:
1768+
print("Detected locally running Deis Controller VM")
1769+
# In order for the Controller to be able to boot Vagrant VMs it needs to run commands on the host machine.
1770+
# It does this via an SSH server. In order to access that server we need to send the current user's name
1771+
# and IP address.
1772+
try:
1773+
user = subprocess.check_output(
1774+
"whoami",
1775+
stderr=subprocess.PIPE
1776+
).strip()
1777+
ip = subprocess.check_output(
1778+
"/sbin/ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n1",
1779+
stderr=subprocess.PIPE,
1780+
shell=True
1781+
).strip()
1782+
except subprocess.CalledProcessError:
1783+
print("Error detecting username and host IP address.")
1784+
sys.exit(1)
1785+
creds = {
1786+
'user': user,
1787+
'ip': ip
1788+
}
1789+
body = {'creds': json.dumps(creds)}
1790+
sys.stdout.write('Activating Vagrant as a provider... ')
1791+
sys.stdout.flush()
1792+
response = self._dispatch('patch', '/api/providers/vagrant',
1793+
json.dumps(body))
1794+
if response.status_code == requests.codes.ok: # @UndefinedVariable
1795+
print('done')
1796+
else:
1797+
raise ResponseError(response)
1798+
else:
1799+
print("No Vagrant VMs detected")
1800+
1801+
17571802
def providers_info(self, args):
17581803
"""
17591804
Print information about a specific provider

contrib/vagrant/README.md

Lines changed: 104 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,116 @@
1-
Provision a Deis Controller on Vagrant
2-
======================================
1+
Local development workflow for Deis
2+
================================================================
33

4-
This document describes how to set up a Deis controller and two nodes with
5-
Vagrant for testing.
4+
This document suggests some ways that might make developing Deis easier and cheaper. You don't have to follow
5+
them all.
66

7-
1. Install VirtualBox version 4.2.18. (Vagrant does not support version 4.3.)
8-
Then start VirtualBox and install the VirtualBox Extension Pack for 4.2.18.
7+
1. You'll need VirtualBox >= `4.2.18`. We recommend installing Vagrant with their binary installer from http://downloads.vagrantup.com
8+
Vagrant 1.3.5 has support for VirtualBox 4.3
99

10-
2. Install Vagrant version 1.3.5 or later. Rather than fight Ruby dependencies,
11-
use a binary installer from vagrantup.com.
10+
2. Firstly you need to decide whether to use your own Chef Server or the free tier of the hosted enterprise
11+
service from Opscode. The free tier has a limit of 5 nodes which is more then enough for development. Also
12+
bear in mind that a local Chef Server VM will take up at least 1GB of RAM.
1213

13-
3. Run the provisioning script:
14-
```console
15-
$ ./contrib/vagrant/provision-vagrant-controller.sh
16-
```
14+
**Local Chef Server**
15+
* `cd [DEIS_DIR] && ln -s contrib/vagrant/knife-config .chef`
16+
* `vagrant up` the chef server Vagrantfile.
17+
* copy the admin.pem and validation.pem files for your own knife client
18+
`scp -r root@chefserver.local:/etc/chef-server/admin.pem [DEIS_DIR]/contrib/vagrant/knife-config/`
19+
`scp -r root@chefserver.local:/etc/chef-server/chef-validator.pem [DEIS_DIR]/contrib/vagrant/knife-config/`
1720

18-
This script will:
19-
- Create the data bags in your Chef account to support Deis
20-
- Run `vagrant up` to create a Deis controller and 2 static nodes
21-
- Register the controller with Chef and install Deis and supporting software
21+
**Hosted Chef Server**
22+
* Goto https://getchef.opscode.com/signup and fill in your details.
23+
* Goto https://preview.opscode.com/login and sign in to your Chef Server.
24+
* Click on the 'Administration' tab and choose your organisation. There should be a tab in the sidebar that says
25+
'Starter Kit'. Click it and it will start a small download.
26+
* Inside the Starter Kit there is a '.chef' folder. Copy it to the root of your Deis codebase.
2227

23-
4. Register a user
28+
3. Now you can follow the standard deis setup:
29+
```bash
30+
bundle install # Installs gem files like the knife tool
31+
berks install # Downloads the relevant cookbooks
32+
# '--ssl-verify' is only needed when using a local Chef Server
33+
berks upload [--ssl-verify=false] # Upload the cookbooks to the Chef Server
34+
```
2435

25-
5. Run the script to create a static formation:
26-
```console
27-
$ ./contrib/vagrant/create-static-formation.sh
28-
```
36+
4. Use the provision script to boot the deis controller.
37+
* If you don't already have the deis-node Vagrant box installed (~1GB). This step might take a long time! If for some reason
38+
you want to manually add it, use:
39+
`vagrant box add deis-node https://s3-us-west-2.amazonaws.com/opdemand/deis-node.box`
40+
* `cd contrib/vagrant && ./provision-controller.sh`
41+
* You will be asked to add the Controller's SSH key to your local SSH server. This will allow the Controller
42+
to run vagrant commands on your machine to bootstrap new nodes.
43+
* If you are using a local Chef Server you will need to tell it that your new controller has permission to create
44+
nodes. Use:
45+
`knife client edit deis-controller`
46+
and your default text editor will launch, you need to set 'admin' to 'true'.
47+
48+
5. The Controller needs to be able to run Vagrant commands on your host machine. It does this via SSH. Therefore
49+
you will need a running SSH server open on port 22.
50+
* On Debian-flavoured Linux you just need to;
51+
`sudo apt-get install openssh-server`
52+
* On Mac OSX you just need to go to **System Preferences -> Sharing** and enable 'Remote Login'.
53+
* **NB** If your machine's IP changes the Controller won't be able to run commands any more. Currently you aren't informed
54+
of this, you just get a 500 error from the client. If you tail `/var/log/deis/celeryd.log` though you'll know. When this
55+
does happen just reupload your IP with `deis providers:discover`.
56+
57+
6. If you want to hack on the actual codebase, you can mount your local codebase onto the VM
58+
by using the custom Vagrantfile.local.
59+
* `cp Vagrantfile.local.example Vagrantfile.local` (don't worry it's in .gitignore)
60+
* Update the VM with `vagrant reload --provision`
61+
* When mounted you can use your favourite editor to change the code _on your local machine's path_ and then run
62+
`service deis-server restart` and/or `service deis-worker restart` on the VM for your changes to instantly take effect.
63+
* It's worth having a read of `Vagrantfile.local.example`
64+
65+
7. If you want to hack on the command line client (`/client/deis.py`), install your local dev version rather than
66+
the one from Pip.
67+
* `cd deis && make install` This will symlink the dev version to your executables path.
68+
* Your deis controller is available at http://deis-controller.local so you can register with;
69+
`deis register http://deis-controller.local`
70+
71+
8. Right, time to boot up some nodes!
72+
* Create a foramtion with a vagrant flavour, 512MB, 1024MB and 2048MB are available.
73+
`deis formations:create dev --flavor=vagrant-512 --domain=deisapp.local`
74+
* Scale a node with `deis nodes:scale dev runtime=1` Be patient, this is the command that runs vagrant commands. Scaling a single node
75+
can take about 5 mins.
76+
* Then create and push your app as per the usual documentation.
77+
78+
## Useful development commands
79+
* To use Django's manage.py:
80+
* SSH in to the VM with `vagrant ssh`
81+
* Switch user to deis with `sudo su deis`
82+
* `cd /opt/deis/controller` and activate Venv with `. venv/bin/activate`
83+
* Get a list of commands with; `./manage.py help`.
84+
85+
* To reset the DB:
86+
* On the VM run `sudo su postgres -c 'dropdb deis && createdb --encoding=utf8 --template=template0 deis'`
87+
* When you restart the server with `sudo service deis-server restart` Django will reinstall the DB.
88+
* You'll need to reupdate the Django's Site Object
89+
`sudo su deis -c "psql deis -c \"UPDATE django_site SET domain = 'deis-controller.local', name = 'deis-controller.local' WHERE id = 1 \""`
90+
91+
* This is useful for uploading your own local version of the cookbooks, rather than the Github versions:
92+
* `knife cookbook upload deis --cookbook-path [deis-cookbook path] --force`
93+
* You need to change directory structure though as knife gets the cookbook name from the folder name. So, for example I use;
94+
95+
```bash
96+
deis
97+
|__ code
98+
|__ api
99+
|__ bin
100+
|__ client
101+
|__ cm
102+
|__ ... and so on
103+
|__ cookbooks
104+
|__ deis
105+
|__ attributes
106+
|__ definitions
107+
|__ recipes
108+
|__ ... and so on
109+
```
29110

30111
Notes
31112
-----
32113

33114
Mac OS X: if you see an error such as
34-
"failed to open /dev/vboxnetctl", try restarting VirtualBox:
35-
sudo /Library/StartupItems/VirtualBox/VirtualBox restart
115+
'failed to open /dev/vboxnetctl', try restarting VirtualBox:
116+
sudo /Library/StartupItems/VirtualBox/VirtualBox restart

0 commit comments

Comments
 (0)