conan 0.3.5 → 0.4.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.
@@ -1,5 +1,7 @@
1
1
  require "bundler/capistrano"
2
2
  require "conan/deployment"
3
+ require "conan/cloud/aws/provision"
4
+ require "conan/cloud/aws/autoscale"
3
5
 
4
6
  Capistrano::Configuration.instance(:must_exist).load do
5
7
  Conan::Deployment.define_tasks(self)
@@ -0,0 +1,106 @@
1
+ require 'fileutils'
2
+ require 'fog'
3
+ require 'json'
4
+
5
+ require_relative "./utils"
6
+
7
+ module AWS
8
+ class Autoscale
9
+ include Utils
10
+
11
+ attr_accessor :autoscale_config, :stage, :application
12
+
13
+ def initialize(stage = 'production', autoscale_config = {}, application = nil)
14
+ @autoscale_config = autoscale_config
15
+ @stage = stage
16
+ @application = application
17
+ end
18
+
19
+ def create_ami_from_server(server_name, region, image_description = nil)
20
+ image_name = "#{server_name}-image-#{Time.now.strftime('%Y%m%d%H%M')}" if image_name.nil?
21
+ image_description = "Image of #{server_name} created at #{DateTime.now} by conan"
22
+ server_to_image = find_server_by_name(server_name, region)
23
+
24
+ raise "Server #{server_name} in #{region} does not exist" if server_to_image.nil?
25
+
26
+ compute = Fog::Compute.new(:provider => :aws, :region => region)
27
+ puts "Creating image #{image_name} from server #{server_name}"
28
+ ami_request = compute.create_image(server_to_image.id, image_name, image_description)
29
+ image_id = ami_request.body["imageId"]
30
+
31
+ pending = true
32
+ image = nil
33
+
34
+ puts "Waiting for #{image_id} to become available"
35
+ while pending
36
+ sleep 10
37
+ image = compute.images.get(image_id)
38
+ pending = image.state == "pending"
39
+ end
40
+
41
+ raise "Image creation failed" if image.state == 'failed'
42
+ image_id
43
+
44
+ end
45
+
46
+ def create_launch_config(name, config = {})
47
+ new_conf = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
48
+ region = new_conf[:region] || "us-east-1"
49
+
50
+ compute = Fog::Compute.new(:provider => :aws, :region => region)
51
+ default_key_name = compute.key_pairs.all.first.name
52
+
53
+ default_params = { :instance_monitoring => true,
54
+ :instance_type => "m1.small",
55
+ :key_name => default_key_name
56
+ }
57
+
58
+ params = default_params.merge(new_conf)
59
+
60
+ if new_conf[:security_groups] and new_conf[:security_groups].size > 0
61
+ params[:security_groups] = new_conf[:security_groups].collect { |g| "#{stage}-#{g}" }
62
+ else
63
+ params[:security_groups] = ["#{stage}-default"]
64
+ end
65
+
66
+ if params[:server_to_image].nil?
67
+ params[:image_id] = default_image_id(region, params[:flavor_id], params[:root_device_type]) if params[:image_id].nil?
68
+ else
69
+ params[:image_id] = create_ami_from_server(params[:server_to_image], region) end
70
+
71
+ autoscale = Fog::AWS::AutoScaling.new(:region => region)
72
+
73
+ #need to create new launchconfiugrations with unique names
74
+ #because you can't modify them and you can't delete them if they are attached
75
+ #to an autoscale group
76
+ params[:id] = "#{ec2_name_tag(name)}-#{Time.now.strftime('%Y%m%d%H%M')}"
77
+
78
+ puts "Creating Autoscale Launch Configuration #{params[:id]}"
79
+ lc = autoscale.configurations.create(params)
80
+
81
+ params[:autoscale_groups].each do |group_name|
82
+ asg = autoscale.groups.get(group_name)
83
+ "Setting Autoscale Group #{group_name} to use Launch Configration #{params[:id]}"
84
+ asg.connection.update_auto_scaling_group(asg.id, {"LaunchConfigurationName" => params[:id]})
85
+ end unless params[:autoscale_groups].nil?
86
+
87
+ end
88
+
89
+ def configure_autoscale
90
+ end
91
+
92
+ def update_autoscale
93
+ autoscale_config.each do |type, resources|
94
+ case type
95
+ when "launch-config"
96
+ resources.each do |name, conf|
97
+ create_launch_config(name, conf)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ end
104
+ end
105
+
106
+
@@ -2,72 +2,72 @@
2
2
  "ubuntu 10.04": {
3
3
  "ap-northeast-1": {
4
4
  "64-bit": {
5
- "ebs": "ami-36e65037",
6
- "instance-store": "ami-baf94fbb"
5
+ "ebs": "ami-942f9995",
6
+ "instance-store": "ami-902f9991"
7
7
  },
8
8
  "32-bit": {
9
- "ebs": "ami-1ae6501b",
10
- "instance-store": "ami-46f94f47"
9
+ "ebs": "ami-922f9993",
10
+ "instance-store": "ami-842f9985"
11
11
  }
12
12
  },
13
13
  "ap-southeast-1": {
14
14
  "64-bit": {
15
- "ebs": "ami-c0c98c92",
16
- "instance-store": "ami-3cc98c6e"
15
+ "ebs": "ami-7089cd22",
16
+ "instance-store": "ami-4e89cd1c"
17
17
  },
18
18
  "32-bit": {
19
- "ebs": "ami-d8c98c8a",
20
- "instance-store": "ami-76c98c24"
19
+ "ebs": "ami-7289cd20",
20
+ "instance-store": "ami-4489cd16"
21
21
  }
22
22
  },
23
23
  "eu-west-1": {
24
24
  "64-bit": {
25
- "ebs": "ami-81dde2f5",
26
- "instance-store": "ami-3fdde24b"
25
+ "ebs": "ami-fb665f8f",
26
+ "instance-store": "ami-1b665f6f"
27
27
  },
28
28
  "32-bit": {
29
- "ebs": "ami-95dde2e1",
30
- "instance-store": "ami-fddee189"
29
+ "ebs": "ami-f3665f87",
30
+ "instance-store": "ami-39665f4d"
31
31
  }
32
32
  },
33
33
  "sa-east-1": {
34
34
  "64-bit": {
35
- "ebs": "ami-645f8079",
36
- "instance-store": "ami-7a5f8067"
35
+ "ebs": "ami-7874ab65",
36
+ "instance-store": "ami-7c74ab61"
37
37
  },
38
38
  "32-bit": {
39
- "ebs": "ami-6a5f8077",
40
- "instance-store": "ami-4a5f8057"
39
+ "ebs": "ami-7e74ab63",
40
+ "instance-store": "ami-4674ab5b"
41
41
  }
42
42
  },
43
43
  "us-east-1": {
44
44
  "64-bit": {
45
- "ebs": "ami-55dc0b3c",
46
- "instance-store": "ami-35de095c"
45
+ "ebs": "ami-349b495d",
46
+ "instance-store": "ami-5c9b4935"
47
47
  },
48
48
  "32-bit": {
49
- "ebs": "ami-71dc0b18",
50
- "instance-store": "ami-4fd00726"
49
+ "ebs": "ami-3e9b4957",
50
+ "instance-store": "ami-809a48e9"
51
51
  }
52
52
  },
53
53
  "us-west-1": {
54
54
  "64-bit": {
55
- "ebs": "ami-a191cfe4",
56
- "instance-store": "ami-3991cf7c"
55
+ "ebs": "ami-7fb0e93a",
56
+ "instance-store": "ami-6bb0e92e"
57
57
  },
58
58
  "32-bit": {
59
- "ebs": "ami-9991cfdc",
60
- "instance-store": "ami-b390cef6"
59
+ "ebs": "ami-7db0e938",
60
+ "instance-store": "ami-63b0e926"
61
61
  }
62
62
  },
63
63
  "us-west-2": {
64
64
  "64-bit": {
65
- "ebs": "ami-8eb33ebe",
66
- "instance-store": "ami-94b33ea4"
65
+ "ebs": "ami-ec0b86dc",
66
+ "instance-store": "ami-e60b86d6"
67
67
  },
68
68
  "32-bit": {
69
- "ebs": "ami-8cb33ebc",
70
- "instance-store": "ami-bcb33e8c"
69
+ "ebs": "ami-ea0b86da",
70
+ "instance-store": "ami-e00b86d0"
71
71
  }
72
72
  }
73
73
  }
