inception-server 0.2.1
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.
- 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
|