ec2launcher 1.0.10 → 1.0.11

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.
@@ -0,0 +1,67 @@
1
+ #
2
+ # Copyright (c) 2012 Sean Laurent
3
+ #
4
+
5
+ module EC2Launcher
6
+ module DSL
7
+ module EmailNotifications
8
+ attr_reader :email_notifications
9
+
10
+ def email_notification(&block)
11
+ notifications = EC2Launcher::DSL::EmailNotification.new
12
+ notifications.instance_exec(&block)
13
+ @email_notifications = notifications
14
+ end
15
+ end
16
+
17
+ class EmailNotification
18
+ def initialize()
19
+ end
20
+
21
+ def from(*from)
22
+ if from.empty?
23
+ @from
24
+ else
25
+ @from = from[0]
26
+ self
27
+ end
28
+ end
29
+
30
+ def to(*to)
31
+ if to.empty?
32
+ @to
33
+ else
34
+ @to = to[0]
35
+ self
36
+ end
37
+ end
38
+
39
+ def ses_access_key(*ses_access_key)
40
+ if ses_access_key.empty?
41
+ @ses_access_key
42
+ else
43
+ @ses_access_key = ses_access_key[0]
44
+ self
45
+ end
46
+ end
47
+
48
+ def ses_secret_key(*ses_secret_key)
49
+ if ses_secret_key.empty?
50
+ @ses_secret_key
51
+ else
52
+ @ses_secret_key = ses_secret_key[0]
53
+ self
54
+ end
55
+ end
56
+
57
+ def to_json(*a)
58
+ {
59
+ "from" => @from,
60
+ "to" => @to,
61
+ "ses_access_key" => @ses_access_key,
62
+ "ses_secret_key" => @ses_secret_key
63
+ }.to_json(*a)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,221 @@
1
+ #
2
+ # Copyright (c) 2012 Sean Laurent
3
+ #
4
+ require 'ec2launcher/dsl/email_notification'
5
+ require 'ec2launcher/security_group_handler'
6
+
7
+ module EC2Launcher
8
+ module DSL
9
+ class Environment
10
+ include EC2Launcher::DSL::EmailNotifications
11
+ include EC2Launcher::SecurityGroupHandler
12
+
13
+ attr_reader :name
14
+ attr_reader :precommands
15
+ attr_reader :postcommands
16
+
17
+ def initialize()
18
+ @aliases = []
19
+ @email_notifications = nil
20
+ @gems = []
21
+ @packages = []
22
+ @precommands = []
23
+ @postcommands = []
24
+ @roles = []
25
+ @security_groups = {}
26
+ end
27
+
28
+ def environment(name)
29
+ @name = name
30
+ yield self
31
+ self
32
+ end
33
+
34
+ def aws_keyfile(*aws_keyfile)
35
+ if aws_keyfile.empty?
36
+ @aws_keyfile
37
+ else
38
+ @aws_keyfile = aws_keyfile[0]
39
+ self
40
+ end
41
+ end
42
+
43
+ def aliases(*aliases)
44
+ if aliases.empty?
45
+ @aliases
46
+ else
47
+ if aliases[0].kind_of? String
48
+ @aliases = [ aliases[0] ]
49
+ else
50
+ @aliases = aliases[0]
51
+ end
52
+ end
53
+ end
54
+
55
+ def ami_name(*ami_name)
56
+ if ami_name.empty?
57
+ @ami_name
58
+ else
59
+ if ami_name[0].kind_of? String
60
+ @ami_name = /#{ami_name[0]}/
61
+ else
62
+ @ami_name = ami_name[0]
63
+ end
64
+ self
65
+ end
66
+ end
67
+
68
+ def availability_zone(*zone)
69
+ if zone.empty?
70
+ @availability_zone
71
+ else
72
+ @availability_zone = zone[0].to_s
73
+ self
74
+ end
75
+ end
76
+
77
+ def chef_server_url(*server_url)
78
+ if server_url.empty?
79
+ @chef_server_url
80
+ else
81
+ @chef_server_url = server_url[0]
82
+ self
83
+ end
84
+ end
85
+
86
+ def chef_validation_pem_url(*chef_validation_pem_url)
87
+ if chef_validation_pem_url.empty?
88
+ @chef_validation_pem_url
89
+ else
90
+ @chef_validation_pem_url = chef_validation_pem_url[0]
91
+ self
92
+ end
93
+ end
94
+
95
+ def domain_name(*domain_name)
96
+ if domain_name.empty?
97
+ @domain_name
98
+ else
99
+ @domain_name = domain_name[0]
100
+ self
101
+ end
102
+ end
103
+
104
+ def gems(*gems)
105
+ if gems.empty?
106
+ @gems
107
+ else
108
+ @gems = gems[0]
109
+ self
110
+ end
111
+ end
112
+
113
+ def inherit(*inherit_type)
114
+ if inherit_type.empty?
115
+ @inherit_type
116
+ else
117
+ @inherit_type = inherit_type[0]
118
+ end
119
+ end
120
+
121
+ def key_name(*key)
122
+ if key.empty?
123
+ @key_name
124
+ else
125
+ @key_name = key[0]
126
+ self
127
+ end
128
+ end
129
+
130
+ def packages(*packages)
131
+ if packages.empty?
132
+ @packages
133
+ else
134
+ @packages = packages[0]
135
+ self
136
+ end
137
+ end
138
+
139
+ def precommand(*command)
140
+ @precommands << command[0]
141
+ end
142
+
143
+ def postcommand(*command)
144
+ @postcommands << command[0]
145
+ end
146
+
147
+ def roles(*roles)
148
+ if roles.empty?
149
+ @roles
150
+ else
151
+ @roles = [] if @roles.nil?
152
+ if roles[0].kind_of? Array
153
+ @roles += roles[0]
154
+ else
155
+ @roles = []
156
+ @roles << roles[0]
157
+ end
158
+ self
159
+ end
160
+ end
161
+
162
+ def short_name(*short_name)
163
+ if short_name.empty?
164
+ @short_name
165
+ else
166
+ @short_name = short_name[0]
167
+ self
168
+ end
169
+ end
170
+
171
+ def subnet(*subnet)
172
+ if subnet.empty?
173
+ @subnet
174
+ else
175
+ @subnet = subnet[0]
176
+ self
177
+ end
178
+ end
179
+
180
+ # Takes values from the other environment and merges them into this one
181
+ def merge(other_env)
182
+ @name =other_env.name
183
+
184
+ @gems += other_env.gems unless other_env.gems.nil?
185
+ @packages += other_env.packages unless other_env.packages.nil?
186
+ @roles += other_env.roles unless other_env.roles.nil?
187
+ @precommands += other_env.precommands unless other_env.precommands.nil?
188
+ @postcommands += other_env.postcommands unless other_env.postcommands.nil?
189
+ unless other_env.security_groups.nil?
190
+ other_env.security_groups.keys.each do |key|
191
+ @security_groups[key] = [] if @security_groups[key].nil?
192
+ @security_groups[key] += other_env.security_groups[key]
193
+ end
194
+ end
195
+
196
+ @aliases = other_env.aliases.nil? ? nil : other_env.aliases
197
+
198
+ @ami_name = other_env.ami_name unless other_env.ami_name.nil?
199
+ @aws_keyfile = other_env.aws_keyfile unless other_env.aws_keyfile.nil?
200
+ @availability_zone = other_env.availability_zone unless other_env.availability_zone.nil?
201
+ @chef_server_url = other_env.chef_server_url unless other_env.chef_server_url.nil?
202
+ @chef_validation_pem_url = other_env.chef_validation_pem_url unless other_env.chef_validation_pem_url.nil?
203
+ @domain_name = other_env.domain_name unless other_env.domain_name.nil?
204
+ @email_notifications = other_env.email_notifications unless other_env.email_notifications.nil?
205
+ @key_name = other_env.key_name unless other_env.key_name.nil?
206
+ @subnet = other_env.subnet unless other_env.subnet.nil?
207
+ @short_name = other_env.short_name unless other_env.short_name.nil?
208
+ end
209
+
210
+ def load(dsl)
211
+ self.instance_eval(dsl)
212
+ self
213
+ end
214
+
215
+ def self.load(dsl)
216
+ env = EC2Launcher::DSL::Environment.new.instance_eval(dsl)
217
+ env
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,117 @@
1
+ #
2
+ # Copyright (c) 2012 Sean Laurent
3
+ #
4
+ require 'rubygems'
5
+ require 'aws-sdk'
6
+
7
+ module EC2Launcher
8
+ # Helper class to generate sequential, numbered host names
9
+ class HostnameGenerator
10
+ #
11
+ # @param [AWS::EC2] ec2 EC2 object used to query for existing instances
12
+ # @param [EC2Launcher::Environment] environment Environment to use for generating host names
13
+ # @param [EC2Launcher::Application] application Application to use for generating hostn ames
14
+ def initialize(ec2, environment, application)
15
+ @ec2 = ec2
16
+ @server_name_cache = nil
17
+
18
+ @prefix = application.basename
19
+ @prefix ||= application.name
20
+
21
+ @env_suffix = environment.short_name
22
+ @env_suffix ||= environment.name
23
+
24
+ @suffix = @env_suffix
25
+ unless application.name_suffix.nil?
26
+ @suffix = "#{application.name_suffix}.#{@env_suffix}"
27
+ end
28
+
29
+ @host_number_regex = Regexp.new("#{@prefix}(\\d+)[.]#{@suffix.gsub(/[.]/, "[.]")}.*")
30
+
31
+ # Load and cache instance names
32
+ load_instances(@prefix, @suffix)
33
+ end
34
+
35
+ # Generates a new host name and automatically caches it
36
+ # so that future requests don't use the same name.
37
+ def generate_hostname()
38
+ # Find next host number
39
+ host_number = get_next_host_number()
40
+
41
+ # Build short host name
42
+ short_name = "#{@prefix}#{host_number}.#{@suffix}"
43
+
44
+ # Cache the new hostname
45
+ @server_name_cache << short_name
46
+
47
+ short_name
48
+ end
49
+
50
+ def generate_long_name(short_hostname, domain_name = nil)
51
+ hostname = short_hostname
52
+ unless domain_name.nil?
53
+ hostname += ".#{domain_name}"
54
+ end
55
+
56
+ hostname
57
+ end
58
+
59
+ def generate_short_name(long_name, domain_name = nil)
60
+ short_hostname = long_name
61
+ unless domain_name.nil?
62
+ short_hostname = long_name.gsub(/.#{domain_name}/, '')
63
+ end
64
+ short_hostname
65
+ end
66
+
67
+ private
68
+
69
+ # Loads and caches instance host names
70
+ def load_instances(prefix, suffix)
71
+ @server_name_cache = []
72
+ AWS.memoize do
73
+ server_instances = @ec2.instances.filter("tag:Name", "#{prefix}*#{suffix}*")
74
+ server_instances.each do |i|
75
+ next if i.status == :terminated
76
+ @server_name_cache << i.tags[:Name]
77
+ end
78
+ end
79
+ end
80
+
81
+ # Determines the next available number for a host name
82
+ def get_next_host_number()
83
+ highest_server_number = 0
84
+ lowest_server_number = 32768
85
+
86
+ server_numbers = []
87
+
88
+ @server_name_cache.each do |server_name|
89
+ unless @host_number_regex.match(server_name).nil?
90
+ server_num = $1.to_i
91
+ server_numbers << server_num
92
+ end
93
+ end
94
+ highest_server_number = server_numbers.max
95
+
96
+ # If the highest number server is less than 10, just add
97
+ # 1 to it. Otherwise, find the first available
98
+ # server number starting at 1.
99
+ host_number = 0
100
+ if highest_server_number.nil?
101
+ host_number = 1
102
+ elsif highest_server_number < 10
103
+ host_number = highest_server_number + 1
104
+ else
105
+ # Try to start over with 1 and find the
106
+ # first available host number
107
+ server_number_set = Set.new(server_numbers)
108
+ host_number = 1
109
+ while server_number_set.include?(host_number) do
110
+ host_number += 1
111
+ end
112
+ end
113
+
114
+ host_number
115
+ end
116
+ end
117
+ end
@@ -51,26 +51,30 @@ module EC2Launcher
51
51
  opts.separator ""
52
52
  opts.separator "Additional launch options:"
53
53
 
54
- opts.on("--command [CMD]", "Additional command to run during launch sequence.") do |command|
54
+ opts.on("--command [CMD]", String, "Additional command to run during launch sequence.") do |command|
55
55
  @options.commands << command
56
56
  end
57
57
 
58
- opts.on("-c", "--clone HOST", "Clone the latest snapshots from a specific host.") do |clone_host|
58
+ opts.on("--clone HOST", String, "Clone the latest snapshots from a specific host.") do |clone_host|
59
59
  @options.clone_host = clone_host
60
60
  end
61
61
 
62
+ opts.on("-c", "--count COUNT", Integer, "Number of new instances to launch.") do |count|
63
+ @options.count = count
64
+ end
65
+
62
66
  opts.separator ""
63
67
  opts.separator "Overrides:"
64
68
 
65
- opts.on("-d", "--directory DIRECTORY", "Location of configuration directory. Defaults to current directory.") do |directory|
69
+ opts.on("-d", "--directory DIRECTORY", String, "Location of configuration directory. Defaults to current directory.") do |directory|
66
70
  @options.directory = directory
67
71
  end
68
72
 
69
- opts.on("-h", "--hostname NAME", "The name for the new server.") do |hostname|
73
+ opts.on("-h", "--hostname NAME", String, "The name for the new server.") do |hostname|
70
74
  @options.hostname = hostname
71
75
  end
72
76
 
73
- opts.on("-u", "--chef-validation-url", "URL for the Chef validation pem file.") do |chef_validation_url|
77
+ opts.on("-u", "--chef-validation-url", String, "URL for the Chef validation pem file.") do |chef_validation_url|
74
78
  @options.chef_validation_url = chef_validation_url
75
79
  end
76
80
 
@@ -93,11 +97,11 @@ module EC2Launcher
93
97
  opts.separator ""
94
98
  opts.separator "AWS Security Options:"
95
99
 
96
- opts.on("--access-key KEY", "Amazon access key. Overrides AWS_ACCESS_KEY environment variable.") do |access_key|
100
+ opts.on("--access-key KEY", String, "Amazon access key. Overrides AWS_ACCESS_KEY environment variable.") do |access_key|
97
101
  @options.access_key = access_key
98
102
  end
99
103
 
100
- opts.on("--secret SECRET", "Amazon secret access key. Overrides AWS_SECRET_ACCESS_KEY environment variable.") do |secret|
104
+ opts.on("--secret SECRET", String, "Amazon secret access key. Overrides AWS_SECRET_ACCESS_KEY environment variable.") do |secret|
101
105
  @options.secret = secret
102
106
  end
103
107
 
@@ -130,6 +134,7 @@ module EC2Launcher
130
134
  @options.application = nil
131
135
  @options.commands = []
132
136
  @options.clone_host = nil
137
+ @options.count = 1
133
138
 
134
139
  @options.ami_id = nil
135
140
  @options.hostname = nil
@@ -156,6 +161,12 @@ module EC2Launcher
156
161
  help
157
162
  exit 1
158
163
  end
164
+
165
+ if ! @options.hostname.nil? && @options.count > 1
166
+ puts "Cannot specify both a hostname ['#{@options.hostname}'] and multiple instances [#{@options.count}]."
167
+ puts
168
+ exit 1
169
+ end
159
170
  end
160
171
 
161
172
  @options
@@ -2,5 +2,5 @@
2
2
  # Copyright (c) 2012 Sean Laurent
3
3
  #
4
4
  module Ec2launcher
5
- VERSION = "1.0.10"
5
+ VERSION = "1.0.11"
6
6
  end