@@ -2,52 +2,60 @@ require "fileutils"
2
2
  require "fog"
3
3
  require "json"
4
4
 
5
+ require_relative "./utils"
6
+ require_relative "./security_group"
7
+
5
8
  module AWS
9
+
6
10
  class Provision
11
+ include Utils
12
+
13
+ attr_accessor :aws_config, :stage, :application
7
14
 
8
- def initialize(aws_config = {}, stage = 'production')
15
+ def initialize(stage = 'production', aws_config = {}, application = nil)
9
16
  @aws_config = aws_config
10
17
  @stage = stage
18
+ @application = application
11
19
  end
12
20
 
13
- def describe_env_to_json(file_path)
14
- servers_json = {}
21
+ def describe_env(filter_role = nil)
22
+ server_config = {}
15
23
  servers = []
16
- ["us-east-1", "us-west-1", "eu-west-1", "ap-southeast-1", "ap-northeast-1"].each do |region|
24
+ all_regions.each do |region|
17
25
  compute = Fog::Compute.new(:provider => :aws, :region => region)
18
26
  compute.servers.all.each { |s| servers << s if s.state == 'running' }
19
27
  end
20
28
  stages = servers.map {|s| s.tags["stage"] }.uniq
21
29
 
22
- stages.each do | stage|
23
- servers_json[stage] = {}
30
+ stages.each do | st|
31
+ server_config[st] = {}
24
32
  servers.each do |server|
