breeze 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,4 +1,92 @@
1
1
  # breeze
2
2
 
3
3
  Breeze provides some [Thor](https://github.com/wycats/thor) tasks and example scripts for managing cloud computing resources
4
- on [Amazon's AWS cloud](http://aws.amazon.com/).
4
+ and deployments on [Amazon's AWS cloud](http://aws.amazon.com/). It uses [fog](https://github.com/geemus/fog) for the hard
5
+ work so it should be fairly easy to add support for other cloud computing providers that are supported by fog.
6
+
7
+ Breeze implements zero downtime deployments by moving an elastic ip from one server to another. Db migrations have to be
8
+ compatible with the previous version.
9
+
10
+ ## install
11
+
12
+ gem install breeze
13
+ cd your-project
14
+ breeze init
15
+
16
+ Then edit Thorfile and the stuff that got copied to config/breeze.
17
+
18
+ Management of configuration files is almost compatible with [rubber](https://github.com/wr0ngway/rubber)
19
+ but breeze does not support roles and additives. See [the rubber wiki](https://github.com/wr0ngway/rubber/wiki/Configuration)
20
+ for more information.
21
+
22
+ ## create a server image
23
+
24
+ thor server:image:create
25
+
26
+ The default install.sh compiles ruby, passenger, nginx and image magick. It takes a long time
27
+ (maybe half an hour on a small instance). It will prompt for the image name when completed.
28
+
29
+ ## use it
30
+
31
+ thor describe # List all cloud resources that the current account can control with breeze
32
+
33
+ thor staging:deploy # Deploy a new version by replacing old servers with new ones
34
+ thor staging:disable # Copy maintenance.html to public/system/ on active web servers
35
+ thor staging:enable # Remove system/maintenance.html from active web servers
36
+ thor staging:rollback # Rollback the previous deploy
37
+ thor staging:start # Start web server and db for staging
38
+ thor staging:stop # Stop staging and destroy server and db
39
+
40
+ Define your staging and production in the Thorfile and the same tasks become available for both name spaces.
41
+ These tasks call app tasks with fixed parameters.
42
+
43
+ ## plumbing commands
44
+
45
+ app
46
+ ---
47
+ thor app:deploy PUBLIC_SERVER_NAME DB_SERVER_NAME BRANCH # Deploy a new version by replacing old servers with new ones
48
+ thor app:disable PUBLIC_SERVER_NAME # Upload system/maintenance.html to web servers
49
+ thor app:enable PUBLIC_SERVER_NAME # Remove system/maintenance.html from web servers
50
+ thor app:rollback PUBLIC_SERVER_NAME # Rollback a deploy
51
+ thor app:start PUBLIC_SERVER_NAME [DB_SERVER_NAME] [DB_NAME] # Start a new app with web server and db
52
+ thor app:stop PUBLIC_SERVER_NAME # Destroy web server and db
53
+
54
+ configuration
55
+ -------------
56
+ thor configuration:deploy_to_localhost # Transform and deploy server configuration files to the local file system based on...
57
+
58
+ db
59
+ --
60
+ thor db:clone OLD_DB NEW_DB # Create a new db server using the latest backup of OLD_DB.
61
+ thor db:create SERVER_NAME [DB_NAME] # Create a new database server
62
+ thor db:destroy NAME # Destroy a database server
63
+
64
+ dns
65
+ ---
66
+ thor dns:record:create ZONE_ID NAME TYPE IP [TTL] # Create a new DNS record
67
+ thor dns:record:destroy ZONE_ID NAME [TYPE] # Destroy a DNS record
68
+ thor dns:zone:create DOMAIN # Create a new DNS zone
69
+ thor dns:zone:destroy ZONE_ID # Destroy a DNS zone
70
+ thor dns:zone:import ZONE_ID FILE # Creates dns records specified in FILE
71
+
72
+ describe
73
+ --------
74
+ thor describe:addresses # List allocated ip addresses
75
+ thor describe:cloud_resources # List all cloud resources that the current account can control with breeze
76
+ thor describe:db_servers # List database servers
77
+ thor describe:dns_records ZONE_ID # List all DNS records for the given zone
78
+ thor describe:dns_zones # Describe DNS zones
79
+ thor describe:images # Describe machine images owned by Breeze::CONFIGURATION[:image_owner]
80
+ thor describe:servers # Describe server instances
81
+ thor describe:volumes # Describe block store volumes (EBS)
82
+
83
+ server
84
+ ------
85
+ thor server:address:associate IP NEW_SERVER_ID # Associate an existing IP with a new server
86
+ thor server:address:create SERVER_ID # Create and associate a new elastic ip
87
+ thor server:address:release IP # Release the ip address
88
+ thor server:create # Launch a new server instance
89
+ thor server:destroy INSTANCE_ID # Terminate a running (or stopped) server instance
90
+ thor server:image:create # Launch a server with the base image, wait for it to boot, invoke...
91
+ thor server:tag:create SERVER_ID KEY VALUE # Create or update a tag
92
+ thor server:tag:destroy SERVER_ID KEY # Delete a tag
@@ -1,6 +1,6 @@
1
1
  module Breeze
2
2
 
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  autoload :Veur, 'breeze/veur'
5
5
 
6
6
  end
@@ -1,6 +1,6 @@
1
1
  require 'breeze'
2
2
  require 'breeze/tasks/configuration'
3
- require 'breeze/tasks/list'
3
+ require 'breeze/tasks/describe'
4
4
  require 'breeze/tasks/server'
5
5
  require 'breeze/tasks/server/address'
6
6
  require 'breeze/tasks/server/image'
@@ -57,24 +57,34 @@ module Breeze
57
57
  deploy_command([new_server], public_server_name, db_server_name, branch)
58
58
  puts("The new server should soon be available at #{ip(new_server)}.")
59
59
  if ask("Ready to continue and move the elastic_ip for #{public_server_name} to the new server? [YES/rollback] >") =~ /r|n/i
60
- remote("sudo shutdown -h +#{CONFIGURATION[:rollback_window]}", :host => ip(old_server))
60
+ new_server.destroy
61
+ else
62
+ remote("sudo shutdown -h +#{CONFIGURATION[:rollback_window]} &", :host => ip(old_server))
61
63
  old_server.spare_for_rollback!
62
64
  move_addresses(old_server, new_server)
63
- else
64
- new_server.destroy
65
65
  end
66
66
  end
67
67
 
68
68
  desc 'rollback PUBLIC_SERVER_NAME', 'Rollback a deploy'
69
69
  def rollback(public_server_name)
70
70
  old_server = spare_servers(public_server_name).first
71
+ raise "no running spare server found for #{public_server_name}" unless old_server
72
+ if ip(old_server)
73
+ temp_ip = nil
74
+ else
75
+ puts("Old server does not have a public ip. Allocating a temporary address:")
76
+ thor("server:address:create #{old_server.id}")
77
+ old_server.reload until old_server.addresses.first
78
+ temp_ip = ip(old_server)
79
+ end
71
80
  remote('sudo shutdown -c', :host => ip(old_server))
72
81
  new_server = active_servers(public_server_name).first
73
82
  remote(disable_app_command, :host => ip(new_server))
83
+ thor("server:address:release #{temp_ip}") if temp_ip
74
84
  move_addresses(new_server, old_server)
75
85
  old_server.breeze_state('reactivated')
76
86
  new_server.breeze_state('abandoned_due_to_rollback')
77
- if accept?('Destroy the abandoned server NOW?')
87
+ if accept?('Ready to destroy the abandoned server now?')
78
88
  new_server.destroy
79
89
  end
80
90
  end
@@ -87,16 +97,16 @@ module Breeze
87
97
  end
88
98
  end
89
99
 
90
- def servers(public_server_name)
91
- fog.servers.select{ |s| s.name == public_server_name }
100
+ def running_servers(public_server_name)
101
+ fog.servers.select{ |s| s.ready? and s.name == public_server_name }
92
102
  end
93
103
 
94
104
  def spare_servers(public_server_name)
95
- servers(public_server_name).select{ |s| s.spare_for_rollback? }
105
+ running_servers(public_server_name).select{ |s| s.spare_for_rollback? }
96
106
  end
97
107
 
98
108
  def active_servers(public_server_name)
99
- servers(public_server_name).select{ |s| ! s.spare_for_rollback? }
109
+ running_servers(public_server_name).select{ |s| not s.spare_for_rollback? }
100
110
  end
101
111
 
102
112
  def on_each_server(command, public_server_name)
@@ -106,7 +116,7 @@ module Breeze
106
116
  end
107
117
 
108
118
  def disable_app_command
109
- "cd #{CONFIGURATION[:app_path]} && cp config/breeze/maintenance.html public/system/"
119
+ "cd #{CONFIGURATION[:app_path]} && mkdir -p public/system && cp config/breeze/maintenance.html public/system/"
110
120
  end
111
121
 
112
122
  def enable_app_command
@@ -141,5 +151,28 @@ module Breeze
141
151
  super(task + (options[:force] ? ' --force' : ''))
142
152
  end
143
153
 
154
+ # Don't know how to include or inherit thor tasks and descriptions.
155
+ # These may be included in Staging and Production.
156
+ def self.inherited(c)
157
+ c.class_eval <<-END_TASKS
158
+ desc 'deploy', 'Deploy a new version by replacing old servers with new ones'
159
+ def deploy
160
+ thor("app:deploy \#{PUBLIC_SERVER_NAME} \#{DB_SERVER_NAME} \#{BRANCH}")
161
+ end
162
+ desc 'rollback', 'Rollback the previous deploy'
163
+ def rollback
164
+ thor("app:rollback \#{PUBLIC_SERVER_NAME}")
165
+ end
166
+ desc 'disable', 'Copy maintenance.html to public/system/ on active web servers'
167
+ def disable
168
+ thor("app:disable \#{PUBLIC_SERVER_NAME}")
169
+ end
170
+ desc 'enable', 'Remove system/maintenance.html from active web servers'
171
+ def enable
172
+ thor("app:enable \#{PUBLIC_SERVER_NAME}")
173
+ end
174
+ END_TASKS
175
+ end
176
+
144
177
  end
145
178
  end
@@ -1,6 +1,8 @@
1
1
  module Breeze
2
2
 
3
- class List < Veur
3
+ class Describe < Veur
4
+
5
+ default_task :cloud_resources
4
6
 
5
7
  desc :cloud_resources, 'List all cloud resources that the current account can control with breeze'
6
8
  def cloud_resources
@@ -24,9 +26,9 @@ module Breeze
24
26
  desc :servers, 'Describe server instances'
25
27
  def servers
26
28
  report "SERVER INSTANCES",
27
- ['Name', 'Instance ID', 'IP Address', 'Image ID', 'Instance Type', 'Availability Zone', 'State'],
29
+ ['Name', 'Instance ID', 'IP Address', 'Image ID', 'Type', 'Zone', 'State', 'Info'],
28
30
  fog.servers.map { |i|
29
- [i.name, i.id, i.public_ip_address, i.image_id, i.flavor_id, i.availability_zone, i.state]
31
+ [i.name, i.id, i.public_ip_address, i.image_id, i.flavor_id, i.availability_zone, i.state, i.breeze_state]
30
32
  }
31
33
  end
32
34
 
@@ -45,7 +45,7 @@ module Breeze
45
45
  end
46
46
 
47
47
  def remote_is_available?(host)
48
- execute(:remote_command, :command => 'exit', :host => host)
48
+ execute(:remote_available?, :host => host)
49
49
  end
50
50
 
51
51
  def remote(command, args)
@@ -8,19 +8,24 @@ module Breeze
8
8
  'stop the server, create a new machine image as a snapshot of the root device, and destroy the server.'
9
9
  method_options CONFIGURATION[:default_server_options].merge(CONFIGURATION[:create_image_options])
10
10
  def create
11
- options[:block_device_mapping] = [{:device_name => '/dev/sda1', :ebs_volume_size => options.delete(:root_device_size)}]
11
+ # The commented lines used to work before fog 0.7.0.
12
+ # options[:block_device_mapping] = [{:device_name => '/dev/sda1', :ebs_volume_size => options.delete(:root_device_size)}]
13
+ options[:block_device_mapping] = [{'DeviceName' => '/dev/sda1', 'Ebs.VolumeSize' => options.delete(:root_device_size)}]
12
14
  server = create_server(options)
13
15
  prepare_private_image(server.public_ip_address)
14
16
  print('Stopping the server before saving a snapshot')
15
17
  server.stop
16
18
  wait_until('stopped!') { server.stopped? }
17
- thor('list:images')
18
- image = fog.images.create(:name => ask('Image name >'), :instance_id => server.id)
19
+ thor('describe:images')
20
+ puts('===== Old server images are listed above. Give a name to the new image. =====')
21
+ # image = fog.images.create(:name => ask('Image name >'), :instance_id => server.id)
22
+ fog.create_image(server.id, ask('Image name >'), '')
19
23
  server.destroy
20
24
  puts
21
- puts("===> Created image #{image.id} and terminated temporary server #{server.id}.")
25
+ # puts("===> Created image #{image.id} and terminated temporary server #{server.id}.")
26
+ puts("===> Created a new server image and terminated temporary server #{server.id}.")
22
27
  puts
23
- puts("NOTICE: it may take a while before the new image shows up in list:images")
28
+ puts("NOTICE: it may take a while before the new image shows up in describe:images")
24
29
  end
25
30
 
26
31
  end
@@ -16,6 +16,7 @@ Breeze::CONFIGURATION = {
16
16
  # Remote and upload commands are required in order to create a server image or deploy
17
17
  # an application. Arguments marked with %{} are automatically replaced when the
18
18
  # commands are used. Use "ssh -i /path/to/key" if not using your default ssh key.
19
+ :remote_available? => 'ssh -q ubuntu@%{host} exit',
19
20
  :remote_command => "ssh ubuntu@%{host} '%{command}'",
20
21
  :upload_command => 'rsync -v %{file_pattern} ubuntu@%{host}:%{remote_path}',
21
22
 
@@ -38,7 +39,7 @@ Breeze::CONFIGURATION = {
38
39
  :root_device_size => 15 # in GB
39
40
  },
40
41
 
41
- # machine images owned by this account are included in list:images (provided that you have access to them)
42
+ # machine images owned by this account are included in describe:images (provided that you have access to them)
42
43
  :image_owner => 'YOUR-ACCOUNT-ID-WITHOUT-DASHES', # canonical: '099720109477'
43
44
 
44
45
  # db configuration is required in order to use Amazon RDS
@@ -66,10 +67,10 @@ Breeze::CONFIGURATION = {
66
67
  # with the "thor help" command.
67
68
  require 'breeze/tasks'
68
69
 
70
+ # prepare_private_image is called from server:image:create. Modify this and/or the scripts
71
+ # that are uploaded in order to create your own private machine image.
69
72
  class Breeze::Server::Image
70
73
  private
71
- # This method is called from server:image:create. Modify this and/or the scripts that
72
- # are uploaded in order to create your own private machine image.
73
74
  def prepare_private_image(ip_address)
74
75
  wait_until_host_is_available(ip_address)
75
76
  puts("Uploading scripts...")
@@ -78,8 +79,7 @@ class Breeze::Server::Image
78
79
  end
79
80
  end
80
81
 
81
- # You can define staging:start etc. with fixed parameters below.
82
-
82
+ # deploy_command is called from app:start and app:deploy.
83
83
  class Breeze::App
84
84
  private
85
85
  def deploy_command(servers, public_server_name, db_server_name, branch)
@@ -90,15 +90,18 @@ class Breeze::App
90
90
  end
91
91
  end
92
92
 
93
- # thor staging:start and staging:stop
93
+ # Define staging:start etc. below. The constants are also needed by
94
+ # inherited tasks: deploy, rollback, enable and disable.
95
+
94
96
  class Staging < Breeze::App
95
97
 
96
98
  PUBLIC_SERVER_NAME = 'staging.example.com'
97
99
  DB_SERVER_NAME = 'staging-db'
100
+ BRANCH = 'master'
98
101
 
99
102
  desc 'start', 'Start web server and db for staging'
100
103
  def start
101
- thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} --db-to-clone=#{Production::DB_SERVER_NAME} --deploy-branch=master")
104
+ thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} --db-to-clone=#{Production::DB_SERVER_NAME} --deploy-branch=#{BRANCH}")
102
105
  end
103
106
 
104
107
  desc 'stop', 'Stop staging and destroy server and db'
@@ -108,15 +111,15 @@ class Staging < Breeze::App
108
111
 
109
112
  end
110
113
 
111
- # thor production:start
112
114
  class Production < Breeze::App
113
115
 
114
- PUBLIC_SERVER_NAME = 'production.example.com'
116
+ PUBLIC_SERVER_NAME = 'www.example.com'
115
117
  DB_SERVER_NAME = 'production-db'
118
+ BRANCH = 'stable'
116
119
 
117
120
  desc 'start', 'Start web server and db for production'
118
121
  def start
119
- thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} crags --dns-ttl=300 --deploy-branch=stable")
122
+ thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} db_name --dns-ttl=300 --deploy-branch=#{BRANCH}")
120
123
  end
121
124
 
122
125
  end
@@ -3,7 +3,7 @@
3
3
  @owner = 'rails'
4
4
  @group = 'rails'
5
5
  @perms = 0640
6
- @post = 'rake db:migrate'
6
+ @post = 'rake db:migrate RAILS_ENV=production'
7
7
 
8
8
  conf = CONFIGURATION[:default_db_options]
9
9
  %>
@@ -5,9 +5,9 @@
5
5
  system("mkdir -p #{dir} && chown www-data #{dir}") unless File.directory?(dir)
6
6
  end
7
7
 
8
- passenger_version = "3.0.2"
8
+ passenger_version = "3.0.5"
9
9
  server_name = ENV['PUBLIC_SERVER_NAME']
10
- server_root = "/srv/your-app/public"
10
+ server_root = "#{CONFIGURATION[:app_path]}/public"
11
11
 
12
12
  shared_server_conf = <<-END_SHARED_SERVER_CONF
13
13
 
@@ -22,14 +22,10 @@
22
22
  # let browsers cache static assets
23
23
  location ~ ^/(images|javascripts|stylesheets)/ { expires 1y; }
24
24
 
25
- # always display system/maintenance.html if it exists
26
- if ($request_filename ~* \.(js|css|gif|png|jpg)$) { break; }
27
- if (-f $document_root/system/maintenance.html) {
28
- rewrite ^(.*)$ /system/maintenance.html last;
29
- break;
30
- }
25
+ # static files, page caching and maintenance.html
26
+ try_files $uri $uri/index.html $uri.html /system/maintenance.html @passenger;
31
27
 
32
- location / {
28
+ location @passenger {
33
29
  passenger_enabled on;
34
30
  }
35
31
 
@@ -17,7 +17,7 @@ PACKAGES="$SYSTEM_PACKAGES $DB_CLIENT_PACKAGES $RUBY_BUILD_DEPENDENCIES $NGINX_A
17
17
 
18
18
  # the rest is used by install_cust.sh
19
19
  RUBY_PACKAGE=ruby-1.9.2-p180
20
- IMAGE_MAGICK_PACKAGE=ImageMagick-6.6.7-8
20
+ IMAGE_MAGICK_PACKAGE=ImageMagick-6.6.8-6
21
21
  IMAGE_MAGICK_OPTIONS='--disable-static --with-modules --without-perl --without-magick-plus-plus --with-quantum-depth=8'
22
22
  NGINX_OPTIONS="\
23
23
  --conf-path=/etc/nginx/nginx.conf \
@@ -5,7 +5,7 @@
5
5
  download ftp://ftp.ruby-lang.org//pub/ruby/1.9/$RUBY_PACKAGE.tar.gz
6
6
  extract_and_install $RUBY_PACKAGE
7
7
  sudo gem update --system
8
- sudo gem install --no-ri --no-rdoc bundler passenger
8
+ sudo gem install --no-ri --no-rdoc bundler passenger breeze
9
9
 
10
10
  # install nginx and passenger
11
11
  sudo passenger-install-nginx-module --auto --auto-download --prefix=/usr --extra-configure-flags="$NGINX_OPTIONS"
@@ -34,10 +34,10 @@ sudo usermod --groups rails ubuntu
34
34
 
35
35
  wget -q --no-check-certificate --directory-prefix=$HOME --output-document=tarball.tar.gz $DOWNLOAD_URL
36
36
  tar --directory $HOME -xzf tarball.tar.gz
37
-
38
37
  sudo mv $HOME/*$APP_NAME* $DEPLOY_PATH
39
- sudo chown -R rails $DEPLOY_PATH
38
+
40
39
  cd $DEPLOY_PATH
41
- sudo bundle install --without=test development
40
+ bundle install --deployment --without=test development
41
+ sudo chown -R rails:rails $DEPLOY_PATH
42
42
  sudo PUBLIC_SERVER_NAME=$PUBLIC_SERVER_NAME DB_SERVER=$DB_SERVER thor configuration:deploy_to_localhost
43
43
  sudo /etc/init.d/monit start
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Markus Bengts
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-03-20 00:00:00 +01:00
17
+ date: 2011-03-22 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -73,8 +73,8 @@ files:
73
73
  - lib/breeze/tasks/app.rb
74
74
  - lib/breeze/tasks/configuration.rb
75
75
  - lib/breeze/tasks/db.rb
76
+ - lib/breeze/tasks/describe.rb
76
77
  - lib/breeze/tasks/dns.rb
77
- - lib/breeze/tasks/list.rb
78
78
  - lib/breeze/tasks/server.rb
79
79
  - lib/breeze/tasks/server/address.rb
80
80
  - lib/breeze/tasks/server/image.rb