Skip to content

Commit e054ffb

Browse files
committed
Merge branch '73-digitalocean-provider' of https://github.com/bacongobbler/deis into bacongobbler-73-digitalocean-provider
Conflicts: Gemfile.lock
2 parents da153a6 + 3ba4960 commit e054ffb

10 files changed

Lines changed: 380 additions & 3 deletions

File tree

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ gem 'berkshelf'
66

77
gem 'knife-ec2'
88
gem 'knife-rackspace'
9+
gem 'knife-digital_ocean'

Gemfile.lock

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ GEM
5050
activesupport (>= 3.2.0)
5151
hashie (>= 2.0.2)
5252
multi_json (>= 1.3.0)
53+
digital_ocean (1.2.0)
54+
faraday (~> 0.8.7)
55+
faraday_middleware (~> 0.9.0)
56+
json
57+
rash
5358
em-winrm (0.5.4)
5459
eventmachine (= 1.0.0.beta.3)
5560
mixlib-log (>= 1.3.0)
@@ -60,7 +65,9 @@ GEM
6065
excon (0.25.3)
6166
faraday (0.8.8)
6267
multipart-post (~> 1.2.0)
63-
ffi (1.9.0)
68+
faraday_middleware (0.9.0)
69+
faraday (>= 0.7.4, < 0.9)
70+
ffi (1.9.1)
6471
fog (1.15.0)
6572
builder
6673
excon (~> 0.25.0)
@@ -85,6 +92,10 @@ GEM
8592
i18n (0.6.5)
8693
ipaddress (0.8.0)
8794
json (1.7.7)
95+
knife-digital_ocean (0.2.0)
96+
chef (>= 10.18)
97+
digital_ocean (~> 1.2.0)
98+
highline
8899
knife-ec2 (0.6.4)
89100
chef (>= 0.10.10)
90101
fog (~> 1.6)
@@ -132,6 +143,8 @@ GEM
132143
systemu
133144
yajl-ruby
134145
rack (1.5.2)
146+
rash (0.4.0)
147+
hashie (~> 2.0.0)
135148
rest-client (1.6.7)
136149
mime-types (>= 1.16)
137150
retryable (1.3.3)
@@ -189,5 +202,6 @@ DEPENDENCIES
189202
berkshelf
190203
chef
191204
foodcritic
205+
knife-digital_ocean
192206
knife-ec2
193207
knife-rackspace

api/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class Provider(UuidAuditedModel):
109109
('mock', 'Mock Reference Provider'),
110110
('rackspace', 'Rackspace Open Cloud'),
111111
('static', 'Static Node'),
112+
('digitalocean', 'Digital Ocean'),
112113
)
113114

114115
owner = models.ForeignKey(settings.AUTH_USER_MODEL)

client/deis.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,14 @@ def providers_create(self, args):
16571657
'api_key': os.environ['RACKSPACE_API_KEY'],
16581658
'identity_type': os.environ.get('CLOUD_ID_TYPE', 'rackspace'),
16591659
}
1660+
elif type == 'digitalocean':
1661+
# read creds from envvars
1662+
for k in ('DIGITALOCEAN_CLIENT_ID', 'DIGITALOCEAN_API_KEY'):
1663+
if not k in os.environ:
1664+
msg = "Missing environment variable: {}".format(k)
1665+
raise EnvironmentError(msg)
1666+
creds = {'client_id': os.environ['DIGITALOCEAN_CLIENT_ID'],
1667+
'api_key': os.environ['DIGITALOCEAN_API_KEY']}
16601668
else:
16611669
creds = json.loads(args.get('<creds>'))
16621670
id = args.get('<id>') # @ReservedAssignment
@@ -1701,7 +1709,7 @@ def providers_discover(self, args):
17011709
else:
17021710
raise ResponseError(response)
17031711
else:
1704-
print('No credentials discovered, did you install the EC2 Command Line tools?')
1712+
print('No EC2 credentials discovered. Did you install the EC2 Command Line tools?')
17051713
if 'RACKSPACE_API_KEY' in os.environ and 'RACKSPACE_USERNAME' in os.environ:
17061714
print("Found Rackspace credentials: {}".format(os.environ['RACKSPACE_API_KEY']))
17071715
inp = raw_input('Import these credentials? (y/n) : ')
@@ -1721,7 +1729,27 @@ def providers_discover(self, args):
17211729
else:
17221730
raise ResponseError(response)
17231731
else:
1724-
print('No Rackspace credentials discovered')
1732+
print('No Rackspace credentials discovered.')
1733+
if 'DIGITALOCEAN_API_KEY' in os.environ and 'DIGITALOCEAN_CLIENT_ID' in os.environ:
1734+
print("Found Digitalocean credentials: {}".format(os.environ['DIGITALOCEAN_CLIENT_ID']))
1735+
inp = raw_input('Import these credentials? (y/n) : ')
1736+
if inp.lower().strip('\n') != 'y':
1737+
print('Aborting.')
1738+
else:
1739+
creds = {'client_id': os.environ['DIGITALOCEAN_CLIENT_ID'],
1740+
'api_key': os.environ['DIGITALOCEAN_API_KEY'],
1741+
}
1742+
body = {'creds': json.dumps(creds)}
1743+
sys.stdout.write('Uploading Digitalocean credentials... ')
1744+
sys.stdout.flush()
1745+
response = self._dispatch('patch', 'api/providers/digitalocean',
1746+
json.dumps(body))
1747+
if response.status_code == requests.codes.ok: # @UndefinedVariable
1748+
print('done')
1749+
else:
1750+
raise ResponseError(response)
1751+
else:
1752+
print('No Digitalocean credentials discovered.')
17251753