25
- if server.tags["stage"] == stage
26
- server_json = {}
27
- server_json[:roles] = server.tags["roles"].split(", ") unless server.tags["roles"].nil?
28
- server_json[:alias] = server.tags["name"]
29
- servers_json[stage][server.dns_name] = server_json
33
+ if server.tags["stage"] == st
34
+ config = {}
35
+ config["roles"] = server.tags["roles"].split(", ") unless server.tags["roles"].nil?
36
+ config["alias"] = server.tags["name"]
37
+ if filter_role.nil? || config["roles"].include?(filter_role)
38
+ server_config[st][server.dns_name] = config
39
+ end
30
40
  end
31
41
  end
32
42
  end
43
+ server_config
33
44
 
34
- File.open(file_path, "w") do |io|
35
- io << JSON.pretty_generate(servers_json)
36
- end
37
45
  end
38
46
 
39
- def build_env()
47
+ def build_env
40
48
 
41
49
  #we need to check the existance of ~/.fog
42
50
 
43
51
  #first key_pairs
44
- key_pairs = @aws_config["key_pairs"]
52
+ key_pairs = aws_config["key_pairs"]
45
53
 
46
54
  key_pairs.each do |name, conf|
47
55
  create_key_pair(name, conf)
48
56
  end unless key_pairs.nil?
49
57
 
50
- security_groups = @aws_config["security"]
58
+ security_groups = aws_config["security"]
51
59
 
52
60
  if security_groups.nil? or security_groups.size == 0
53
61
  create_default_security_groups()
@@ -59,9 +67,13 @@ module AWS
59
67
  security_groups["rds"].each do |name, conf|
60
68
  create_rds_security_group(name, conf)
61
69
  end unless security_groups["rds"].nil?
70
+
71
+ security_groups["elasticache"].each do |name, conf|
72
+ create_elasticache_security_group(name, conf)
73
+ end unless security_groups["elasticache"].nil?
62
74
  end
63
75
 
64
- @aws_config.each do |type, resources|
76
+ aws_config.each do |type, resources|
65
77
  case type
66
78
  when "ec2"
67
79
  resources.each do |name, conf|
@@ -79,6 +91,10 @@ module AWS
79
91
  resources.each do |name,conf|
80
92
  create_elb(name, conf)
81
93
  end
94
+ when "elasticache"
95
+ resources.each do |name,conf|
96
+ create_elasticache_cluster(name,conf)
97
+ end
82
98
  end
83
99
  end
84
100
  end
@@ -116,15 +132,22 @@ module AWS
116
132
 
117
133
  compute = Fog::Compute.new(:provider => :aws, :region => region)
118
134
 
119
- sg_name = "#{@stage}-#{name}"
135
+ sg_name = ec2_name_tag(name)
120
136
 
121
137
  sg = compute.security_groups.get(sg_name)
122
138
  if sg.nil?
123
139
  puts "Creating EC2 Secruity Group #{sg_name}"
124
- sg = compute.security_groups.create(:name => sg_name, :description => "#{name} Security Group for #{@stage}")
125
- new_conf[:ports].each do |port|
126
- sg.authorize_port_range(Range.new(port.to_i,port.to_i))
127
- end unless new_conf[:ports].nil?
140
+ sg = compute.security_groups.create(:name => sg_name, :description => "#{name} Security Group for #{stage}")
141
+ new_conf[:ingress].each do |ingress|
142
+ ingress = ingress.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
143
+ port = ingress.delete(:port)
144
+ if ingress[:group_name]
145
+ ingress[:group_name] = ec2_name_tag(ingress[:group_name])
146
+ sg.authorize_ip_permission(Range.new(port.to_i,port.to_i),ingress)
147
+ else
148
+ sg.authorize_port_range(Range.new(port.to_i,port.to_i),ingress)
149
+ end
150
+ end unless new_conf[:ingress].nil?
128
151
  else
129
152
  puts "EC2 Security Group #{sg_name} already exists. Skipping"
130
153
  end
