ec2launcher 1.0.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/ec2launcher +34 -0
- data/ec2launcher.gemspec +18 -0
- data/lib/ec2launcher/application.rb +262 -0
- data/lib/ec2launcher/block_device.rb +91 -0
- data/lib/ec2launcher/block_device_builder.rb +270 -0
- data/lib/ec2launcher/config.rb +76 -0
- data/lib/ec2launcher/defaults.rb +9 -0
- data/lib/ec2launcher/email_notification.rb +62 -0
- data/lib/ec2launcher/environment.rb +179 -0
- data/lib/ec2launcher/init_options.rb +166 -0
- data/lib/ec2launcher/version.rb +6 -0
- data/lib/ec2launcher.rb +734 -0
- data/startup-scripts/setup.rb +154 -0
- data/startup-scripts/setup_instance.rb +340 -0
- metadata +81 -0
@@ -0,0 +1,270 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Sean Laurent
|
3
|
+
#
|
4
|
+
require 'ec2launcher/defaults'
|
5
|
+
|
6
|
+
module EC2Launcher
|
7
|
+
# Helper class to build EC2 block device definitions.
|
8
|
+
#
|
9
|
+
class BlockDeviceBuilder
|
10
|
+
attr_reader :block_device_setup
|
11
|
+
attr_reader :block_device_mappings
|
12
|
+
attr_reader :block_device_tags
|
13
|
+
|
14
|
+
# @param [AWS::EC2] ec2 interface to ec2
|
15
|
+
# @param [Integer, nil] volume_size size of new EBS volumes. If set to nil, uses EC2Launcher::Defaults::DEFAULT_VOLUME_SIZE.
|
16
|
+
#
|
17
|
+
def initialize(ec2, volume_size = nil)
|
18
|
+
@ec2 = ec2
|
19
|
+
@block_size = volume_size
|
20
|
+
@volume_size ||= EC2Launcher::DEFAULT_VOLUME_SIZE
|
21
|
+
|
22
|
+
@block_device_setup = {}
|
23
|
+
@block_device_mappings = {}
|
24
|
+
@block_device_tags = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Iterates over a number of block_devices, executing the specified Ruby block.
|
28
|
+
#
|
29
|
+
# @param [Integer] count number of block devices
|
30
|
+
# @param [String, "sdf"] device the starting device name. Defaults to "sdf".
|
31
|
+
# Incremented for each iteration.
|
32
|
+
# @param [Block] block block to execute. Passes in the current device name and zero-based index.
|
33
|
+
#
|
34
|
+
def build_block_devices(count, device = "sdf", &block)
|
35
|
+
device_name = device
|
36
|
+
0.upto(count - 1).each do |index|
|
37
|
+
yield device_name, index
|
38
|
+
device_name.next!
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates the mappings for the appropriate EBS volumes.
|
43
|
+
#
|
44
|
+
# @param [String] hostname FQDN for new host
|
45
|
+
# @param [String] short_hostname short name for host host, without domain name.
|
46
|
+
# @param [String] environment_name name of the environment
|
47
|
+
# @param [Array<EC2Launcher::BlockDevice>] block_devices list of block devices to create.
|
48
|
+
#
|
49
|
+
def build_ebs_volumes(hostname, short_hostname, environment_name, block_devices)
|
50
|
+
base_device_name = "sdf"
|
51
|
+
block_devices.each do |block_device|
|
52
|
+
build_block_devices(block_device.count, base_device_name) do |device_name, index|
|
53
|
+
volume_size = block_device.size
|
54
|
+
volume_size ||= @volume_size
|
55
|
+
|
56
|
+
block_device_mappings["/dev/#{device_name}"] = {
|
57
|
+
:volume_size => volume_size,
|
58
|
+
:delete_on_termination => true
|
59
|
+
}
|
60
|
+
|
61
|
+
block_device_tags["/dev/#{device_name}"] = {
|
62
|
+
"purpose" => block_device.name,
|
63
|
+
"host" => hostname,
|
64
|
+
"environment" => environment_name
|
65
|
+
}
|
66
|
+
|
67
|
+
if block_device.raid_level.nil?
|
68
|
+
block_device_tags["/dev/#{device_name}"]["Name"] = "#{short_hostname} #{block_device.name}"
|
69
|
+
else
|
70
|
+
block_device_tags["/dev/#{device_name}"]["Name"] = "#{short_hostname} #{block_device.name} raid (#{(index + 1).to_s})"
|
71
|
+
block_device_tags["/dev/#{device_name}"]["raid_number"] = (index + 1).to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates the mappings for the appropriate ephemeral drives.
|
78
|
+
#
|
79
|
+
# @param [String] instance_type type of instance. See EC2Launcher::Defaults::INSTANCE_TYPES.
|
80
|
+
#
|
81
|
+
def build_ephemeral_drives(instance_type)
|
82
|
+
ephemeral_drive_count = case instance_type
|
83
|
+
when "m1.small" then 1
|
84
|
+
when "m1.medium" then 1
|
85
|
+
when "m2.xlarge" then 1
|
86
|
+
when "m2.2xlarge" then 1
|
87
|
+
when "c1.medium" then 1
|
88
|
+
when "m1.large" then 2
|
89
|
+
when "m2.4xlarge" then 2
|
90
|
+
when "cc1.4xlarge" then 2
|
91
|
+
when "cg1.4xlarge" then 2
|
92
|
+
when "m1.xlarge" then 4
|
93
|
+
when "c1.xlarge" then 4
|
94
|
+
when "cc2.8xlarge" then 4
|
95
|
+
else 0
|
96
|
+
end
|
97
|
+
build_block_devices(ephemeral_drive_count, "sdb") do |device_name, index|
|
98
|
+
@block_device_mappings["/dev/#{device_name}"] = "ephemeral#{index}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Finds the EBS snapshots to clone for all appropriate block devices and
|
103
|
+
# updates the block device mapping hash.
|
104
|
+
#
|
105
|
+
# @param [EC2Launcher::Environment] environment current environment
|
106
|
+
# @param [EC2Launcher::Application] application current application
|
107
|
+
# @param [String] clone_host name of host to clone
|
108
|
+
#
|
109
|
+
def clone_volumes(environment, application, clone_host)
|
110
|
+
return if clone_host.nil?
|
111
|
+
|
112
|
+
puts "Retrieving snapshots..."
|
113
|
+
AWS.start_memoizing
|
114
|
+
base_device_name = "sdf"
|
115
|
+
application.block_devices.each do |block_device|
|
116
|
+
if block_device.raid_level.nil?
|
117
|
+
@block_device_mappings["/dev/#{base_device_name}"][:snapshot_id] = get_latest_snapshot(clone_short_hostname, clone_host, block_device.name).id
|
118
|
+
base_device_name.next!
|
119
|
+
else
|
120
|
+
snapshots = get_latest_raid_snapshot_mapping(clone_host, block_device.name, block_device.count)
|
121
|
+
build_block_devices(block_device.count, base_device_name) do |device_name, index|
|
122
|
+
@block_device_mappings["/dev/#{device_name}"][:snapshot_id] = snapshots[(index + 1).to_s].id
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
AWS.stop_memoizing
|
127
|
+
end
|
128
|
+
|
129
|
+
# Generates the mappings for ephemeral and ebs volumes.
|
130
|
+
#
|
131
|
+
# @param [String] hostname FQDN for new host
|
132
|
+
# @param [String] short_hostname short name for host host, without domain name.
|
133
|
+
# @param [String] instance_type type of instance. See EC2Launcher::Defaults::INSTANCE_TYPES.
|
134
|
+
# @param [EC2Launcher::Environment] environment current environment
|
135
|
+
# @param [EC2Launcher::Application] application current application
|
136
|
+
# @param [String, nil] clone_host FQDN of host to clone or nill to skip cloning.
|
137
|
+
#
|
138
|
+
def generate_block_devices(hostname, short_hostname, instance_type, environment, application, clone_host = nil)
|
139
|
+
build_ephemeral_drives(instance_type)
|
140
|
+
build_ebs_volumes(hostname, short_hostname, environment.name, application.block_devices)
|
141
|
+
clone_volumes(environment, application, clone_host)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Retrieves the latest set of completed snapshots for a RAID array of EBS volumes.
|
145
|
+
#
|
146
|
+
# Volumes must have the following tags:
|
147
|
+
# * host
|
148
|
+
# * volumeName
|
149
|
+
# * time
|
150
|
+
#
|
151
|
+
# @param [String] hostname FQDN for new host
|
152
|
+
# @param [String] purpose purpose of RAID array, which is stored in the `purpose` tag for snapshots/volumes
|
153
|
+
# and is part of the snapshot name.
|
154
|
+
# @param [Integer] count number of EBS snapshots to look for
|
155
|
+
#
|
156
|
+
# @return [Hash<Integer, AWS::EC2::Snapshot>] mapping of RAID device numbers (zero based) to AWS Snapshots.
|
157
|
+
#
|
158
|
+
def get_latest_raid_snapshot_mapping(hostname, purpose, count)
|
159
|
+
puts "Retrieving list of snapshots ..."
|
160
|
+
result = @ec2.snapshots.tagged("host").tagged_values(hostname).tagged("volumeName").tagged_values("*raid*").tagged("time")
|
161
|
+
|
162
|
+
puts "Building list of snapshots to clone (#{purpose}) for '#{hostname}'..."
|
163
|
+
snapshot_name_regex = /#{purpose} raid.*/
|
164
|
+
host_snapshots = []
|
165
|
+
result.each do |s|
|
166
|
+
next if snapshot_name_regex.match(s.tags["volumeName"]).nil?
|
167
|
+
host_snapshots << s if s.status == :completed
|
168
|
+
end
|
169
|
+
|
170
|
+
# Bucket the snapshots based on volume number e.g. "raid (1)" vs "raid (2)"
|
171
|
+
snapshot_buckets = { }
|
172
|
+
volume_number_regex = /raid \((\d)\)$/
|
173
|
+
host_snapshots.each do |snapshot|
|
174
|
+
next if snapshot.tags["time"].nil?
|
175
|
+
|
176
|
+
volume_name = snapshot.tags["volumeName"]
|
177
|
+
|
178
|
+
match_info = volume_number_regex.match(volume_name)
|
179
|
+
next if match_info.nil?
|
180
|
+
|
181
|
+
matches = match_info.captures
|
182
|
+
next if matches.length != 1
|
183
|
+
|
184
|
+
raid_number = matches[0]
|
185
|
+
|
186
|
+
snapshot_buckets[raid_number] = [] if snapshot_buckets[raid_number].nil?
|
187
|
+
snapshot_buckets[raid_number] << snapshot
|
188
|
+
end
|
189
|
+
|
190
|
+
# Sort the snapshots in each bucket by time
|
191
|
+
snapshot_buckets.keys.each do |key|
|
192
|
+
snapshot_buckets[key].sort! do |a, b|
|
193
|
+
b.tags["time"] <=> a.tags["time"]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# We need to find the most recent backup time that all snapshots have in common.
|
198
|
+
#
|
199
|
+
# For example, we may have the following snapshots for "raid (1)":
|
200
|
+
# volumeName => db1.dev db raid (1), time => 11-06-15 10:00
|
201
|
+
# volumeName => db1.dev db raid (1), time => 11-06-15 09:00
|
202
|
+
# volumeName => db1.dev db raid (1), time => 11-06-14 09:00
|
203
|
+
# And the following snapshots for "raid (2)":
|
204
|
+
# volumeName => db1.dev db raid (1), time => 11-06-15 09:00
|
205
|
+
# volumeName => db1.dev db raid (1), time => 11-06-14 09:00
|
206
|
+
#
|
207
|
+
# In this example, the latest snapshot from "raid (1)" is dated "11-06-15 10:00", but "raid (2)" does not have
|
208
|
+
# a matching snapshot (because it hasn't completed yet). Instead, we should use the "11-06-15 09:00" snapshots.
|
209
|
+
#
|
210
|
+
# We find the most recent date from each bucket and then take the earliest one.
|
211
|
+
most_recent_dates = []
|
212
|
+
snapshot_buckets.keys().each do |key|
|
213
|
+
snapshot = snapshot_buckets[key][0]
|
214
|
+
most_recent_dates << snapshot.tags["time"].to_s
|
215
|
+
end
|
216
|
+
most_recent_dates.sort!
|
217
|
+
|
218
|
+
puts "Most recent snapshot: #{most_recent_dates[0]}"
|
219
|
+
|
220
|
+
snapshot_mapping = { }
|
221
|
+
AWS.memoize do
|
222
|
+
snapshot_buckets.keys.each do |index|
|
223
|
+
found = false
|
224
|
+
snapshot_buckets[index].each do |snapshot|
|
225
|
+
if snapshot.tags["time"] == most_recent_dates[0]
|
226
|
+
snapshot_mapping[index] = snapshot
|
227
|
+
found = true
|
228
|
+
break
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
abort("***** ERROR: Unable to find snapshot for #{purpose} (#{index.to_s})") unless found
|
233
|
+
end
|
234
|
+
end
|
235
|
+
snapshot_mapping
|
236
|
+
end
|
237
|
+
|
238
|
+
# Retrieves the most recent snapshot with a specific name AND one or more other filters
|
239
|
+
#
|
240
|
+
# @param [String] server_name name of server with the volume to clone.
|
241
|
+
# @param [String, nil] extra additional AWS compatible filters for searching.
|
242
|
+
#
|
243
|
+
# @return [AWS::EC2::Snapshot, nil] matching snapshot or nil if no matching snapshot
|
244
|
+
#
|
245
|
+
def get_latest_snapshot(server_name, extra = nil)
|
246
|
+
puts " Retrieving snapshot for #{server_name} #{extra}"
|
247
|
+
|
248
|
+
filter = server_name
|
249
|
+
filter += " (#{server_name} #{extra})" unless extra.nil? || extra.empty?
|
250
|
+
get_latest_snapshot_by_name(filter)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Retrieves the most recent snapshot for a volume with a specific name
|
254
|
+
#
|
255
|
+
# @param [String] name_filter AWS compatible filter for the Name tag on a snapshot
|
256
|
+
#
|
257
|
+
# @return [AWS::EC2::Snapshot, nil] matching snapshot or nil if no matching snapshot
|
258
|
+
#
|
259
|
+
def get_latest_snapshot_by_name(name_filter)
|
260
|
+
puts " Retrieving snapshot with filter tag:Name='#{name_filter}'"
|
261
|
+
|
262
|
+
snapshot = nil
|
263
|
+
@ec2.snapshots.filter("tag:Name", name_filter).each do |s|
|
264
|
+
next unless s.status == :completed
|
265
|
+
snapshot = s if snapshot.nil? || snapshot.start_time < s.start_time
|
266
|
+
end
|
267
|
+
snapshot
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Sean Laurent
|
3
|
+
#
|
4
|
+
module EC2Launcher
|
5
|
+
class ConfigDSL
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
def config(&block)
|
9
|
+
return @config if block.nil?
|
10
|
+
|
11
|
+
@config = Config.new
|
12
|
+
@config.instance_eval &block
|
13
|
+
@config
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.execute(dsl)
|
17
|
+
new.tap do |context|
|
18
|
+
context.instance_eval(dsl)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Config
|
24
|
+
DEFAULT_CONFIG_ERB = %q{
|
25
|
+
config do
|
26
|
+
environments "environments"
|
27
|
+
applications "applications"
|
28
|
+
|
29
|
+
package_manager "apt"
|
30
|
+
config_manager "chef"
|
31
|
+
end
|
32
|
+
}.gsub(/^ /, '')
|
33
|
+
|
34
|
+
def environments(*environments)
|
35
|
+
if environments.empty?
|
36
|
+
@environments
|
37
|
+
else
|
38
|
+
if environments[0].kind_of? Array
|
39
|
+
@environments = @environments[0]
|
40
|
+
else
|
41
|
+
@environments = [ environments[0] ]
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def applications(*applications)
|
48
|
+
if applications.empty?
|
49
|
+
@applications
|
50
|
+
else
|
51
|
+
if applications[0].kind_of? Array
|
52
|
+
@applications = @applications[0]
|
53
|
+
else
|
54
|
+
@applications = [ applications[0] ]
|
55
|
+
end
|
56
|
+
self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def package_manager(*package_manager)
|
61
|
+
if package_manager.empty?
|
62
|
+
@package_manager
|
63
|
+
else
|
64
|
+
@package_manager = package_manager[0]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def config_manager(*config_manager)
|
69
|
+
if config_manager.empty?
|
70
|
+
@config_manager
|
71
|
+
else
|
72
|
+
@config_manager = config_manager[0]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Sean Laurent
|
3
|
+
#
|
4
|
+
module EC2Launcher
|
5
|
+
DEFAULT_VOLUME_SIZE = 60 # in GB
|
6
|
+
|
7
|
+
AVAILABILITY_ZONES = %w{us-east-1a us-east-1b us-east-1c us-east-1d}
|
8
|
+
INSTANCE_TYPES = %w{m1.small m1.medium m1.large m1.xlarge t1.micro m2.xlarge m2.2xlarge m2.4xlarge c1.medium c1.xlarge cc1.4xlarge cg1.4xlarge}
|
9
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Sean Laurent
|
3
|
+
#
|
4
|
+
module EmailNotifications
|
5
|
+
attr_reader :email_notifications
|
6
|
+
|
7
|
+
def email_notification(&block)
|
8
|
+
notifications = EmailNotification.new
|
9
|
+
notifications.instance_exec(&block)
|
10
|
+
@email_notifications = notifications
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class EmailNotification
|
15
|
+
def initialize()
|
16
|
+
end
|
17
|
+
|
18
|
+
def from(*from)
|
19
|
+
if from.empty?
|
20
|
+
@from
|
21
|
+
else
|
22
|
+
@from = from[0]
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to(*to)
|
28
|
+
if to.empty?
|
29
|
+
@to
|
30
|
+
else
|
31
|
+
@to = to[0]
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def ses_access_key(*ses_access_key)
|
37
|
+
if ses_access_key.empty?
|
38
|
+
@ses_access_key
|
39
|
+
else
|
40
|
+
@ses_access_key = ses_access_key[0]
|
41
|
+
self
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def ses_secret_key(*ses_secret_key)
|
46
|
+
if ses_secret_key.empty?
|
47
|
+
@ses_secret_key
|
48
|
+
else
|
49
|
+
@ses_secret_key = ses_secret_key[0]
|
50
|
+
self
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_json(*a)
|
55
|
+
{
|
56
|
+
"from" => @from,
|
57
|
+
"to" => @to,
|
58
|
+
"ses_access_key" => @ses_access_key,
|
59
|
+
"ses_secret_key" => @ses_secret_key
|
60
|
+
}.to_json(*a)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Sean Laurent
|
3
|
+
#
|
4
|
+
require 'ec2launcher/email_notification'
|
5
|
+
|
6
|
+
module EC2Launcher
|
7
|
+
class Environment
|
8
|
+
include EmailNotifications
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize()
|
13
|
+
@aliases = []
|
14
|
+
@email_notifications = nil
|
15
|
+
@gems = []
|
16
|
+
@packages = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def environment(name)
|
20
|
+
@name = name
|
21
|
+
yield self
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def aws_keyfile(*aws_keyfile)
|
26
|
+
if aws_keyfile.empty?
|
27
|
+
@aws_keyfile
|
28
|
+
else
|
29
|
+
@aws_keyfile = aws_keyfile[0]
|
30
|
+
self
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def aliases(*aliases)
|
35
|
+
if aliases.empty?
|
36
|
+
@aliases
|
37
|
+
else
|
38
|
+
if aliases[0].kind_of? String
|
39
|
+
@aliases = [ aliases[0] ]
|
40
|
+
else
|
41
|
+
@aliases = aliases[0]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def ami_name(*ami_name)
|
47
|
+
if ami_name.empty?
|
48
|
+
@ami_name
|
49
|
+
else
|
50
|
+
if ami_name[0].kind_of? String
|
51
|
+
@ami_name = /#{ami_name[0]}/
|
52
|
+
else
|
53
|
+
@ami_name = ami_name[0]
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def availability_zone(*zone)
|
60
|
+
if zone.empty?
|
61
|
+
@availability_zone
|
62
|
+
else
|
63
|
+
@availability_zone = zone[0].to_s
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def chef_server_url(*server_url)
|
69
|
+
if server_url.empty?
|
70
|
+
@chef_server_url
|
71
|
+
else
|
72
|
+
@chef_server_url = server_url[0]
|
73
|
+
self
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def chef_validation_pem_url(*chef_validation_pem_url)
|
78
|
+
if chef_validation_pem_url.empty?
|
79
|
+
@chef_validation_pem_url
|
80
|
+
else
|
81
|
+
@chef_validation_pem_url = chef_validation_pem_url[0]
|
82
|
+
self
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def domain_name(*domain_name)
|
87
|
+
if domain_name.empty?
|
88
|
+
@domain_name
|
89
|
+
else
|
90
|
+
@domain_name = domain_name[0]
|
91
|
+
self
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def gems(*gems)
|
96
|
+
if gems.empty?
|
97
|
+
@gems
|
98
|
+
else
|
99
|
+
@gems = gems[0]
|
100
|
+
self
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def key_name(*key)
|
105
|
+
if key.empty?
|
106
|
+
@key_name
|
107
|
+
else
|
108
|
+
@key_name = key[0]
|
109
|
+
self
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def packages(*packages)
|
114
|
+
if packages.empty?
|
115
|
+
@packages
|
116
|
+
else
|
117
|
+
@packages = packages[0]
|
118
|
+
self
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def roles(*roles)
|
123
|
+
if roles.empty?
|
124
|
+
@roles
|
125
|
+
else
|
126
|
+
@roles = [] if @roles.nil?
|
127
|
+
if roles[0].kind_of? Array
|
128
|
+
@roles += roles[0]
|
129
|
+
else
|
130
|
+
@roles = []
|
131
|
+
@roles << roles[0]
|
132
|
+
end
|
133
|
+
self
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def security_groups(*security_groups)
|
138
|
+
if security_groups.empty?
|
139
|
+
@security_groups
|
140
|
+
else
|
141
|
+
@security_groups = [] if @security_groups.nil?
|
142
|
+
if security_groups[0].kind_of? Array
|
143
|
+
@security_groups += security_groups[0]
|
144
|
+
else
|
145
|
+
@security_groups << security_groups[0]
|
146
|
+
end
|
147
|
+
self
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def short_name(*short_name)
|
152
|
+
if short_name.empty?
|
153
|
+
@short_name
|
154
|
+
else
|
155
|
+
@short_name = short_name[0]
|
156
|
+
self
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def subnet(*subnet)
|
161
|
+
if subnet.empty?
|
162
|
+
@subnet
|
163
|
+
else
|
164
|
+
@subnet = subnet[0]
|
165
|
+
self
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def load(dsl)
|
170
|
+
self.instance_eval(dsl)
|
171
|
+
self
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.load(dsl)
|
175
|
+
env = Environment.new.instance_eval(dsl)
|
176
|
+
env
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|