breeze 0.1.0 → 0.2.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0700bdcae3cd19bf8920aeff10db9d3d4d5eaac6
4
+ data.tar.gz: 4aea1e6bf9898e114c2ebb87cd74ba3e5e1e5a5f
5
+ SHA512:
6
+ metadata.gz: af99135461958862e35d01aa4966fe135ffbcbbc0ea7ff580aedab8016a65d1f3f9e153ca65879ccbac004fca704ca0a168a54440022b0eade90323cc38ef074
7
+ data.tar.gz: ff9683ce457c7af33c036bbb4d29aadf64bc48ac7a2007dcf89e28369f6112995b2e308a42eadba25601fbc7589836198684af718f4a04539204e784c3867cbe
@@ -0,0 +1 @@
1
+ 2.1.1
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in breeze.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -5,7 +5,8 @@ and deployments. Currently only [Amazon's AWS cloud](http://aws.amazon.com/) is
5
5
  [fog](https://github.com/geemus/fog) for the hard work so it should be fairly easy to add support for other cloud computing
6
6
  providers that are supported by fog.
7
7
 
8
- Breeze implements zero downtime deploys and rollbacks by moving an elastic ip from one server to another. Db migrations have to be
8
+ Breeze implements zero downtime deploys and rollbacks by moving an elastic ip from one server to another or by replacing
9
+ server instances behind an [elastic load balancer](http://aws.amazon.com/elasticloadbalancing). Db migrations have to be
9
10
  compatible with the previous version. http://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/
10
11
 
11
12
  ## install
@@ -50,16 +51,16 @@ These tasks call app tasks with fixed parameters.
50
51
 
51
52
  app
52
53
  ---
53
- thor app:deploy PUBLIC_SERVER_NAME DB_SERVER_NAME BRANCH # Deploy a new version by replacing old servers with new ones
54
- thor app:disable PUBLIC_SERVER_NAME # Upload system/maintenance.html to web servers
55
- thor app:enable PUBLIC_SERVER_NAME # Remove system/maintenance.html from web servers
56
- thor app:rollback PUBLIC_SERVER_NAME # Rollback a deploy
57
- thor app:start PUBLIC_SERVER_NAME [DB_SERVER_NAME] [DB_NAME] # Start a new app with web server and db
58
- thor app:stop PUBLIC_SERVER_NAME # Destroy web server and db
54
+ thor app:deploy PUBLIC_SERVER_NAME # Deploy a new version by replacing old servers with new ones
55
+ thor app:disable PUBLIC_SERVER_NAME # Upload system/maintenance.html to web servers
56
+ thor app:enable PUBLIC_SERVER_NAME # Remove system/maintenance.html from web servers
57
+ thor app:rollback PUBLIC_SERVER_NAME # Rollback a deploy
58
+ thor app:start PUBLIC_SERVER_NAME # Start a new app with web server and db
59
+ thor app:stop PUBLIC_SERVER_NAME # Destroy web server and db
59
60
 
60
61
  configuration
61
62
  -------------
62
- thor configuration:deploy_to_localhost # Transform and deploy server configuration files to the local file system based...
63
+ thor configuration:deploy_to_localhost [FILE] # Transform and deploy server configuration files to the local file system based on ERB templates in config/server
63
64
 
64
65
  db
65
66
  --
@@ -67,32 +68,47 @@ These tasks call app tasks with fixed parameters.
67
68
  thor db:create SERVER_NAME [DB_NAME] # Create a new database server
68
69
  thor db:destroy NAME # Destroy a database server
69
70
 
70
- dns
71
- ---
72
- thor dns:record:create ZONE_ID NAME TYPE IP [TTL] # Create a new DNS record
73
- thor dns:record:destroy ZONE_ID NAME [TYPE] # Destroy a DNS record
74
- thor dns:zone:create DOMAIN # Create a new DNS zone
75
- thor dns:zone:destroy ZONE_ID # Destroy a DNS zone
76
- thor dns:zone:import ZONE_ID FILE # Creates dns records specified in FILE
77
-
78
71
  describe
79
72
  --------
80
73
  thor describe:addresses # List allocated ip addresses
74
+ thor describe:cache_clusters # Describe ElastiCache clusters
81
75
  thor describe:cloud_resources # List all cloud resources that the current account can control with breeze
82
76
  thor describe:db_servers # List database servers
83
77
  thor describe:dns_records ZONE_ID # List all DNS records for the given zone
84
78
  thor describe:dns_zones # Describe DNS zones
85
79
  thor describe:images # Describe machine images owned by Breeze::CONFIGURATION[:image_owner]
80
+ thor describe:load_balancers # Describe ELB load balancers
86
81
  thor describe:servers # Describe server instances
87
82
  thor describe:volumes # Describe block store volumes (EBS)
88
83
 
84
+ dns
85
+ ---
86
+ thor dns:record:create ZONE_ID NAME TYPE IP [TTL] # Create a new DNS record
87
+ thor dns:record:destroy ZONE_ID NAME [TYPE] # Destroy a DNS record
88
+ thor dns:zone:create DOMAIN # Create a new DNS zone
89
+ thor dns:zone:destroy ZONE_ID # Destroy a DNS zone
90
+ thor dns:zone:import ZONE_ID FILE # Creates dns records specified in FILE
91
+
92
+ elasticache
93
+ -----------
94
+ thor elasticache:create CLUSTER_NAME # Create a new cache cluster
95
+ thor elasticache:destroy CLUSTER_NAME # Destroy a cache cluster
96
+
97
+ elb
98
+ ---
99
+ thor elb:add_instances LOAD_BALANCER_NAME instance_id [instance_id, ...] # Add server instances to a load balancer
100
+ thor elb:create LOAD_BALANCER_NAME [CNAME] [DNS_ZONE_ID] # Create a new elastic load balancer
101
+ thor elb:destroy LOAD_BALANCER_NAME # Destroy an elastic load balancer
102
+ thor elb:remove_instances LOAD_BALANCER_NAME instance_id [instance_id, ...] # Remove server instances from a load balancer
103
+
89
104
  server
90
105
  ------
91
106
  thor server:address:associate IP NEW_SERVER_ID # Associate an existing IP with a new server
92
107
  thor server:address:create SERVER_ID # Create and associate a new elastic ip
93
108
  thor server:address:release IP # Release the ip address
94
109
  thor server:create # Launch a new server instance
95
- thor server:destroy INSTANCE_ID # Terminate a running (or stopped) server instance
96
- thor server:image:create # Launch a server with the base image, wait for it to boot, invoke...
110
+ thor server:destroy INSTANCE_ID [...] # Terminate a running (or stopped) server instance
111
+ thor server:image:create # Launch a server with the base image, wait for it to boot, invoke prepare_private_image(ip_address), stop the server, create a new machine image as a snapshot of the root device, and destroy the server.
112
+ thor server:image:destroy IMAGE_ID [...] # Deregister the image and destroy the related volume snapshot
97
113
  thor server:tag:create SERVER_ID KEY VALUE # Create or update a tag
98
114
  thor server:tag:destroy SERVER_ID KEY # Delete a tag
@@ -35,4 +35,5 @@ system("echo 'Fog.mock!' >> #{thorfile_path}")
35
35
  Before do
36
36
  system("cp -r #{template_dir} tmp/aruba")
37
37
  @aruba_timeout_seconds = 5
38
+ @dirs = ['tmp/aruba/test_app_template']
38
39
  end
@@ -1,6 +1,6 @@
1
1
  module Breeze
2
2
 
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  autoload :Veur, 'breeze/veur'
5
5
 
6
6
  end
@@ -7,7 +7,7 @@ module Breeze
7
7
  module FogWrapper
8
8
 
9
9
  def self.connection(type)
10
- {:compute => Compute, :dns => DNS, :rds => RDS}[type].get_connection
10
+ {compute: Compute, dns: DNS, rds: RDS, elasticache: Elasticache, elb: ELB}[type].get_connection
11
11
  end
12
12
 
13
13
  def self.flush_mock_data!
@@ -79,5 +79,23 @@ module Breeze
79
79
  def mock_class ; Fog::AWS::RDS::Mock ; end
80
80
  end
81
81
 
82
+ class Elasticache < AbstractConnectionWrapper
83
+ def self.direct_fog_connection
84
+ Fog::AWS::Elasticache.new(CONFIGURATION[:cloud_service])
85
+ end
86
+ private
87
+ def data_file ; 'fog_elasticache_data.yaml' ; end
88
+ def mock_class ; Fog::AWS::Elasticache::Mock ; end
89
+ end
90
+
91
+ class ELB < AbstractConnectionWrapper
92
+ def self.direct_fog_connection
93
+ Fog::AWS::ELB.new(CONFIGURATION[:cloud_service])
94
+ end
95
+ private
96
+ def data_file ; 'fog_elb_data.yaml' ; end
97
+ def mock_class ; Fog::AWS::ELB::Mock ; end
98
+ end
99
+
82
100
  end
83
101
  end
@@ -7,4 +7,6 @@ require 'breeze/tasks/server/image'
7
7
  require 'breeze/tasks/server/tag'
8
8
  require 'breeze/tasks/dns'
9
9
  require 'breeze/tasks/db'
10
+ require 'breeze/tasks/elasticache'
11
+ require 'breeze/tasks/elb'
10
12
  require 'breeze/tasks/app'
@@ -4,42 +4,63 @@ module Breeze
4
4
 
5
5
  class App < Server
6
6
 
7
- desc 'start PUBLIC_SERVER_NAME [DB_SERVER_NAME] [DB_NAME]', 'Start a new app with web server and db'
8
- method_options :db => true, :db_to_clone => :string, :elastic_ip => true, :dns_ttl => 60, :deploy_branch => :string
9
- def start(public_server_name, db_server_name=nil, db_name=nil)
7
+ desc 'start PUBLIC_SERVER_NAME', 'Start a new app with web server and db'
8
+ method_options db: true, db_server_name: :string, db_name: :string, db_to_clone: :string,
9
+ elasticache: true, cache_cluster_name: :string,
10
+ elastic_ip: true, dns_ttl: 60,
11
+ elb_name: :string, elb_cname: true,
12
+ deploy_branch: :string
13
+ def start(public_server_name)
10
14
  if options[:db]
11
- raise 'DB_SERVER_NAME is required unless --no-db is given.' if db_server_name.nil?
15
+ raise '--db-server-name is required unless --no-db is given.' if options[:db_server_name].nil?
12
16
  if options[:db_to_clone]
13
- thor("db:clone #{options[:db_to_clone]} #{db_server_name}")
17
+ thor("db:clone #{options[:db_to_clone]} #{options[:db_server_name]}")
14
18
  else
15
- thor("db:create #{db_server_name} #{db_name}")
19
+ thor("db:create #{options[:db_server_name]} #{options[:db_name]}")
16
20
  end
17
21
  end
18
- server = create_server
19
- server.breeze_data(:name => public_server_name, :db => db_server_name)
20
- if options[:elastic_ip]
21
- thor("server:address:create #{server.id}")
22
- server.reload until server.addresses.first
22
+ if options[:elasticache]
23
+ raise '--cache-cluster-name is required unless --no-elasticache is given.' if options[:cache_cluster_name].nil?
24
+ thor("elasticache:create #{options[:cache_cluster_name]}")
25
+ end
26
+ if options[:elb_name]
27
+ create_elb_and_app_servers(public_server_name, options)
28
+ else
29
+ create_app_server_with_elastic_ip(public_server_name, options)
23
30
  end
24
- deploy_command([server], public_server_name, db_server_name, options[:deploy_branch]) if options[:deploy_branch]
25
- thor("dns:record:create #{zone_id(public_server_name)} #{public_server_name}. A #{ip(server)} #{options[:dns_ttl]}")
26
31
  end
27
32
 
28
33
  desc 'stop PUBLIC_SERVER_NAME', 'Destroy web server and db'
29
34
  method_options :force => false
30
35
  def stop(public_server_name)
31
36
  dbs_to_destroy = []
37
+ cache_clusters_to_destroy = []
38
+ elb_to_destroy = nil
32
39
  active_servers(public_server_name).each do |server|
33
40
  server.addresses.each do |address|
34
41
  thor("server:address:release #{address.public_ip}")
35
42
  end
36
- thor("dns:record:destroy #{zone_id(public_server_name)} #{public_server_name}. A")
37
43
  dbs_to_destroy << server.breeze_data['db']
44
+ cache_clusters_to_destroy << server.breeze_data['cache']
45
+ elb_to_destroy ||= server.breeze_data['elb']
38
46
  thor("server:destroy #{server.id}")
39
47
  end
40
48
  dbs_to_destroy.uniq.compact.each do |db_name|
41
49
  thor("db:destroy #{db_name}")
42
50
  end
51
+ cache_clusters_to_destroy.uniq.compact.each do |cache_cluster_name|
52
+ thor("elasticache:destroy #{cache_cluster_name}")
53
+ end
54
+ if elb_to_destroy
55
+ elb_cname_record = find_zone_recursively(public_server_name).records.detect{ |r| r.name == "#{public_server_name}." and r.type == 'CNAME' }
56
+ if elb_cname_record
57
+ thor("elb:destroy #{elb_to_destroy} #{public_server_name} #{zone_id(public_server_name)}")
58
+ else
59
+ thor("elb:destroy #{elb_to_destroy}")
60
+ end
61
+ else
62
+ thor("dns:record:destroy #{zone_id(public_server_name)} #{public_server_name}. A")
63
+ end
43
64
  end
44
65
 
45
66
  desc 'disable PUBLIC_SERVER_NAME', 'Upload system/maintenance.html to web servers'
@@ -52,12 +73,63 @@ module Breeze
52
73
  on_each_server(enable_app_command, public_server_name)
53
74
  end
54
75
 
55
- desc 'deploy PUBLIC_SERVER_NAME DB_SERVER_NAME BRANCH', 'Deploy a new version by replacing old servers with new ones'
56
- def deploy(public_server_name, db_server_name, branch)
76
+ desc 'deploy PUBLIC_SERVER_NAME', 'Deploy a new version by replacing old servers with new ones'
77
+ method_options db_server_name: :string, cache_cluster_name: :string, elb_name: :string, deploy_branch: :string
78
+ def deploy(public_server_name)
79
+ if options[:elb_name]
80
+ deploy_with_elb(public_server_name, options)
81
+ else
82
+ deploy_with_elastic_ip(public_server_name, options)
83
+ end
84
+ end
85
+
86
+ desc 'rollback PUBLIC_SERVER_NAME', 'Rollback a deploy'
87
+ method_options elb_name: :string
88
+ def rollback(public_server_name)
89
+ old_servers = spare_servers(public_server_name)
90
+ raise "no running spare server found for #{public_server_name}" if old_servers.size == 0
91
+ old_servers.each do |old_server|
92
+ unless ip(old_server) # the ip may be temporarily unknown if the old elastic ip has been moved to another instance
93
+ wait_until { old_server.reload; ip(old_server) }
94
+ end
95
+ remote('sudo shutdown -c', :host => ip(old_server))
96
+ end
97
+ new_servers = active_servers(public_server_name)
98
+ new_servers.each do |new_server|
99
+ remote(disable_app_command, :host => ip(new_server))
100
+ end
101
+ if options[:elb_name]
102
+ thor("elb:add_instances #{options[:elb_name]} #{old_servers.map(&:id).join(' ')}")
103
+ thor("elb:remove_instances #{options[:elb_name]} #{new_servers.map(&:id).join(' ')}")
104
+ else
105
+ move_addresses(new_servers.first, old_servers.first)
106
+ end
107
+ old_servers.each { |s| s.breeze_state('reactivated') }
108
+ new_servers.each { |s| s.breeze_state('abandoned_due_to_rollback') }
109
+ if accept?("Ready to destroy the abandoned #{new_servers.size} server(s) now?")
110
+ new_servers.each { |s| s.destroy }
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def deploy_with_elb(public_server_name, options)
117
+ old_servers = active_servers(public_server_name)
118
+ create_app_servers_for_elb(public_server_name, options)
119
+ if accept?("Continue and remove the old servers from the ELB?")
120
+ thor("elb:remove_instances #{options[:elb_name]} #{old_servers.map(&:id).join(' ')}")
121
+ old_servers.each do |old_server|
122
+ remote("nohup sudo shutdown -h +#{CONFIGURATION[:rollback_window]} > /dev/null 2>&1 &", :host => ip(old_server))
123
+ old_server.spare_for_rollback!
124
+ end
125
+ end
126
+ end
127
+
128
+ def deploy_with_elastic_ip(public_server_name, options)
57
129
  old_server = active_servers(public_server_name).first
58
130
  new_server = create_server
59
- new_server.breeze_data(:name => public_server_name, :db => db_server_name)
60
- deploy_command([new_server], public_server_name, db_server_name, branch)
131
+ new_server.breeze_data(name: public_server_name, db: options[:db_server_name], cache: options[:cache_cluster_name])
132
+ deploy_command([new_server], public_server_name, options)
61
133
  puts("The new server should soon be available at: #{ip(new_server)}")
62
134
  if ask("Ready to continue and move the elastic_ip for #{public_server_name} to the new server? [YES/rollback] >") =~ /r|n/i
63
135
  new_server.destroy
@@ -72,31 +144,48 @@ module Breeze
72
144
  end
73
145
  end
74
146
 
75
- desc 'rollback PUBLIC_SERVER_NAME', 'Rollback a deploy'
76
- def rollback(public_server_name)
77
- old_server = spare_servers(public_server_name).first
78
- raise "no running spare server found for #{public_server_name}" unless old_server
79
- if ip(old_server)
80
- temp_ip = nil
147
+ def create_elb_and_app_servers(public_server_name, options)
148
+ if options[:elb_cname]
149
+ thor("elb:create #{options[:elb_name]} #{public_server_name} #{zone_id(public_server_name)}")
81
150
  else
82
- puts("Old server does not have a public ip. Allocating a temporary address:")
83
- thor("server:address:create #{old_server.id}")
84
- old_server.reload until old_server.addresses.first
85
- temp_ip = ip(old_server)
86
- end
87
- remote('sudo shutdown -c', :host => ip(old_server))
88
- new_server = active_servers(public_server_name).first
89
- remote(disable_app_command, :host => ip(new_server))
90
- thor("server:address:release #{temp_ip} --force") if temp_ip
91
- move_addresses(new_server, old_server)
92
- old_server.breeze_state('reactivated')
93
- new_server.breeze_state('abandoned_due_to_rollback')
94
- if accept?('Ready to destroy the abandoned server now?')
95
- new_server.destroy
151
+ thor("elb:create #{options[:elb_name]}")
96
152
  end
153
+ create_app_servers_for_elb(public_server_name, options.merge(force: true))
97
154
  end
98
155
 
99
- private
156
+ def create_app_servers_for_elb(public_server_name, options)
157
+ servers = []
158
+ CONFIGURATION[:elb][:instances].each do |instance_conf|
159
+ instance_conf = instance_conf.dup
160
+ instance_conf.delete(:count).times do
161
+ servers << create_server(CONFIGURATION[:default_server_options].merge(instance_conf))
162
+ set_server_tags(servers.last, public_server_name, options)
163
+ end
164
+ end
165
+ deploy_command(servers, public_server_name, options)
166
+ servers.each do |server|
167
+ if force_or_accept?("Ready to add #{ip(server)} to ELB #{options[:elb_name]}?")
168
+ thor("elb:add_instances #{options[:elb_name]} #{server.id}")
169
+ else
170
+ server.destroy
171
+ end
172
+ end
173
+ end
174
+
175
+ def create_app_server_with_elastic_ip(public_server_name, options)
176
+ server = create_server
177
+ set_server_tags(server, public_server_name, options)
178
+ if options[:elastic_ip]
179
+ thor("server:address:create #{server.id}")
180
+ server.reload until server.addresses.first
181
+ end
182
+ deploy_command([server], public_server_name, options)
183
+ thor("dns:record:create #{zone_id(public_server_name)} #{public_server_name}. A #{ip(server)} #{options[:dns_ttl]}")
184
+ end
185
+
186
+ def set_server_tags(server, public_server_name, options)
187
+ server.breeze_data(name: public_server_name, db: options[:db_server_name], cache: options[:cache_cluster_name], elb: options[:elb_name])
188
+ end
100
189
 
101
190
  def move_addresses(from_server, to_server)
102
191
  from_server.addresses.each do |address|
@@ -170,11 +259,19 @@ module Breeze
170
259
  c.class_eval <<-END_TASKS
171
260
  desc 'deploy', 'Deploy a new version by replacing old servers with new ones'
172
261
  def deploy
173
- thor("app:deploy \#{PUBLIC_SERVER_NAME} \#{DB_SERVER_NAME} \#{BRANCH}")
262
+ if defined?(ELB_NAME)
263
+ thor("app:deploy \#{PUBLIC_SERVER_NAME} --db-server-name=\#{DB_SERVER_NAME} --cache-cluster-name=\#{CACHE_CLUSTER_NAME} --elb-name=\#{ELB_NAME} --deploy-branch=\#{BRANCH}")
264
+ else
265
+ thor("app:deploy \#{PUBLIC_SERVER_NAME} --db-server-name=\#{DB_SERVER_NAME} --cache-cluster-name=\#{CACHE_CLUSTER_NAME} --deploy-branch=\#{BRANCH}")
266
+ end
174
267
  end
175
268
  desc 'rollback', 'Rollback the previous deploy'
176
269
  def rollback
177
- thor("app:rollback \#{PUBLIC_SERVER_NAME}")
270
+ if defined?(ELB_NAME)
271
+ thor("app:rollback \#{PUBLIC_SERVER_NAME} --elb-name=\#{ELB_NAME}")
272
+ else
273
+ thor("app:rollback \#{PUBLIC_SERVER_NAME}")
274
+ end
178
275
  end
179
276
  desc 'disable', 'Copy maintenance.html to public/system/ on active web servers'
180
277
  def disable
@@ -184,9 +281,10 @@ module Breeze
184
281
  def enable
185
282
  thor("app:enable \#{PUBLIC_SERVER_NAME}")
186
283
  end
187
- desc 'ssh', 'Log in with ssh'
188
- def ssh
189
- log_in_to(PUBLIC_SERVER_NAME)
284
+ desc 'ssh [INSTANCE_ID]', 'Log in with ssh'
285
+ def ssh(instance_id=nil)
286
+ server = (instance_id ? fog.servers.get(instance_id) : active_servers(PUBLIC_SERVER_NAME)[0])
287
+ log_in_to(server.public_ip_address)
190
288
  end
191
289
  END_TASKS
192
290
  end
@@ -12,6 +12,8 @@ module Breeze
12
12
  volumes
13
13
  db_servers
14
14
  dns_zones
15
+ cache_clusters
16
+ load_balancers
15
17
  end
16
18
 
17
19
  desc :images, 'Describe machine images owned by Breeze::CONFIGURATION[:image_owner]'
@@ -72,5 +74,20 @@ module Breeze
72
74
  zone.records.map{ |r| [r.name, r.type, r.ttl, r.ip.join(', ')] }
73
75
  end
74
76
 
77
+ desc :cache_clusters, 'Describe ElastiCache clusters'
78
+ def cache_clusters
79
+ report 'CACHE CLUSTERS',
80
+ ['Name', 'Type', 'Engine', 'Nodes', 'Status'],
81
+ elasticache.clusters.map{ |c| [c.id, c.node_type, c.engine, c.num_nodes, c.status] }
82
+ # c.nodes[0]['Address']
83
+ end
84
+
85
+ desc :load_balancers, 'Describe ELB load balancers'
86
+ def load_balancers
87
+ report 'ELASTIC LOAD BALANCERS',
88
+ ['Name', 'DNS name', 'Availability zones', 'Instances'],
89
+ elb.load_balancers.map{ |lb| [lb.id, lb.dns_name, lb.availability_zones.join(', '), lb.instances.join(', ')] }
90
+ end
91
+
75
92
  end
76
93
  end
@@ -0,0 +1,24 @@
1
+ module Breeze
2
+
3
+ class Elasticache < Veur
4
+
5
+ desc 'create CLUSTER_NAME', 'Create a new cache cluster'
6
+ method_options CONFIGURATION[:default_elasticache_options]
7
+ def create(name)
8
+ options.update(:id => name)
9
+ # puts "elasticache options: #{options}"
10
+ elasticache.clusters.create(options)
11
+ end
12
+
13
+ desc 'destroy CLUSTER_NAME', 'Destroy a cache cluster'
14
+ method_options :force => false
15
+ def destroy(name)
16
+ cluster = elasticache.clusters.get(name)
17
+ if force_or_accept?("Destroy cache cluster #{name}?")
18
+ cluster.destroy
19
+ cluster.reload
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ module Breeze
2
+
3
+ class Elb < Veur
4
+
5
+ desc 'create LOAD_BALANCER_NAME [CNAME] [DNS_ZONE_ID]', 'Create a new elastic load balancer'
6
+ method_options :dns_ttl => 60
7
+ def create(name, cname=nil, dns_zone_id=nil)
8
+ conf = CONFIGURATION[:elb]
9
+ response = elb.create_load_balancer(conf[:instances].map{ |i| i[:availability_zone] }.uniq, name, conf[:listeners])
10
+ if cname
11
+ thor("dns:record:create #{dns_zone_id} #{cname}. CNAME #{response.body['CreateLoadBalancerResult']['DNSName']} #{options[:dns_ttl]}")
12
+ end
13
+ elb.configure_health_check(name, conf[:health_check])
14
+ end
15
+
16
+ desc 'add_instances LOAD_BALANCER_NAME instance_id [instance_id, ...]', 'Add server instances to a load balancer'
17
+ def add_instances(name, *instance_ids)
18
+ elb.register_instances(instance_ids, name)
19
+ end
20
+
21
+ desc 'remove_instances LOAD_BALANCER_NAME instance_id [instance_id, ...]', 'Remove server instances from a load balancer'
22
+ def remove_instances(name, *instance_ids)
23
+ elb.deregister_instances(instance_ids, name)
24
+ end
25
+
26
+ desc 'destroy LOAD_BALANCER_NAME', 'Destroy an elastic load balancer'
27
+ method_options :force => false
28
+ def destroy(name, cname=nil, dns_zone_id=nil)
29
+ load_balancer = elb.load_balancers.get(name)
30
+ if force_or_accept?("Destroy load balancer #{name}?")
31
+ load_balancer.destroy
32
+ if cname
33
+ thor("dns:record:destroy #{dns_zone_id} #{cname}. CNAME --force")
34
+ end
35
+ load_balancer.reload
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -86,5 +86,13 @@ module Breeze
86
86
  @rds ||= Breeze::FogWrapper.connection(:rds)
87
87
  end
88
88
 
89
+ def elasticache
90
+ @elasticache ||= Breeze::FogWrapper.connection(:elasticache)
91
+ end
92
+
93
+ def elb
94
+ @elb ||= Breeze::FogWrapper.connection(:elb)
95
+ end
96
+
89
97
  end
90
98
  end
@@ -54,6 +54,45 @@ Breeze::CONFIGURATION = {
54
54
  :password => 'admin'
55
55
  },
56
56
 
57
+ # elasticache configuration is required in order to use Amazon ElastiCache
58
+ :default_elasticache_options => {
59
+ :node_type => 'cache.t1.micro',
60
+ :security_group_names => '',
61
+ :num_nodes => 1,
62
+ :auto_minor_version_upgrade => true,
63
+ :engine => 'memcached',
64
+ :engine_version => '',
65
+ :port => '',
66
+ :preferred_availablility_zone => ''
67
+ },
68
+
69
+ # ELB configuration is required in order to use Amazon Elastic Load Balancing
70
+ :elb => {
71
+ :instances => [
72
+ {availability_zone: 'us-east-1a', flavor_id: 't1.micro', count: 1},
73
+ {availability_zone: 'us-east-1d', flavor_id: 't1.micro', count: 1}
74
+ ],
75
+ :listeners => [{
76
+ 'Protocol' => 'HTTP',
77
+ 'LoadBalancerPort' => 80,
78
+ 'InstancePort' => 80,
79
+ 'InstanceProtocol' => 'HTTP'
80
+ }, {
81
+ 'Protocol' => 'HTTPS',
82
+ 'LoadBalancerPort' => 443,
83
+ 'InstancePort' => 80,
84
+ 'InstanceProtocol' => 'HTTP',
85
+ 'SSLCertificateId' => 'arn:aws:iam::....'
86
+ }],
87
+ :health_check => {
88
+ 'Target' => 'HTTP:80/ping',
89
+ 'Interval' => 20,
90
+ 'Timeout' => 4,
91
+ 'HealthyThreshold' => 3,
92
+ 'UnhealthyThreshold' => 2
93
+ }
94
+ },
95
+
57
96
  # you can add your own keys and access this hash as CONFIGURATION in the erb templates
58
97
  :admin_email => 'YOUR-EMAIL',
59
98
  :app_path => '/srv/YOUR-APP'
metadata CHANGED
@@ -1,89 +1,75 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breeze
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Markus Bengts
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-10-28 00:00:00.000000000 Z
11
+ date: 2014-03-22 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: thor
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: fog
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: cucumber
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: aruba
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
- description: ! 'Breeze makes it easy to automate server installation and configuration.
79
- It provides
80
-
69
+ description: |
70
+ Breeze makes it easy to automate server installation and configuration. It provides
81
71
  example scripts and configuration files that you can modify and keep in your revision
82
-
83
- control system. Thor tasks are provided to create server images, launch server instances
84
- etc.
85
-
86
- '
72
+ control system. Thor tasks are provided to create server images, launch server instances etc.
87
73
  email:
88
74
  - markus.bengts@gmail.com
89
75
  executables:
@@ -91,8 +77,8 @@ executables:
91
77
  extensions: []
92
78
  extra_rdoc_files: []
93
79
  files:
94
- - .gitignore
95
- - .rbenv-version
80
+ - ".gitignore"
81
+ - ".ruby-version"
96
82
  - Gemfile
97
83
  - LICENSE
98
84
  - README.md
@@ -117,6 +103,8 @@ files:
117
103
  - lib/breeze/tasks/db.rb
118
104
  - lib/breeze/tasks/describe.rb
119
105
  - lib/breeze/tasks/dns.rb
106
+ - lib/breeze/tasks/elasticache.rb
107
+ - lib/breeze/tasks/elb.rb
120
108
  - lib/breeze/tasks/server.rb
121
109
  - lib/breeze/tasks/server/address.rb
122
110
  - lib/breeze/tasks/server/image.rb
@@ -141,33 +129,26 @@ files:
141
129
  - lib/templates/user_data.sh
142
130
  homepage: https://github.com/markus/breeze
143
131
  licenses: []
132
+ metadata: {}
144
133
  post_install_message:
145
134
  rdoc_options: []
146
135
  require_paths:
147
136
  - lib
148
137
  required_ruby_version: !ruby/object:Gem::Requirement
149
- none: false
150
138
  requirements:
151
- - - ! '>='
139
+ - - ">="
152
140
  - !ruby/object:Gem::Version
153
141
  version: '0'
154
- segments:
155
- - 0
156
- hash: 4461246332485121240
157
142
  required_rubygems_version: !ruby/object:Gem::Requirement
158
- none: false
159
143
  requirements:
160
- - - ! '>='
144
+ - - ">="
161
145
  - !ruby/object:Gem::Version
162
146
  version: '0'
163
- segments:
164
- - 0
165
- hash: 4461246332485121240
166
147
  requirements: []
167
148
  rubyforge_project: breeze
168
- rubygems_version: 1.8.23
149
+ rubygems_version: 2.2.2
169
150
  signing_key:
170
- specification_version: 3
151
+ specification_version: 4
171
152
  summary: Thor tasks to manage cloud computing resources and deployments
172
153
  test_files:
173
154
  - features/dns.feature
@@ -1 +0,0 @@
1
- 1.9.3-p286