@@ -137,15 +160,15 @@ module AWS
137
160
  region = new_conf[:region] || "us-east-1"
138
161
  rds = Fog::AWS::RDS.new(:region => region)
139
162
 
140
- rdssg_name = "#{@stage}-db-#{name}"
163
+ rdssg_name = rds_name_tag(name)
141
164
 
142
165
  rdssg = rds.security_groups.get(rdssg_name)
143
166
 
144
167
  if rdssg.nil?
145
168
  puts "Creating RDS Security Group #{rdssg_name}"
146
- rdssg = rds.security_groups.create(:id => rdssg_name, :description => "#{name} DB Security Group For #{@stage}")
169
+ rdssg = rds.security_groups.create(:id => rdssg_name, :description => "#{name} DB Security Group For #{stage}")
147
170
  new_conf[:ec2_security_groups].each do |ec2_group|
148
- rdssg.authorize_ec2_security_group("#{@stage}-#{ec2_group}")
171
+ rdssg.authorize_ec2_security_group("#{stage}-#{ec2_group}")
149
172
  end
150
173
  else
151
174
  puts "RDS Security Group #{rdssg_name} already exists. Skipping"
@@ -154,18 +177,51 @@ module AWS
154
177
  end
155
178
  end
156
179
 
180
+ def create_elasticache_security_group(name, config = {})
181
+ unless Fog.mocking?
182
+ new_conf = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
183
+ region = new_conf[:region] || "us-east-1"
184
+ elasticache = Fog::AWS::Elasticache.new(:region => region)
185
+
186
+ cache_sg_name = elasticache_name_tag(name)
187
+
188
+ sg_exists = false
189
+ body = elasticache.describe_cache_security_groups.body
190
+ sg_exists = body['CacheSecurityGroups'].any? do |group|
191
+ group['CacheSecurityGroupName'] == cache_sg_name
192
+ end
193
+
194
+ unless sg_exists
195
+ puts "Creating Elasticache Security Group #{cache_sg_name}"
196
+ body = elasticache.create_cache_security_group(cache_sg_name, "#{cache_sg_name} ElastiCache Security Group for #{stage}").body
197
+ new_conf[:ec2_security_groups].each do |ec2_group|
198
+ compute = Fog::Compute.new(:provider => :aws, :region => region)
199
+ sg_name = ec2_name_tag(ec2_group)
200
+ sg = compute.security_groups.get(sg_name)
201
+ body = elasticache.authorize_cache_security_group_ingress(
202
+ cache_sg_name, sg.name, sg.owner_id).body
203
+ end
204
+ else
205
+ puts "Elasticache Security Group #{cache_sg_name} already exists. Skipping"
206
+ end
207
+
208
+ end
209
+ end
210
+
157
211
  def create_s3_bucket(name, config = {})
158
212
  new_conf = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
159
213
  region = new_conf[:region] || "us-east-1"
160
214
 
161
215
  storage = Fog::Storage.new(:provider => :aws, :region => region)
162
216
 
217
+ new_conf['LocationConstraint'] = new_conf.delete(:location_constraint) if new_conf[:location_constraint]
218
+
163
219
  begin
164
220
  bucket = storage.get_bucket(name)
165
221
  puts "S3 Bucket #{name} already exists. Skipping"
166
222
  rescue Excon::Errors::NotFound
167
223
  puts "Creating S3 Bucket #{name}"
168
- storage.put_bucket(name)
224
+ storage.put_bucket(name, new_conf)
169
225
 
170
226
  acl = new_conf[:acl] || 'public-read'
171
227
 
@@ -181,7 +237,7 @@ module AWS
181
237
 
182
238
  zones = new_conf[:availability_zones] || all_availability_zones(region)
183
239
 
184
- elb_name = "#{@stage}-#{name}"
240
+ elb_name = ec2_name_tag(name)
185
241
 
186
242
  lb = elb.load_balancers.get(elb_name)
187
243
  if lb.nil?
@@ -193,9 +249,9 @@ module AWS
193
249
 
194
250
  compute = Fog::Compute.new(:provider => :aws, :region => region)
195
251
 
196
- inst_servers = new_conf[:servers].map { |s| "#{@stage}-#{s}" } unless new_conf[:servers].nil?
252
+ inst_servers = new_conf[:servers].map { |s| ec2_name_tag(s) } unless new_conf[:servers].nil?
197
253
 
198
- compute.servers.all.each do |server|
254
+ list_stage_servers(region).each do |server|
199
255
  #the mocking seems wrong
200
256
  unless Fog.mocking?
201
257
  name = server.tags["name"]
@@ -213,7 +269,6 @@ module AWS
213
269
  region = new_conf[:region] || "us-east-1"