17261754
def providers_info(self, args):
17271755
"""

contrib/digitalocean/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
How to Provision a Deis Controller on Digital Ocean
2+
===================================================
3+
4+
Here are the steps to get started on Digital Ocean:
5+
6+
* install [knife-digital_ocean][kdo]
7+
8+
```
9+
bundle install
10+
```
11+
12+
* install python requirements
13+
14+
```
15+
pip install -r requirements.txt
16+
```
17+
18+
* add the following to ~/.chef/knife.rb
19+
20+
```
21+
knife[:digital_ocean_client_id] = "your digital ocean client ID"
22+
knife[:digital_ocean_api_key] = "your digital ocean API key"
23+
```
24+
25+
* Follow the steps provided in contrib/digitalocean/prepare-digitalocean-snapshot.sh
26+
* Run this command to start the provisioning process
27+
28+
```
29+
./contrib/digitalocean/provision-digitalocean-controller.sh
30+
```
31+
32+
This script will read from your knife config file, create a new SSH key for the controller, upload the SSH key to digital ocean, and provision a Deis Controller from the snapshot created.
33+
34+
[kdo]: https://github.com/rmoriz/knife-digital_ocean
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/bin/bash -ex
2+
3+
#
4+
# Prepare a Deis-optimized snapshot from a vanilla Ubuntu 12.04.3 droplet.
5+
#
6+
# Instructions:
7+
#
8+
# 1. Launch a vanilla Ubuntu 12.04.3 droplet (64-bit)
9+
# 2. Run this script (as root!) to install the packages necessary for faster boot times
10+
# 3. Create a new snapshot of this droplet with the name 'deis-base'
11+
# 4. Create/update your Deis flavors to use your new snapshot
12+
#
13+
14+
THIS_DIR=$(cd $(dirname $0); pwd) # absolute path
15+
CONTRIB_DIR=$(dirname $THIS_DIR)
16+
17+
# upgrade to latest packages
18+
apt-get update
19+
apt-get upgrade -yq
20+
21+
# install HTTPS transport support
22+
apt-get install -qy apt-transport-https
23+
24+
# install docker's dependencies
25+
apt-get install python-software-properties -y
26+
27+
# Add the Docker repository key to your local keychain
28+
# using apt-key finger you can check the fingerprint matches 36A1 D786 9245 C895 0F96 6E92 D857 6A8B A88D 21E9
29+
curl https://get.docker.io/gpg | apt-key add -
30+
31+
# Add the Docker repository to your apt sources list.
32+
echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list
33+
34+
# upgrade to latest packages
35+
apt-get update
36+
apt-get -qy upgrade
37+
38+
# install required packages
39+
apt-get install lxc-docker curl git make python-setuptools python-pip -yq
40+
41+
# create buildstep docker image
42+
git clone -b deis https://github.com/opdemand/buildstep.git
43+
cd buildstep
44+
git checkout deis
45+
make
46+
cd ..
47+
rm -rf buildstep
48+
49+
# install chef 11.x deps
50+
apt-get install -yq ruby1.9.1 ruby1.9.1-dev make
51+
update-alternatives --set ruby /usr/bin/ruby1.9.1
52+
update-alternatives --set gem /usr/bin/gem1.9.1
53+
54+
# clean and remove old packages
55+
apt-get clean
56+
apt-get autoremove -yq
57+
58+
# reset cloud-init
59+
rm -rf /var/lib/cloud
60+
61+
# purge SSH authorized keys
62+
rm -f /root/.ssh/authorized_keys
63+
64+
# ssh host keys are automatically regenerated
65+
# on system boot by ubuntu cloud init
66+
67+
# purge /var/log
68+
find /var/log -type f | xargs rm
69+
70+
# flush writes to block storage
71+
sync
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Usage: ./provision-digitalocean-controller.sh <region-id>
4+
#
5+
# Retrieve the region-id by using `knife digital_ocean region list`
6+
#
7+
8+
function echo_color {
9+
echo -e "\033[1m$1\033[0m"
10+
}
11+
12+
THIS_DIR=$(cd $(dirname $0); pwd) # absolute path
13+
CONTRIB_DIR=$(dirname $THIS_DIR)
14+
15+
echo_color "Provisioning a deis controller on Digital Ocean!"
16+
17+
# check for Deis' general dependencies
18+
if ! $CONTRIB_DIR/check-deis-deps.sh; then
19+
echo 'Deis is missing some dependencies.'
20+
exit 1
21+
fi
22+
23+
# connection details for using digital ocean's API
24+
client_id=$DIGITALOCEAN_CLIENT_ID
25+
api_key=$DIGITALOCEAN_API_KEY
26+
27+
# Check that client ID and API key was set
28+
if test -z $client_id; then
29+
echo "Please add your client id to ${knife_file}."
30+
fi
31+
32+
if test -z $api_key; then
33+
echo "Please add your api key to ${knife_file}."
34+
fi
35+
36+
#################
37+
# chef settings #
38+
#################
39+
40+
node_name=deis-controller
41+
run_list="recipe[deis::controller]"
42+
chef_version=11.4.4
43+
44+
##########################
45+
# digital ocean settings #
46+
##########################
47+
48+
# the name of the location we want to work with
49+
location_id=$1
50+
# The snapshot that we want to use (deis-base)
51+
image_id=$(knife digital_ocean image list | grep "deis-base" | awk '{print $1}')
52+
# the ID of the size (1GB)
53+
size_id=$(knife digital_ocean size list | grep "2GB" | awk '{print $1}')
54+
55+
################
56+
# SSH settings #
57+
################
58+
59+
key_name="deis-controller"
60+
ssh_key_path=~/.ssh/$key_name
61+
62+
# create ssh keypair and store it
63+
if ! test -e $ssh_key_path; then
64+
echo_color "Creating new SSH key: $key_name"
65+
set -x
66+
ssh-keygen -f $ssh_key_path -t rsa -N '' -C "deis-controller" >/dev/null
67+
curl -X GET \
68+
--data-urlencode "name=$node_name" \
69+
--data-urlencode "ssh_pub_key=$(cat $ssh_key_path.pub)" \
70+
--data-urlencode "client_id=$client_id" \
71+
--data-urlencode "api_key=$api_key" \
72+
https://api.digitalocean.com/ssh_keys/new
73+
ssh-add $ssh_key_path
74+
set +x
75+
echo_color "Saved to $ssh_key_path"
76+
else
77+
echo_color "WARNING: SSH key $ssh_key_path exists, skipping upload"
78+
fi
79+
80+
# get the id of the SSH key that we just uploaded
81+
ssh_key_id=$(knife digital_ocean sshkey list | grep "$key_name" | awk '{print $1}')
82+
83+
# create data bags
84+
knife data bag create deis-users 2>/dev/null
85+
knife data bag create deis-formations 2>/dev/null
86+
knife data bag create deis-apps 2>/dev/null
87+
88+
# trigger digital ocean instance bootstrap
89+
echo_color "Provisioning $node_name with knife digital_ocean..."
90+
91+
set -x
92+
knife digital_ocean droplet create \
93+
--server-name $node_name \
94+
--image $image_id \
95+
--location $location_id \
96+
--size $size_id \
97+
--ssh-keys $ssh_key_id \
98+
--identity-file $ssh_key_path \
99+
--bootstrap \
100+
--run-list $run_list
101+
set +x

dev_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ django-json-field==0.5.5
99
django-yamlfield==0.5
1010
djangorestframework==2.3.8
1111
git+git://github.com/surfly/gevent.git@1.0rc3#egg=gevent
12+
dop==0.1.4
1213
gunicorn==18.0
1314
paramiko==1.12.0
1415
psycopg2==2.5.1

0 commit comments

Comments
 (0)