ec2launcher 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|