214
270
 
215
271
  compute = Fog::Compute.new(:provider => :aws, :region => region)
216
-
217
272
  default_key_name = compute.key_pairs.all.first.name
218
273
 
219
274
  default_params = { :availability_zone => default_availability_zone(region),
@@ -228,32 +283,31 @@ module AWS
228
283
 
229
284
  tags = {}
230
285
 
231
- #need to bork if no name in config file
232
- ec2_name = "#{@stage}-#{name}"
233
-
234
286
  #need to parse all servers to see if this one exists
235
- servers = compute.servers.all
236
- server_exists = false
237
- servers.each { |server| server_exists = true if server.tags["name"] == ec2_name and server.state == 'running' }
287
+ server = find_server_by_name(name, region)
238
288
 
239
- unless server_exists
289
+ #need to bork if no name in config file
290
+ ec2_name = ec2_name_tag(name)
291
+
292
+ unless server
240
293
  puts "Creating EC2 Server named #{ec2_name}"
241
294
  tags[:name] = ec2_name
242
- tags[:stage] = @stage
295
+ tags[:Name] = ec2_name
296
+ tags[:stage] = stage
243
297
 
244
298
  if new_conf[:roles]
245
- new_conf[:roles] << @stage unless new_conf[:roles].include? @stage
299
+ new_conf[:roles] << stage unless new_conf[:roles].include? stage
246
300
  tags[:roles] = new_conf[:roles].join(', ')
247
301
  else
248
- tags[:roles] = "app, db, #{@stage}"
302
+ tags[:roles] = "app, db, #{stage}"
249
303
  end
250
304
 
251
305
  params[:tags] = tags
252
306
 
253
307
  if new_conf[:groups] and new_conf[:groups].size > 0
254
- params[:groups] = new_conf[:groups].collect { |g| "#{@stage}-#{g}" }
308
+ params[:groups] = new_conf[:groups].collect { |g| "#{stage}-#{g}" }
255
309
  else
256
- params[:groups] = ["#{@stage}-default"]
310
+ params[:groups] = ["#{stage}-default"]
257
311
  end
258
312
 
259
313
  server = compute.servers.create(params)
@@ -281,12 +335,14 @@ module AWS
281
335
  }
282
336
  params = default_params.merge(new_conf)
283
337
 
284
- params[:id] = "#{@stage}-#{name}"
338
+ params[:id] = ec2_name_tag(name)
339
+
340
+ params.delete(:availability_zone) if params[:multi_az]
285
341
 
286
342
  if new_conf[:db_security_groups] and new_conf[:db_security_groups].size > 0
287
- params[:db_security_groups] = new_conf[:db_security_groups].collect { |g| "#{@stage}-db-#{g}" }
343
+ params[:security_group_names] = new_conf[:db_security_groups].collect { |g| rds_name_tag(g) }
288
344
  else
289
- params[:db_security_groups] = ["#{@stage}-db-default"]
345
+ params[:security_group_names] = [rds_name_tag('default')]
290
346
  end
291
347
 
292
348
  server = rds.servers.get(params[:id])
@@ -295,49 +351,50 @@ module AWS
295
351
  puts "Creating RDS Server #{params[:id]}"
296
352
  server = rds.servers.create(params)
297
353
  else
298
- puts "RDS Server #{params[:id]} aready exists. Skipping"
354
+ puts "RDS Server #{params[:id]} already exists. Skipping"
299
355
  end
300
356
  else
301
357
  puts "Fog is mocking. Can't test with RDS Servers. Skipping"
302
358
  end
303
359
  end
304
360
 
305
- private
361
+ def create_elasticache_cluster(name, config = {})
362
+ unless Fog.mocking?
363
+ new_conf = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
364
+ region = new_conf[:region] || "us-east-1"
306
365
 
307
- def default_availability_zone(region)
308
- #using availability zone b by default as a is often unavailable in us-east-1
309
- "#{region}b"
310
- end
366
+ elasticache = Fog::AWS::Elasticache.new(:region => region)
311
367
 
312
- def all_availability_zones(region)
313
- case region
314
- when "us-east-1"
315
- #not using availability zone us-east-1a as it often fails
316
- ["us-east-1b", "us-east-1c"]
317
- when "us-west-1"
318
- ["us-west-1a", "us-west-1b", "us-west-1c"]
319
- when "eu-west-1"
320
- ["eu-west-1a", "eu-west-1b"]
321
- when "ap-northeast-1"
322
- ["ap-northeast-1a", "ap-northeast-1a"]
323
- when "ap-southeast-1"
324
- ["ap-southeast-1a", "ap-southeast-1b"]
325
- end
326
- end
368
+ default_params = { :node_type => "cache.m1.large",
369
+ :num_nodes => 1,
370
+ :port => 11211,
371
+ :preferred_availability_zone => default_availability_zone(region)
372
+ }
327
373
 
