kitchen-digital_ocean 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +17 -0
- data/README.md +48 -0
- data/kitchen-digital_ocean.gemspec +28 -0
- data/lib/kitchen/driver/digital_ocean.rb +184 -0
- metadata +150 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: fc1701a957915027c014f74ee178a5222744d634
|
|
4
|
+
data.tar.gz: c5355d1367f8c36c9144aa7239798cdec06f8f88
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 209df6a181b18ab1a2977ba447e7eab39700b13b74c3b28e15b500ee0346799d3b04005a07cc9bb04e2751b7d4f3cfa2c0ed9943940e709ccbd66068336d381b
|
|
7
|
+
data.tar.gz: 092cee75876360102fc19761d7f00b013271d7d7baa561b411c5069d920e4795bb8b0fee375dda022053a05c93d924fa9f1efde5cab78a9ba31b81f6b05f6f04
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Author:: Greg Fitzgerald (<greg@gregf.org>)
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2013, Greg Fitzgerald
|
|
4
|
+
Copyright (C) 2014, Will Farrington
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
data/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Kitchen::DigitalOcean
|
|
2
|
+
|
|
3
|
+
A Test Kitchen driver for Digital Ocean API v2.
|
|
4
|
+
|
|
5
|
+
Forked from the official [test-kitchen/kitchen-digitalocean driver](https://github.com/test-kitchen/kitchen-digitalocean).
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
* Obviously, this gem depends on Test Kitchen.
|
|
10
|
+
* It also depends on `rest_client`, but that'll automatically be handled via RubyGems.
|
|
11
|
+
* You also need a Digital Ocean account.
|
|
12
|
+
* You need to define the following environment variables:
|
|
13
|
+
* `DIGITALOCEAN_API_TOKEN` -- your API token (requires read+write)
|
|
14
|
+
* `DIGITALOCEAN_SSH_KEYS` -- comma-separated list of SSH key IDs (get from Digital Ocean API)
|
|
15
|
+
|
|
16
|
+
## Installation and Setup
|
|
17
|
+
|
|
18
|
+
1. Use ChefDK.
|
|
19
|
+
1. Be happy.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
chef gem install kitchen-digital_ocean
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
In your `.kitchen.yml` or `.kitchen.local.yml`:
|
|
26
|
+
|
|
27
|
+
``` yaml
|
|
28
|
+
---
|
|
29
|
+
driver:
|
|
30
|
+
name: digitalocean
|
|
31
|
+
|
|
32
|
+
platforms:
|
|
33
|
+
- name: ubuntu-12.10
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Additional configuration options
|
|
37
|
+
|
|
38
|
+
* `username` -- user name to SSH with
|
|
39
|
+
* `port` -- SSH port to SSH into
|
|
40
|
+
* `private_networking` -- enable private networking on the drpolet
|
|
41
|
+
* `region` -- the region to provision the droplet in; you can use the short slugs (eg. `nyc2`)
|
|
42
|
+
* `size` -- the size to provision the droplet as; you can use the short slugs (eg. `2gb`)
|
|
43
|
+
* `image` -- the image to provision the droplet with; you can use the short slugs
|
|
44
|
+
* `server_name` -- you probably want to leave this alone
|
|
45
|
+
* `digitalocean_api_token` -- you can set this, but seriously use the environment variable above
|
|
46
|
+
* `digitalocean_ssh_keys` -- you can set this, but seriously use the environment variable above
|
|
47
|
+
|
|
48
|
+
For more details, see the [Digital Ocean API documentation](https://developers.digitalocean.com/).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = 'kitchen-digital_ocean'
|
|
5
|
+
spec.version = '0.3.0'
|
|
6
|
+
spec.authors = ['Will Farrington', 'Greg Fitzgerald']
|
|
7
|
+
spec.email = ['wfarr@digitalocean.com']
|
|
8
|
+
spec.description = 'A Test Kitchen Driver for Digital Ocean using apiv2'
|
|
9
|
+
spec.summary = spec.description
|
|
10
|
+
spec.homepage = 'https://github.com/wfarr/kitchen-digital_ocean'
|
|
11
|
+
spec.license = 'Apache 2.0'
|
|
12
|
+
|
|
13
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
14
|
+
spec.executables = []
|
|
15
|
+
spec.test_files = []
|
|
16
|
+
spec.require_paths = ['lib']
|
|
17
|
+
|
|
18
|
+
spec.add_dependency 'test-kitchen', '~> 1.0'
|
|
19
|
+
spec.add_dependency 'rest_client'
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency 'rubocop'
|
|
22
|
+
spec.add_development_dependency 'rake'
|
|
23
|
+
spec.add_development_dependency 'cane'
|
|
24
|
+
spec.add_development_dependency 'countloc'
|
|
25
|
+
spec.add_development_dependency 'rspec'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# vim: ai et ts=2 sts=2 sw=2 ft=ruby
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Author:: Greg Fitzgerald (<greg@gregf.org>)
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2013, Greg Fitzgerald
|
|
6
|
+
# Copyright (C) 2014, Will Farrington
|
|
7
|
+
#
|
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
# you may not use this file except in compliance with the License.
|
|
10
|
+
# You may obtain a copy of the License at
|
|
11
|
+
#
|
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
#
|
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
# See the License for the specific language governing permissions and
|
|
18
|
+
# limitations under the License.
|
|
19
|
+
|
|
20
|
+
require 'rest_client'
|
|
21
|
+
require 'json'
|
|
22
|
+
require 'kitchen'
|
|
23
|
+
require 'etc'
|
|
24
|
+
require 'socket'
|
|
25
|
+
|
|
26
|
+
module Kitchen
|
|
27
|
+
module Driver
|
|
28
|
+
# Digital Ocean driver for Kitchen.
|
|
29
|
+
#
|
|
30
|
+
# @author Greg Fitzgerald <greg@gregf.org>
|
|
31
|
+
class DigitalOcean < Kitchen::Driver::SSHBase
|
|
32
|
+
IMAGES = {
|
|
33
|
+
"ubuntu-12.04" => "ubuntu-12-04-x64",
|
|
34
|
+
"ubuntu-14.04" => "ubuntu-14-04-x64",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
default_config :username, 'root'
|
|
38
|
+
default_config :port, '22'
|
|
39
|
+
|
|
40
|
+
default_config :private_networking, true
|
|
41
|
+
|
|
42
|
+
default_config :region, 'nyc2'
|
|
43
|
+
default_config :size, '2gb'
|
|
44
|
+
|
|
45
|
+
default_config :image do |driver|
|
|
46
|
+
driver.default_image
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
default_config :server_name do |driver|
|
|
50
|
+
driver.default_name
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
default_config :digitalocean_api_token do
|
|
54
|
+
ENV['DIGITALOCEAN_API_TOKEN']
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
default_config :ssh_keys do
|
|
58
|
+
ENV['DIGITALOCEAN_SSH_KEYS']
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
required_config :digitalocean_api_token
|
|
62
|
+
required_config :ssh_keys
|
|
63
|
+
|
|
64
|
+
def create(state)
|
|
65
|
+
droplet = create_droplet
|
|
66
|
+
state[:server_id] = droplet['id']
|
|
67
|
+
|
|
68
|
+
info("Digital Ocean instance <#{state[:server_id]}> created.")
|
|
69
|
+
|
|
70
|
+
while true
|
|
71
|
+
sleep 10
|
|
72
|
+
droplet = get_droplet(state[:server_id])
|
|
73
|
+
|
|
74
|
+
break if droplet \
|
|
75
|
+
&& droplet['networks'] \
|
|
76
|
+
&& droplet['networks']['v4'] \
|
|
77
|
+
&& droplet['networks']['v4'].any? { |n| n['type'] == 'public' }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
state[:hostname] = droplet['networks']['v4'].detect { |n| n['type'] == 'public' }['ip_address']
|
|
81
|
+
|
|
82
|
+
wait_for_sshd(state[:hostname]) ; print "(ssh ready)\n"
|
|
83
|
+
|
|
84
|
+
debug("digitalocean:create #{state[:hostname]}")
|
|
85
|
+
rescue RestClient::Exception => e
|
|
86
|
+
raise ActionFailed, e.message
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def destroy(state)
|
|
90
|
+
return if state[:server_id].nil?
|
|
91
|
+
|
|
92
|
+
if get_droplet(state[:server_id])
|
|
93
|
+
destroy_droplet state[:server_id]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
info("Digital Ocean instance <#{state[:server_id]}> destroyed.")
|
|
97
|
+
|
|
98
|
+
state.delete(:server_id)
|
|
99
|
+
state.delete(:hostname)
|
|
100
|
+
rescue RestClient::Exception => e
|
|
101
|
+
raise ActionFailed, e.message
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def default_image
|
|
105
|
+
IMAGES.fetch(instance.platform.name) { 'ubuntu-14-04-x64' }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def default_name
|
|
109
|
+
# Generate what should be a unique server name
|
|
110
|
+
rand_str = Array.new(8) { rand(36).to_s(36) }.join
|
|
111
|
+
"#{instance.name}-"\
|
|
112
|
+
"#{Etc.getlogin.gsub('_', '-')}-"\
|
|
113
|
+
"#{rand_str}-"\
|
|
114
|
+
"#{Socket.gethostname}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def get_droplet(id)
|
|
120
|
+
api_request(:get, "droplets/#{id}")['droplet']
|
|
121
|
+
rescue RestClient::Exception => e
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def create_droplet
|
|
126
|
+
debug_droplet_config
|
|
127
|
+
|
|
128
|
+
droplet = api_request :post, 'droplets', {
|
|
129
|
+
name: config[:server_name],
|
|
130
|
+
region: config[:region],
|
|
131
|
+
size: config[:size],
|
|
132
|
+
image: config[:image],
|
|
133
|
+
ssh_keys: config[:ssh_keys].split(','),
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
droplet['droplet']
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def destroy_droplet(id)
|
|
140
|
+
api_request :delete, "droplets/#{id}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def debug_droplet_config
|
|
144
|
+
debug("digitalocean_api_token #{config[:digitalocean_api_token]}")
|
|
145
|
+
debug("digitalocean:name #{config[:server_name]}")
|
|
146
|
+
debug("digitalocean:image_id #{config[:image_id]}")
|
|
147
|
+
debug("digitalocean:flavor_id #{config[:flavor_id]}")
|
|
148
|
+
debug("digitalocean:region_id #{config[:region_id]}")
|
|
149
|
+
debug("digitalocean:ssh_key_ids #{config[:ssh_key_ids]}")
|
|
150
|
+
debug("digitalocean:private_networking #{config[:private_networking]}")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def api_request(method, url, content=nil)
|
|
154
|
+
url = "https://api.digitalocean.com/v2/#{url}" unless url =~ /^http/
|
|
155
|
+
headers = {'Authorization' => "Bearer #{config[:digitalocean_api_token]}"}
|
|
156
|
+
if %w(get head delete).include? method.to_s
|
|
157
|
+
res = RestClient.send(method.to_sym, url, headers)
|
|
158
|
+
json = JSON.parse(res) unless res.empty?
|
|
159
|
+
|
|
160
|
+
if json
|
|
161
|
+
if json['links'] && json['links']['pages'] && json['links']['pages']['next']
|
|
162
|
+
json.deep_merge!(api_request(method, json['links']['pages']['next']))
|
|
163
|
+
else
|
|
164
|
+
json
|
|
165
|
+
end
|
|
166
|
+
else
|
|
167
|
+
""
|
|
168
|
+
end
|
|
169
|
+
elsif %w(post put).include? method.to_s
|
|
170
|
+
begin
|
|
171
|
+
JSON.parse(RestClient.send(method.to_sym, url, content, headers.merge(:content_type => 'application/json')))
|
|
172
|
+
rescue RestClient::Exception => rce
|
|
173
|
+
raise rce
|
|
174
|
+
end
|
|
175
|
+
else
|
|
176
|
+
raise "What kind of HTTP method actually is #{method}"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# vim: ai et ts=2 sts=2 sw=2 ft=ruby
|
metadata
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: kitchen-digital_ocean
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Will Farrington
|
|
8
|
+
- Greg Fitzgerald
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2014-07-26 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: test-kitchen
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - "~>"
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '1.0'
|
|
21
|
+
type: :runtime
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - "~>"
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '1.0'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: rest_client
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
type: :runtime
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
name: rubocop
|
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
type: :development
|
|
50
|
+
prerelease: false
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
- !ruby/object:Gem::Dependency
|
|
57
|
+
name: rake
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
- !ruby/object:Gem::Dependency
|
|
71
|
+
name: cane
|
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
- !ruby/object:Gem::Dependency
|
|
85
|
+
name: countloc
|
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
type: :development
|
|
92
|
+
prerelease: false
|
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
- !ruby/object:Gem::Dependency
|
|
99
|
+
name: rspec
|
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0'
|
|
105
|
+
type: :development
|
|
106
|
+
prerelease: false
|
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '0'
|
|
112
|
+
description: A Test Kitchen Driver for Digital Ocean using apiv2
|
|
113
|
+
email:
|
|
114
|
+
- wfarr@digitalocean.com
|
|
115
|
+
executables: []
|
|
116
|
+
extensions: []
|
|
117
|
+
extra_rdoc_files: []
|
|
118
|
+
files:
|
|
119
|
+
- ".gitignore"
|
|
120
|
+
- Gemfile
|
|
121
|
+
- LICENSE.txt
|
|
122
|
+
- README.md
|
|
123
|
+
- kitchen-digital_ocean.gemspec
|
|
124
|
+
- lib/kitchen/driver/digital_ocean.rb
|
|
125
|
+
homepage: https://github.com/wfarr/kitchen-digital_ocean
|
|
126
|
+
licenses:
|
|
127
|
+
- Apache 2.0
|
|
128
|
+
metadata: {}
|
|
129
|
+
post_install_message:
|
|
130
|
+
rdoc_options: []
|
|
131
|
+
require_paths:
|
|
132
|
+
- lib
|
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '0'
|
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
|
+
requirements:
|
|
140
|
+
- - ">="
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: '0'
|
|
143
|
+
requirements: []
|
|
144
|
+
rubyforge_project:
|
|
145
|
+
rubygems_version: 2.2.1
|
|
146
|
+
signing_key:
|
|
147
|
+
specification_version: 4
|
|
148
|
+
summary: A Test Kitchen Driver for Digital Ocean using apiv2
|
|
149
|
+
test_files: []
|
|
150
|
+
has_rdoc:
|