inception-server 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.chef/knife.rb +4 -0
- data/.gitignore +21 -0
- data/.kitchen.yml +47 -0
- data/.rspec +3 -0
- data/.travis.yml +18 -0
- data/Berksfile +8 -0
- data/Berksfile.lock +9 -0
- data/ChangeLog.md +20 -0
- data/Gemfile +27 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +126 -0
- data/Rakefile +66 -0
- data/TODO.md +25 -0
- data/bin/inception +8 -0
- data/bin/inception-server +8 -0
- data/config/ssh/kitchen-aws +23 -0
- data/cookbooks/bosh_inception/README.md +15 -0
- data/cookbooks/bosh_inception/attributes/default.rb +25 -0
- data/cookbooks/bosh_inception/files/default/Gemfile.cf +5 -0
- data/cookbooks/bosh_inception/files/default/Gemfile.micro +5 -0
- data/cookbooks/bosh_inception/metadata.rb +32 -0
- data/cookbooks/bosh_inception/recipes/default.rb +16 -0
- data/cookbooks/bosh_inception/recipes/install_bosh.rb +37 -0
- data/cookbooks/bosh_inception/recipes/install_ruby.rb +10 -0
- data/cookbooks/bosh_inception/recipes/mount_store_volume.rb +24 -0
- data/cookbooks/bosh_inception/recipes/packages.rb +23 -0
- data/cookbooks/bosh_inception/recipes/setup_dotfog.rb +29 -0
- data/cookbooks/bosh_inception/recipes/setup_git.rb +34 -0
- data/cookbooks/bosh_inception/recipes/useful_dirs.rb +13 -0
- data/inception-server.gemspec +43 -0
- data/lib/inception/cli.rb +141 -0
- data/lib/inception/cli_helpers/display.rb +26 -0
- data/lib/inception/cli_helpers/interactions.rb +15 -0
- data/lib/inception/cli_helpers/prepare_deploy_settings.rb +89 -0
- data/lib/inception/cli_helpers/provider.rb +14 -0
- data/lib/inception/cli_helpers/settings.rb +53 -0
- data/lib/inception/inception_server.rb +304 -0
- data/lib/inception/inception_server_cookbook.rb +90 -0
- data/lib/inception/next_deploy_actions.rb +20 -0
- data/lib/inception/providers/README.md +5 -0
- data/lib/inception/providers/clients/aws_provider_client.rb +144 -0
- data/lib/inception/providers/clients/fog_provider_client.rb +185 -0
- data/lib/inception/providers/clients/openstack_provider_client.rb +84 -0
- data/lib/inception/providers/constants/aws_constants.rb +25 -0
- data/lib/inception/providers/constants/openstack_constants.rb +12 -0
- data/lib/inception/providers.rb +28 -0
- data/lib/inception/version.rb +3 -0
- data/lib/inception.rb +9 -0
- data/nodes/.gitkeep +0 -0
- data/spec/assets/.gitkeep +0 -0
- data/spec/assets/gitconfig +5 -0
- data/spec/assets/settings/aws-before-server.yml +14 -0
- data/spec/assets/settings/aws-created-server.yml +31 -0
- data/spec/integration/.gitkeep +0 -0
- data/spec/integration/aws/aws_basic_spec.rb +38 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/support/aws/aws_helpers.rb +73 -0
- data/spec/support/settings_helper.rb +20 -0
- data/spec/support/stdout_capture.rb +17 -0
- data/spec/unit/.gitkeep +0 -0
- data/spec/unit/cli_delete_spec.rb +39 -0
- data/spec/unit/cli_deploy_aws_spec.rb +83 -0
- data/spec/unit/cli_ssh_spec.rb +80 -0
- data/spec/unit/inception_server_cookbook_spec.rb +62 -0
- data/spec/unit/inception_server_spec.rb +58 -0
- data/spec/unit/providers/aws_spec.rb +198 -0
- data/test/integration/default/bats/discover_user.bash +2 -0
- data/test/integration/default/bats/dotfog.bats +11 -0
- data/test/integration/default/bats/install_ruby.bats +8 -0
- data/test/integration/default/bats/useful_dirs.bats +8 -0
- data/test/integration/default/bats/user.bats +9 -0
- data/test/integration/default/bats/verify_bosh.bats +18 -0
- data/test/integration/default/bats/verify_git.bats +18 -0
- metadata +361 -0
@@ -0,0 +1,304 @@
|
|
1
|
+
require "fog"
|
2
|
+
|
3
|
+
module Inception
|
4
|
+
class InceptionServer
|
5
|
+
|
6
|
+
DEFAULT_SERVER_NAME = "inception"
|
7
|
+
DEFAULT_FLAVOR = "m1.small"
|
8
|
+
DEFAULT_DISK_SIZE = 16
|
9
|
+
DEFAULT_SECURITY_GROUPS = ["ssh"]
|
10
|
+
|
11
|
+
attr_reader :attributes
|
12
|
+
|
13
|
+
# @provider_client [Inception::Providers::FogProvider] - interact with IaaS
|
14
|
+
# @attributes [ReadWriteSettings]
|
15
|
+
#
|
16
|
+
# Required @attributes:
|
17
|
+
# {
|
18
|
+
# "name" => "inception",
|
19
|
+
# "ip_address" => "54.214.15.178",
|
20
|
+
# "key_pair" => {
|
21
|
+
# "name" => "inception",
|
22
|
+
# "private_key" => "private_key",
|
23
|
+
# "public_key" => "public_key"
|
24
|
+
# }
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# Including optional @attributes and default values:
|
28
|
+
# {
|
29
|
+
# "name" => "inception",
|
30
|
+
# "ip_address" => "54.214.15.178",
|
31
|
+
# "security_groups" => ["ssh"],
|
32
|
+
# "flavor" => "m1.small",
|
33
|
+
# "key_pair" => {
|
34
|
+
# "name" => "inception",
|
35
|
+
# "private_key" => "private_key",
|
36
|
+
# "public_key" => "public_key"
|
37
|
+
# }
|
38
|
+
# }
|
39
|
+
def initialize(provider_client, attributes, ssh_dir)
|
40
|
+
@provider_client = provider_client
|
41
|
+
@ssh_dir = ssh_dir
|
42
|
+
@attributes = attributes.is_a?(Hash) ? ReadWriteSettings.new(attributes) : attributes
|
43
|
+
raise "@attributes must be ReadWriteSettings (or Hash)" unless @attributes.is_a?(ReadWriteSettings)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create the underlying server, with key pair & security groups, unless it is already created
|
47
|
+
#
|
48
|
+
# The @attributes hash is updated with a `provisioned` key during/after creation.
|
49
|
+
# When saved as YAML it might look like:
|
50
|
+
# inception:
|
51
|
+
# provisioned:
|
52
|
+
# image_id: ami-123456
|
53
|
+
# server_id: i-e7f005d2
|
54
|
+
# security_groups:
|
55
|
+
# - ssh
|
56
|
+
# - mosh
|
57
|
+
# username: ubuntu
|
58
|
+
# disk_device: /dev/sdi
|
59
|
+
# host: ec2-54-214-15-178.us-west-2.compute.amazonaws.com
|
60
|
+
# validated: true
|
61
|
+
# converged: true
|
62
|
+
def create
|
63
|
+
validate_attributes_for_bootstrap
|
64
|
+
ensure_required_security_groups
|
65
|
+
create_missing_default_security_groups
|
66
|
+
bootstrap_vm
|
67
|
+
attach_persistent_disk
|
68
|
+
end
|
69
|
+
|
70
|
+
# Delete the server, volume and release the IP address
|
71
|
+
def delete_all
|
72
|
+
delete_server
|
73
|
+
delete_volume
|
74
|
+
delete_key_pair
|
75
|
+
release_ip_address
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete_server
|
79
|
+
@fog_server = nil # force reload of fog_server model
|
80
|
+
if fog_server
|
81
|
+
print "Deleting server... "
|
82
|
+
fog_server.destroy
|
83
|
+
wait_for_termination(fog_server) unless Fog.mocking?
|
84
|
+
puts "done."
|
85
|
+
else
|
86
|
+
puts "Server already destroyed"
|
87
|
+
end
|
88
|
+
provisioned.delete("host")
|
89
|
+
provisioned.delete("server_id")
|
90
|
+
provisioned.delete("username")
|
91
|
+
end
|
92
|
+
|
93
|
+
def delete_volume
|
94
|
+
volume_id = provisioned.exists?("disk_device.volume_id")
|
95
|
+
if volume_id && (volume = fog_compute.volumes.get(volume_id)) && volume.ready?
|
96
|
+
print "Deleting volume... "
|
97
|
+
volume.destroy
|
98
|
+
wait_for_termination(volume, "deleting")
|
99
|
+
puts ""
|
100
|
+
else
|
101
|
+
puts "Volume already destroyed"
|
102
|
+
end
|
103
|
+
provisioned.delete("disk_device")
|
104
|
+
end
|
105
|
+
|
106
|
+
def delete_key_pair
|
107
|
+
key_pair_name = attributes.exists?("key_pair.name")
|
108
|
+
if key_pair_name && key_pair = fog_compute.key_pairs.get(key_pair_name)
|
109
|
+
puts "Deleting key pair '#{key_pair_name}'"
|
110
|
+
key_pair.destroy
|
111
|
+
else
|
112
|
+
puts "Keypair already destroyed"
|
113
|
+
end
|
114
|
+
attributes.delete("key_pair")
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def release_ip_address
|
119
|
+
public_ip = provisioned.exists?("ip_address")
|
120
|
+
if public_ip && ip_address = fog_compute.addresses.get(public_ip)
|
121
|
+
puts "Releasing IP address #{public_ip}"
|
122
|
+
ip_address.destroy
|
123
|
+
else
|
124
|
+
puts "IP address already released"
|
125
|
+
end
|
126
|
+
provisioned.delete("ip_address")
|
127
|
+
end
|
128
|
+
|
129
|
+
def security_groups
|
130
|
+
@attributes.security_groups
|
131
|
+
end
|
132
|
+
|
133
|
+
def server_name
|
134
|
+
@attributes["name"] ||= DEFAULT_SERVER_NAME
|
135
|
+
@attributes.name
|
136
|
+
end
|
137
|
+
|
138
|
+
def key_name
|
139
|
+
@attributes.key_pair.name
|
140
|
+
end
|
141
|
+
|
142
|
+
def private_key_path
|
143
|
+
@private_key_path ||= File.join(@ssh_dir, key_name)
|
144
|
+
end
|
145
|
+
|
146
|
+
def public_key
|
147
|
+
@attributes.exists?("key_pair.public_key")
|
148
|
+
end
|
149
|
+
|
150
|
+
# Flavor/instance type of the server to be provisioned
|
151
|
+
# TODO: DEFAULT_FLAVOR should become IaaS/provider specific
|
152
|
+
def flavor
|
153
|
+
@attributes["flavor"] ||= DEFAULT_FLAVOR
|
154
|
+
end
|
155
|
+
|
156
|
+
# Size of attached persistent disk for the inception server
|
157
|
+
def disk_size
|
158
|
+
@attributes["disk_size"] ||= DEFAULT_DISK_SIZE
|
159
|
+
end
|
160
|
+
|
161
|
+
def ip_address
|
162
|
+
provisioned.ip_address
|
163
|
+
end
|
164
|
+
|
165
|
+
def image_id
|
166
|
+
@attributes["image_id"] ||= @provider_client.image_id
|
167
|
+
end
|
168
|
+
|
169
|
+
# The progresive/final attributes of the provisioned Inception server &
|
170
|
+
# persistent disk.
|
171
|
+
def provisioned
|
172
|
+
@attributes["provisioned"] = {} unless @attributes["provisioned"]
|
173
|
+
@attributes.provisioned
|
174
|
+
end
|
175
|
+
|
176
|
+
# Because @attributes["provisioned"] is not the same as @attributes.provisioned
|
177
|
+
# we need a helper to export the complete nested attributes.
|
178
|
+
def export_attributes
|
179
|
+
attrs = attributes.to_nested_hash
|
180
|
+
attrs["provisioned"] = provisioned.to_nested_hash
|
181
|
+
attrs
|
182
|
+
end
|
183
|
+
|
184
|
+
def disk_devices
|
185
|
+
provisioned["disk_device"] ||= default_disk_device
|
186
|
+
end
|
187
|
+
|
188
|
+
def external_disk_device
|
189
|
+
disk_devices["external"]
|
190
|
+
end
|
191
|
+
|
192
|
+
def default_disk_device
|
193
|
+
case @provider_client
|
194
|
+
when Inception::Providers::Clients::AwsProviderClient
|
195
|
+
{ "external" => "/dev/sdf", "internal" => "/dev/xvdf" }
|
196
|
+
when Inception::Providers::Clients::OpenStackProviderClient
|
197
|
+
{ "external" => "/dev/vdc", "internal" => "/dev/vdc" }
|
198
|
+
else
|
199
|
+
raise "Please implement InceptionServer#default_disk_device for #{@provider_client.class}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def user_host
|
204
|
+
"#{provisioned.username}@#{provisioned.host}"
|
205
|
+
end
|
206
|
+
|
207
|
+
def fog_server
|
208
|
+
@fog_server ||= begin
|
209
|
+
if server_id = provisioned["server_id"]
|
210
|
+
fog_compute.servers.get(server_id)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def fog_compute
|
216
|
+
@provider_client.fog_compute
|
217
|
+
end
|
218
|
+
|
219
|
+
protected
|
220
|
+
# set_resource_name(fog_server, "inception")
|
221
|
+
# set_resource_name(volume, "inception-root")
|
222
|
+
# set_resource_name(volume, "inception-store")
|
223
|
+
def set_resource_name(resource, name)
|
224
|
+
@provider_client.set_resource_name(resource, name)
|
225
|
+
end
|
226
|
+
|
227
|
+
def fog_attributes
|
228
|
+
@provider_client.fog_attributes(self)
|
229
|
+
end
|
230
|
+
|
231
|
+
def validate_attributes_for_bootstrap
|
232
|
+
missing_attributes = []
|
233
|
+
missing_attributes << "provisioned.ip_address" unless @attributes.exists?("provisioned.ip_address")
|
234
|
+
missing_attributes << "key_pair.private_key" unless @attributes.exists?("key_pair.private_key")
|
235
|
+
if missing_attributes.size > 0
|
236
|
+
raise "Missing InceptionServer attributes: #{missing_attributes.join(', ')}"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# ssh group must be first (bootstrap method looks for port 22 in first group)
|
241
|
+
def ensure_required_security_groups
|
242
|
+
if @attributes["security_groups"] && @attributes["security_groups"].is_a?(Array)
|
243
|
+
unless @attributes["security_groups"].include?("ssh")
|
244
|
+
@attributes["security_groups"] = ["ssh", *@attributes["security_groups"]]
|
245
|
+
end
|
246
|
+
else
|
247
|
+
@attributes["security_groups"] = ["ssh"]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def create_missing_default_security_groups
|
252
|
+
# provider method only creates group if missing
|
253
|
+
@provider_client.create_security_group("ssh", "ssh", {ssh: 22})
|
254
|
+
end
|
255
|
+
|
256
|
+
def bootstrap_vm
|
257
|
+
unless fog_server
|
258
|
+
print "Booting #{flavor} inception server... "
|
259
|
+
@fog_server = @provider_client.bootstrap(fog_attributes)
|
260
|
+
provisioned["server_id"] = fog_server.id
|
261
|
+
provisioned["host"] = fog_server.dns_name || fog_server.public_ip_address
|
262
|
+
provisioned["username"] = fog_attributes[:username]
|
263
|
+
puts provisioned.server_id
|
264
|
+
end
|
265
|
+
set_resource_name(fog_server, server_name)
|
266
|
+
end
|
267
|
+
|
268
|
+
def attach_persistent_disk
|
269
|
+
unless Fog.mocking?
|
270
|
+
print "Confirming ssh access to server... "
|
271
|
+
Fog.wait_for(60) { fog_server.sshable?(ssh_options) }
|
272
|
+
puts "done"
|
273
|
+
end
|
274
|
+
|
275
|
+
unless volume = @provider_client.find_server_device(fog_server, external_disk_device)
|
276
|
+
print "Provisioning #{disk_size}Gb persistent disk for inception server... "
|
277
|
+
volume = @provider_client.create_and_attach_volume("Inception Disk", disk_size, fog_server, external_disk_device)
|
278
|
+
disk_devices["volume_id"] = volume.id
|
279
|
+
puts disk_devices.volume_id
|
280
|
+
end
|
281
|
+
set_resource_name(volume, server_name)
|
282
|
+
end
|
283
|
+
|
284
|
+
def ssh_options
|
285
|
+
{
|
286
|
+
keys: [private_key_path]
|
287
|
+
}
|
288
|
+
end
|
289
|
+
|
290
|
+
# Poll a fog model until it terminates; print . each second
|
291
|
+
def wait_for_termination(fog_model, state_to_wait_for="terminated")
|
292
|
+
fog_model.wait_for do
|
293
|
+
print "."
|
294
|
+
state == state_to_wait_for
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
protected
|
299
|
+
# TODO emit events rather than writing directly to STDOUT
|
300
|
+
def say(*args)
|
301
|
+
puts(*args)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Inception
|
2
|
+
# Perform converge chef cookbooks upon inception server
|
3
|
+
class InceptionServerCookbook
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
attr_reader :server, :settings, :project_dir
|
7
|
+
|
8
|
+
class InvalidTarget < StandardError; end
|
9
|
+
|
10
|
+
def initialize(inception_server, settings, project_dir)
|
11
|
+
@server = inception_server
|
12
|
+
@settings = settings
|
13
|
+
@project_dir = project_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def prepare
|
17
|
+
FileUtils.chdir(project_dir) do
|
18
|
+
prepare_project_dir
|
19
|
+
knife_solo :prepare unless ignore_chef_preparations?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# To be invoked within the settings_dir
|
24
|
+
def converge
|
25
|
+
FileUtils.chdir(project_dir) do
|
26
|
+
knife_solo :cook
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def ignore_chef_preparations?
|
31
|
+
@settings.exists?("cookbook.prepared")
|
32
|
+
end
|
33
|
+
|
34
|
+
def user_host; server.user_host; end
|
35
|
+
def key_path; server.private_key_path; end
|
36
|
+
|
37
|
+
def knife_solo(command)
|
38
|
+
attributes = cookbook_attributes_for_inception.to_json
|
39
|
+
sh %Q{knife solo #{command} #{user_host} -i #{key_path} -j '#{attributes}' -r 'bosh_inception'}
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
def prepare_project_dir
|
44
|
+
prepare_cookbook
|
45
|
+
prepare_knife_config
|
46
|
+
prepare_berksfile
|
47
|
+
end
|
48
|
+
|
49
|
+
def prepare_cookbook
|
50
|
+
mkdir_p("cookbooks")
|
51
|
+
rm_rf("cookbooks/bosh_inception")
|
52
|
+
cp_r(inception_cookbook_path, "cookbooks/")
|
53
|
+
end
|
54
|
+
|
55
|
+
def prepare_knife_config
|
56
|
+
mkdir_p("nodes") # needed for knife solo
|
57
|
+
end
|
58
|
+
|
59
|
+
def prepare_berksfile
|
60
|
+
unless File.exists?("Berksfile")
|
61
|
+
cp_r(File.join(gem_root_path, "Berksfile"), "Berksfile")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def cookbook_attributes_for_inception
|
66
|
+
{
|
67
|
+
"disk" => {
|
68
|
+
"mounted" => true,
|
69
|
+
"device" => settings.inception.provisioned.disk_device.internal
|
70
|
+
},
|
71
|
+
"git" => {
|
72
|
+
"name" => settings.git.name,
|
73
|
+
"email" => settings.git.email
|
74
|
+
},
|
75
|
+
"user" => {
|
76
|
+
"username" => settings.inception.provisioned.username
|
77
|
+
},
|
78
|
+
"fog" => settings.provider.credentials
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def gem_root_path
|
83
|
+
File.expand_path("../../..", __FILE__)
|
84
|
+
end
|
85
|
+
|
86
|
+
def inception_cookbook_path
|
87
|
+
File.join(gem_root_path, "cookbooks/bosh_inception")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Inception
|
2
|
+
|
3
|
+
class NextDeployActions
|
4
|
+
def initialize(attributes, cli_options)
|
5
|
+
@attributes = attributes.is_a?(Hash) ? ReadWriteSettings.new(attributes) : attributes
|
6
|
+
raise "@attributes must be ReadWriteSettings (or Hash)" unless @attributes.is_a?(ReadWriteSettings)
|
7
|
+
raise "@cli_options must be Hash" unless cli_options.is_a?(Hash)
|
8
|
+
apply_cli_options(cli_options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def skip_chef_converge?
|
12
|
+
@attributes["no_converge"] || @attributes["no-converge"] || @attributes["skip_chef_converge"]
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
def apply_cli_options(cli_options)
|
17
|
+
@attributes.merge(cli_options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# Copyright (c) 2012-2013 Stark & Wayne, LLC
|
2
|
+
|
3
|
+
module Inception; module Providers; module Clients; end; end; end
|
4
|
+
|
5
|
+
require "inception/providers/clients/fog_provider_client"
|
6
|
+
require "inception/providers/constants/aws_constants"
|
7
|
+
|
8
|
+
class Inception::Providers::Clients::AwsProviderClient < Inception::Providers::Clients::FogProviderClient
|
9
|
+
include Inception::Providers::Constants::AwsConstants
|
10
|
+
|
11
|
+
# @return [Integer] megabytes of RAM for requested flavor of server
|
12
|
+
def ram_for_server_flavor(server_flavor_id)
|
13
|
+
if flavor = fog_compute_flavor(server_flavor_id)
|
14
|
+
flavor[:ram]
|
15
|
+
else
|
16
|
+
raise "Unknown AWS flavor '#{server_flavor_id}'"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Hash] e.g. { :bits => 0, :cores => 2, :disk => 0,
|
21
|
+
# :id => 't1.micro', :name => 'Micro Instance', :ram => 613}
|
22
|
+
# or nil if +server_flavor_id+ is not a supported flavor ID
|
23
|
+
def fog_compute_flavor(server_flavor_id)
|
24
|
+
aws_compute_flavors.find { |fl| fl[:id] == server_flavor_id }
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Array] of [Hash] for each supported compute flavor
|
28
|
+
# Example [Hash] { :bits => 0, :cores => 2, :disk => 0,
|
29
|
+
# :id => 't1.micro', :name => 'Micro Instance', :ram => 613}
|
30
|
+
def aws_compute_flavors
|
31
|
+
Fog::Compute::AWS::FLAVORS
|
32
|
+
end
|
33
|
+
|
34
|
+
def aws_compute_flavor_ids
|
35
|
+
aws_compute_flavors.map { |fl| fl[:id] }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Provision an EC2 or VPC elastic IP addess.
|
39
|
+
# * VPC - provision_public_ip_address(vpc: true)
|
40
|
+
# * EC2 - provision_public_ip_address
|
41
|
+
# @return [String] provisions a new public IP address in target region
|
42
|
+
# TODO nil if none available
|
43
|
+
def provision_public_ip_address(options={})
|
44
|
+
if options.delete(:vpc)
|
45
|
+
options[:domain] = "vpc"
|
46
|
+
else
|
47
|
+
options[:domain] = options.delete(:domain) || "standard"
|
48
|
+
end
|
49
|
+
address = fog_compute.addresses.create(options)
|
50
|
+
address.public_ip
|
51
|
+
# TODO catch error and return nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def associate_ip_address_with_server(ip_address, server)
|
55
|
+
address = fog_compute.addresses.get(ip_address)
|
56
|
+
address.server = server
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_vpc(name, cidr_block)
|
60
|
+
vpc = fog_compute.vpcs.create(name: name, cidr_block: cidr_block)
|
61
|
+
vpc.id
|
62
|
+
end
|
63
|
+
|
64
|
+
# Creates a VPC subnet
|
65
|
+
# @return [String] the subnet_id
|
66
|
+
def create_subnet(vpc_id, cidr_block)
|
67
|
+
subnet = fog_compute.subnets.create(vpc_id: vpc_id, cidr_block: cidr_block)
|
68
|
+
subnet.subnet_id
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_internet_gateway(vpc_id)
|
72
|
+
gateway = fog_compute.internet_gateways.create(vpc_id: vpc_id)
|
73
|
+
gateway.id
|
74
|
+
end
|
75
|
+
|
76
|
+
def find_server_device(server, device)
|
77
|
+
server.volumes.all.find {|v| v.device == device}
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_and_attach_volume(name, disk_size, server, device)
|
81
|
+
volume = fog_compute.volumes.create(
|
82
|
+
size: disk_size,
|
83
|
+
name: name,
|
84
|
+
description: '',
|
85
|
+
device: device,
|
86
|
+
availability_zone: server.availability_zone)
|
87
|
+
# TODO: the following works in fog 1.9.0+ (but which has a bug in bootstrap)
|
88
|
+
# https://github.com/fog/fog/issues/1516
|
89
|
+
#
|
90
|
+
# volume.wait_for { volume.status == 'available' }
|
91
|
+
# volume.attach(server.id, "/dev/vdc")
|
92
|
+
# volume.wait_for { volume.status == 'in-use' }
|
93
|
+
#
|
94
|
+
# Instead, using:
|
95
|
+
volume.server = server
|
96
|
+
end
|
97
|
+
|
98
|
+
# Ubuntu 13.04
|
99
|
+
def image_id
|
100
|
+
region = fog_compute.region
|
101
|
+
# http://cloud-images.ubuntu.com/locator/ec2/
|
102
|
+
image_id = case region.to_s
|
103
|
+
when "ap-northeast-1"
|
104
|
+
"ami-6b26ab6a"
|
105
|
+
when "ap-southeast-1"
|
106
|
+
"ami-2b511e79"
|
107
|
+
when "eu-west-1"
|
108
|
+
"ami-3d160149"
|
109
|
+
when "sa-east-1"
|
110
|
+
"ami-28e43e35"
|
111
|
+
when "us-east-1"
|
112
|
+
"ami-c30360aa"
|
113
|
+
when "us-west-1"
|
114
|
+
"ami-d383af96"
|
115
|
+
when "ap-southeast-2"
|
116
|
+
"ami-84a333be"
|
117
|
+
when "us-west-2"
|
118
|
+
"ami-bf1d8a8f"
|
119
|
+
end
|
120
|
+
image_id || raise("Please add Ubuntu 13.04 64bit (EBS) AMI image id to aws.rb#raring_image_id method for region '#{region}'")
|
121
|
+
end
|
122
|
+
|
123
|
+
# Construct a Fog::Compute object
|
124
|
+
# Uses +attributes+ which normally originates from +settings.provider+
|
125
|
+
def setup_fog_connection
|
126
|
+
configuration = Fog.symbolize_credentials(attributes.credentials)
|
127
|
+
configuration[:provider] = "AWS"
|
128
|
+
configuration[:region] = attributes.region
|
129
|
+
@fog_compute = Fog::Compute.new(configuration)
|
130
|
+
end
|
131
|
+
|
132
|
+
def fog_attributes(inception_server)
|
133
|
+
{
|
134
|
+
image_id: inception_server.image_id,
|
135
|
+
groups: inception_server.security_groups,
|
136
|
+
key_name: inception_server.key_name,
|
137
|
+
private_key_path: inception_server.private_key_path,
|
138
|
+
flavor_id: inception_server.flavor,
|
139
|
+
public_ip_address: inception_server.ip_address,
|
140
|
+
bits: 64,
|
141
|
+
username: "ubuntu",
|
142
|
+
}
|
143
|
+
end
|
144
|
+
end
|