328
- def default_image_id(region, flavor_id, root_device_type)
329
- arch = ["m1.small", "t1.micro", "c1.medium"].include?(flavor_id) ? "32-bit" : "64-bit"
374
+ params = default_params.merge(new_conf)
330
375
 
331
- defaults = JSON.parse(File.read(File.expand_path(File.join(File.dirname(__FILE__), 'default_amis.json'))))
332
-
333
- region_defaults = defaults["ubuntu 10.04"][region]
334
- raise "Invalid Region" if region_defaults.nil?
335
- default_ami = region_defaults[arch][root_device_type]
376
+ if new_conf[:security_groups] and new_conf[:security_groups].size > 0
377
+ params[:security_group_names] = new_conf[:security_groups].collect { |g| elasticache_name_tag(g) }
378
+ else
379
+ params[:security_group_names] = [elasticache_name_tag('default')]
380
+ end
381
+
382
+ cluster_name = ec2_name_tag(name)
336
383
 
337
- raise "Default AMI not found for #{region} #{flavor_id} #{root_device_type}" if default_ami.nil?
338
- default_ami
384
+ cl = elasticache.clusters.get(cluster_name)
339
385
 
386
+ unless cl
387
+ puts "Creating ElastiCache cluster #{cluster_name}"
388
+ params[:id] = cluster_name
389
+ cl = elasticache.clusters.new(params)
390
+ cl.save
391
+ else
392
+ puts "Elasticache cluster #{cluster_name} already exists. Skipping"
393
+ end
394
+
395
+ end
340
396
  end
397
+
341
398
  end
342
399
  end
343
400
 
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'fog/aws/models/compute/security_group'
3
+
4
+ module Fog
5
+ module Compute
6
+ class AWS
7
+ class SecurityGroup
8
+ def authorize_ip_permission(port_range, options = {})
9
+ requires :name
10
+
11
+ permission = {
12
+ 'FromPort' => port_range.min,
13
+ 'ToPort' => port_range.max,
14
+ 'IpProtocol' => options[:ip_protocol] || 'tcp'
15
+ }
16
+
17
+ if options[:group_name]
18
+ grp_permitted = {'GroupName' => options[:group_name]}
19
+ grp_permitted['UserId'] = options[:user_id] if options[:user_id]
20
+ permission['Groups'] = [grp_permitted]
21
+ else
22
+ ip_permitted = {'CidrIp' => "0.0.0.0/0"}
23
+ if options[:cidr_ip]
24
+ ip_permitted = {'CidrIp' => options[:cidr_ip]}
25
+ end
26
+ permission['IpRanges'] = [ip_permitted]
27
+ end
28
+
29
+ connection.authorize_security_group_ingress(
30
+ name,
31
+ 'IpPermissions' => [permission]
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,81 @@
1
+ require "fileutils"
2
+ require "fog"
3
+ require "json"
4
+
5
+ module AWS
6
+ module Utils
7
+
8
+ def ec2_name_tag(server_name)
9
+ "#{stage}-#{server_name}"
10
+ end
11
+
12
+ def rds_name_tag(server_name)
13
+ "#{stage}-db-#{server_name}"
14
+ end
15
+
16
+ def elasticache_name_tag(server_name)
17
+ "#{stage}-elasticache-#{server_name}"
18
+ end
19
+
20
+ def find_server_by_name(name, region = nil)
21
+ regions_to_search = region.nil? ? all_regions : [region]
22
+ found_servers = []
23
+ regions_to_search.each do |r|
24
+ compute = Fog::Compute.new(:provider => :aws, :region => r)
25
+ servers = compute.servers.all
26
+ found_servers = found_servers + servers.select { |server| server.tags["name"] == ec2_name_tag(name) and server.state == 'running' }
27
+ end
28
+ found_servers.empty? ? nil : found_servers[0]
29
+ end
30
+
31
+ def list_stage_servers(region = nil)
32
+ regions_to_search = region.nil? ? all_regions : [region]
33
+ found_servers = []
34
+ regions_to_search.each do |r|
35
+ compute = Fog::Compute.new(:provider => :aws, :region => r)
36
+ servers = compute.servers.all
37
+ found_servers = found_servers + servers.select { |server| server.tags["stage"] == stage and server.state == 'running' }
38
+ end
39
+ found_servers
40
+ end
41
+
42
+ def default_availability_zone(region)
43
+ #using availability zone b by default as a is often unavailable in us-east-1
44
+ "#{region}b"
45
+ end
46
+
47
+ def all_regions
48
+ ['us-east-1', 'us-west-1', 'eu-west-1', 'ap-northeast-1', 'ap-southeast-1']
49
+ end
50
+
51
+ def all_availability_zones(region)
52
+ case region
53
+ when "us-east-1"
54
+ #not using availability zone us-east-1a as it often fails
55
+ ["us-east-1b", "us-east-1c"]
56
+ when "us-west-1"
57
+ ["us-west-1a", "us-west-1b", "us-west-1c"]
58
+ when "eu-west-1"
59
+ ["eu-west-1a", "eu-west-1b"]
60
+ when "ap-northeast-1"
61
+ ["ap-northeast-1a", "ap-northeast-1a"]
62
+ when "ap-southeast-1"
63
+ ["ap-southeast-1a", "ap-southeast-1b"]
64
+ end
65
+ end
66
+
67
+ def default_image_id(region, flavor_id, root_device_type)
68
+ arch = ["m1.small", "t1.micro", "c1.medium"].include?(flavor_id) ? "32-bit" : "64-bit"
69
+
70
+ defaults = JSON.parse(File.read(File.expand_path(File.join(File.dirname(__FILE__), 'default_amis.json'))))
71
+
72
+ region_defaults = defaults["ubuntu 10.04"][region]
73
+ raise "Invalid Region" if region_defaults.nil?
74
+ default_ami = region_defaults[arch][root_device_type]
75
+
76
+ raise "Default AMI not found for #{region} #{flavor_id} #{root_device_type}" if default_ami.nil?
77
+ default_ami
78
+
79
+ end
80
+ end
81
+ end
@@ -1,16 +1,45 @@
1
1
  require "fileutils"
2
2
  require "json"
3
- require File.expand_path(File.join(File.dirname(__FILE__), 'aws/provision'))
4
3
 
5
4
  namespace :aws do
6
5
 
7
6
  task :provision do
8
7
  aws_config = JSON.parse(File.read("config/aws.json"))[stage] || {}
9
- AWS::Provision.new(aws_config, stage).build_env
8
+ AWS::Provision.new(stage, aws_config, application).build_env
10
9
  end
11
10
 
12
11
  task :write_config do
13
- AWS::Provision.new.describe_env_to_json("config/servers.json")
12
+ server_config = AWS::Provision.new.describe_env
13
+ File.open("config/servers.json", "w") do |io|
14
+ io << JSON.pretty_generate(server_config)
15
+ end
14
16
  end
17
+
18
+ desc "Allows ssh to instance by name. cap ssh <NAME>"
19
+ task :ssh do
20
+ server = variables[:logger].instance_variable_get("@options")[:actions][2]
21
+ instance = AWS::Provision.new(stage).find_server_by_name(server)
22
+ unless instance.nil?
23
+ port = ssh_options[:port] || 22
24
+ command = "ssh -p #{port} ubuntu@#{instance.dns_name}"
25
+ puts "Running `#{command}`"
26
+ exec(command)
27
+ else
28
+ puts "Server #{server} not found"
29
+ end
30
+ end
31
+
32
+ desc "create autoscale setup from config/autoscale.json"
33
+ task :create_autoscale do
34
+ autoscale_config = JSON.parse(File.read("config/autoscale.json"))[stage] || {}
35
+ AWS::Autoscale.new(stage, autoscale_config, application).configure_autoscale
36
+ end
37
+
38
+ desc "update autoscale from config/autoscale.json after a deployment"
39
+ task :update_autoscale do
40
+ autoscale_config = JSON.parse(File.read("config/autoscale.json"))[stage] || {}
41
+ AWS::Autoscale.new(stage, autoscale_config, application).update_autoscale
42
+ end
43
+
15
44
  end
16
45
 
@@ -31,12 +31,11 @@ module Conan
31
31
 
32
32
  def add_role(*roles)
33
33
  roles = Hash.new{ |h,k| h[k] = [] }
34
-
35
34
  server_config.each do |s, c|
36
35
  c["roles"].each do |r|
37
36
  roles[r.to_sym] << s
38
37
  end
39
- end
38
+ end unless server_config.nil?
40
39
 
41
40
  roles.each do |r, ss|
42
41
  next unless roles.include?(r)
@@ -18,7 +18,6 @@ namespace :chef do
18
18
  cache[host] ||= `ssh #{host} ifconfig`[/inet addr:(10\.\d+\.\d+\.\d+)/, 1]
19
19
  aliases[config["alias"]] = cache[host]
20
20
  end
21
-
22
21
  FileUtils.mkdir_p File.dirname(cache_path)
23
22
  File.open(cache_path, "w") do |io|
24
23
  io << JSON.dump(cache)
@@ -1,5 +1,14 @@
1
1
  require "json"
2
- set :server_config, JSON.parse(File.read("config/servers.json"))[stage] || {}
2
+
3
+ if File.exists?("config/servers.json")
4
+ set :server_config, JSON.parse(File.read("config/servers.json"))[stage] || {}
5
+ else
6
+ if File.exists?("config/aws.json")
7
+ set :server_config, AWS::Provision.new.describe_env(application)[stage]
8
+ else
9
+ set :server_config, {}
10
+ end
11
+ end
3
12
 
4
13
  add_role :app, :db
5
14
 
@@ -0,0 +1,15 @@
1
+ {
2
+ "staging": {
3
+ "launch-config": {
4
+ "lcname": {
5
+ "server_to_image": "app1",
6
+ "image_id": "ORTHIS",
7
+ "flavor_id": "c1.xlarge",
8
+ "instance_monitoring": true
9
+ "key_name": "keyname",
10
+ "autoscale_groups": [""],
11
+ "security_groups": ["default"]
12
+ }
13
+ }
14
+ }
15
+ }
@@ -99,12 +99,45 @@
99
99
  "region": "us-east-1",
100
100
  "ec2_security_groups": ["default"]
101
101
  }
102
- }
102
+ },
103
+ "elasticache": {
104
+ "default": {
105
+ "region": "us-east-1",
106
+ "ec2_security_groups": ["default"]
107
+ }
108
+ }
103
109
  },
104
110
  "s3": {
105
111
  "test": {
106
112
  "region": "us-east-1"
107
113
  }
108
- }
114
+ },
115
+ "elasticache": {
116
+ "cachename": {
117
+ "node_type": "cache.m1.large",
118
+ "num_nodes": 2,
119
+ "port": 11211,
120
+ "preferred_availablility_zone": "us-east-1b",
121
+ "security_groups": ["default"]
122
+ }
123
+ },
124
+ "cloud_watch": {
125
+ "metric_alarms": {
126
+ "alarmname": {
127
+ "region": "us-east-1",
128
+ "description": "CPU over 70%",
129
+ "comparison": "GreaterThanOrEqualToThreshold",
130
+ "evaluation_period": 1,
131
+ "metric_name": "CPUUtilization",
132
+ "namespace": "AWS/EC2",
133
+ "period": 60,
134
+ "statistic": "Average",
135
+ "threshold": 70,
136
+ "unit": "Percent",
137
+ "dimensions": {
138
+ "ec2": ["app-1"]
139
+ }
140
+ }
141
+ }
109
142
  }
110
143
  }
data/lib/conan/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Conan
2
- VERSION = "0.3.5"
2
+ VERSION = "0.4.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-02-15 00:00:00.000000000Z
13
+ date: 2012-02-27 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
17
- requirement: &70097716738400 !ruby/object:Gem::Requirement
17
+ requirement: &70281889180960 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 1.6.1
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70097716738400
25
+ version_requirements: *70281889180960
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: capistrano
28
- requirement: &70097716737480 !ruby/object:Gem::Requirement
28
+ requirement: &70281889178900 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *70097716737480
36
+ version_requirements: *70281889178900
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: fog
39
- requirement: &70097716735820 !ruby/object:Gem::Requirement
39
+ requirement: &70281889177220 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: '0'
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *70097716735820
47
+ version_requirements: *70281889177220
48
48
  description: Set up a project to enable the provision of infrastructure through AWS
49
49
  and the configuration of servers using Chef via Capistrano.
50
50
  email:
@@ -56,8 +56,11 @@ extra_rdoc_files: []
56
56
  files:
57
57
  - bin/conan
58
58
  - lib/conan/capistrano.rb
59
+ - lib/conan/cloud/aws/autoscale.rb
59
60
  - lib/conan/cloud/aws/default_amis.json
60
61
  - lib/conan/cloud/aws/provision.rb
62
+ - lib/conan/cloud/aws/security_group.rb
63
+ - lib/conan/cloud/aws/utils.rb
61
64
  - lib/conan/cloud/tasks.rb
62
65
  - lib/conan/common.rb
63
66
  - lib/conan/deployment/assets.rb
@@ -70,6 +73,7 @@ files:
70
73
  - lib/conan/smart_hash_merge.rb
71
74
  - lib/conan/template/Capfile
72
75
  - lib/conan/template/CONAN_TODO
76
+ - lib/conan/template/config/autoscale.json
73
77
  - lib/conan/template/config/aws.json
74
78
  - lib/conan/template/config/deploy.rb
75
79
  - lib/conan/template/config/servers.json