breeze 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +4 -0
- data/Rakefile +2 -0
- data/bin/breeze +17 -0
- data/breeze.gemspec +28 -0
- data/lib/breeze.rb +6 -0
- data/lib/breeze/fog_extensions.rb +2 -0
- data/lib/breeze/fog_extensions/aws.rb +65 -0
- data/lib/breeze/initializer.rb +40 -0
- data/lib/breeze/tasks.rb +10 -0
- data/lib/breeze/tasks/app.rb +145 -0
- data/lib/breeze/tasks/configuration.rb +63 -0
- data/lib/breeze/tasks/db.rb +31 -0
- data/lib/breeze/tasks/dns.rb +67 -0
- data/lib/breeze/tasks/list.rb +74 -0
- data/lib/breeze/tasks/server.rb +72 -0
- data/lib/breeze/tasks/server/address.rb +27 -0
- data/lib/breeze/tasks/server/image.rb +27 -0
- data/lib/breeze/tasks/server/tag.rb +16 -0
- data/lib/breeze/veur.rb +86 -0
- data/lib/templates/Thorfile +122 -0
- data/lib/templates/maintenance.html +23 -0
- data/lib/templates/profiles/minimal/scripts/install_conf.sh +4 -0
- data/lib/templates/profiles/minimal/scripts/install_cust.sh +7 -0
- data/lib/templates/profiles/rails_and_image_magick/configs/database.yml +18 -0
- data/lib/templates/profiles/rails_and_image_magick/configs/memcached.conf +51 -0
- data/lib/templates/profiles/rails_and_image_magick/configs/nginx/logrotate +26 -0
- data/lib/templates/profiles/rails_and_image_magick/configs/nginx/monit +9 -0
- data/lib/templates/profiles/rails_and_image_magick/configs/nginx/nginx.conf +99 -0
- data/lib/templates/profiles/rails_and_image_magick/scripts/install_conf.sh +33 -0
- data/lib/templates/profiles/rails_and_image_magick/scripts/install_cust.sh +24 -0
- data/lib/templates/shared/configs/crontab +10 -0
- data/lib/templates/shared/configs/monitrc +248 -0
- data/lib/templates/shared/scripts/credentials.sh +5 -0
- data/lib/templates/shared/scripts/deploy.sh +43 -0
- data/lib/templates/shared/scripts/install.sh +38 -0
- data/lib/templates/user_data.sh +4 -0
- metadata +133 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
module Breeze
|
2
|
+
module Dns
|
3
|
+
|
4
|
+
class Zone < Veur
|
5
|
+
|
6
|
+
desc 'create DOMAIN', 'Create a new DNS zone'
|
7
|
+
def create(domain)
|
8
|
+
zone = dns.zones.create(:domain => domain)
|
9
|
+
puts "Zone ID: #{zone.id}"
|
10
|
+
puts "Change info: #{zone.change_info}"
|
11
|
+
puts "Name servers: #{zone.nameservers}"
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'destroy ZONE_ID', 'Destroy a DNS zone'
|
15
|
+
def destroy(zone_id)
|
16
|
+
zone = dns.zones.get(zone_id)
|
17
|
+
if accept?("Destroy DNS zone and records for #{zone.domain}?")
|
18
|
+
zone.records.each(&:destroy)
|
19
|
+
zone.destroy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'import ZONE_ID FILE', 'Creates dns records specified in FILE'
|
24
|
+
long_desc <<-END_DESC
|
25
|
+
FILE should be the path to a ruby file that defines DNS_RECORDS like this:
|
26
|
+
DNS_RECORDS = [
|
27
|
+
{:name => 'example.com', :type => 'A', :ip => '1.2.3.4'},
|
28
|
+
{:name => 'www.example.com', :type => 'CNAME', :ip => 'example.com'}
|
29
|
+
]
|
30
|
+
You can also specify :ttl for each record. The default ttl is 3600 (1 hour).
|
31
|
+
END_DESC
|
32
|
+
def import(zone_id, file)
|
33
|
+
load file
|
34
|
+
zone = get_zone(zone_id)
|
35
|
+
DNS_RECORDS.each do |record_hash|
|
36
|
+
zone.records.create(record_hash)
|
37
|
+
puts record_hash.inspect
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def get_zone(id)
|
44
|
+
dns.zones.get(id)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
class Record < Zone
|
50
|
+
|
51
|
+
desc 'create ZONE_ID NAME TYPE IP [TTL]', 'Create a new DNS record'
|
52
|
+
def create(zone_id, name, type, ip, ttl=3600)
|
53
|
+
get_zone(zone_id).records.create(:name => name, :type => type, :ip => ip, :ttl => ttl)
|
54
|
+
end
|
55
|
+
|
56
|
+
desc 'destroy ZONE_ID NAME [TYPE]', 'Destroy a DNS record'
|
57
|
+
method_options :force => false
|
58
|
+
def destroy(zone_id, name, type=nil)
|
59
|
+
records = get_zone(zone_id).records.select{ |r| r.name == name && (type.nil? || r.type == type) }
|
60
|
+
if force_or_accept?("Destroy #{records.size} record#{records.size == 1 ? '' : 's'}?")
|
61
|
+
records.each(&:destroy)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Breeze
|
2
|
+
|
3
|
+
class List < Veur
|
4
|
+
|
5
|
+
desc :cloud_resources, 'List all cloud resources that the current account can control with breeze'
|
6
|
+
def cloud_resources
|
7
|
+
images
|
8
|
+
servers
|
9
|
+
addresses
|
10
|
+
volumes
|
11
|
+
db_servers
|
12
|
+
dns_zones
|
13
|
+
end
|
14
|
+
|
15
|
+
desc :images, 'Describe machine images owned by Breeze::CONFIGURATION[:image_owner]'
|
16
|
+
def images
|
17
|
+
report 'MACHINE IMAGES',
|
18
|
+
['Name or Location', 'Image ID', 'Owner', 'Image Type', 'Public'],
|
19
|
+
fog.images.all('Owner' => Breeze::CONFIGURATION[:image_owner]).map{ |i|
|
20
|
+
[i.name||i.location, i.id, i.owner_id, i.full_type, i.is_public]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
desc :servers, 'Describe server instances'
|
25
|
+
def servers
|
26
|
+
report "SERVER INSTANCES",
|
27
|
+
['Name', 'Instance ID', 'IP Address', 'Image ID', 'Instance Type', 'Availability Zone', 'State'],
|
28
|
+
fog.servers.map { |i|
|
29
|
+
[i.name, i.id, i.public_ip_address, i.image_id, i.flavor_id, i.availability_zone, i.state]
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
desc :addresses, 'List allocated ip addresses'
|
34
|
+
def addresses
|
35
|
+
report "ALLOCATED IP ADDRESSES",
|
36
|
+
['Address', 'Server'],
|
37
|
+
fog.addresses.map{ |a| [a.public_ip, a.server_id] }
|
38
|
+
end
|
39
|
+
|
40
|
+
desc :volumes, 'Describe block store volumes (EBS)'
|
41
|
+
def volumes
|
42
|
+
report "VOLUMES",
|
43
|
+
['Volume ID', 'Size', 'Status', 'Zone', 'Snapshot ID', 'Used by'],
|
44
|
+
fog.volumes.map { |v|
|
45
|
+
[v.id, v.size, v.state, v.availability_zone, v.snapshot_id, v.server_id]
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
desc :db_servers, 'List database servers'
|
50
|
+
def db_servers
|
51
|
+
report "DATABASE SERVERS",
|
52
|
+
['Name', 'Type', 'Storage', 'State', 'Endpoint'],
|
53
|
+
rds.servers.map{ |s| [s.id, s.flavor_id, s.allocated_storage, s.state, s.endpoint] }
|
54
|
+
end
|
55
|
+
|
56
|
+
desc :dns_zones, 'Describe DNS zones'
|
57
|
+
def dns_zones
|
58
|
+
zones = dns.zones
|
59
|
+
zones.each(&:reload) # necessary in order to get nameservers
|
60
|
+
report "DNS ZONES",
|
61
|
+
['Domain', 'Zone ID', 'Name servers'],
|
62
|
+
zones.map{ |z| [z.domain, z.id, z.nameservers.join(', ')] }
|
63
|
+
end
|
64
|
+
|
65
|
+
desc 'dns_records ZONE_ID', 'List all DNS records for the given zone'
|
66
|
+
def dns_records(zone_id)
|
67
|
+
zone = dns.zones.get(zone_id)
|
68
|
+
report "DNS RECORDS FOR #{zone.domain}",
|
69
|
+
['Name', 'Type', 'TTL', 'Value'],
|
70
|
+
zone.records.map{ |r| [r.name, r.type, r.ttl, r.ip.join(', ')] }
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'resolv'
|
2
|
+
|
3
|
+
module Breeze
|
4
|
+
|
5
|
+
# Dealing with server instances.
|
6
|
+
class Server < Veur
|
7
|
+
|
8
|
+
desc 'create', 'Launch a new server instance'
|
9
|
+
method_options CONFIGURATION[:default_server_options]
|
10
|
+
def create
|
11
|
+
if options[:user_data_file]
|
12
|
+
options[:user_data] = Base64.encode64(File.read(options[:user_data_file])).strip
|
13
|
+
end
|
14
|
+
create_server(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'destroy INSTANCE_ID', 'Terminate a running (or stopped) server instance'
|
18
|
+
method_options :force => false
|
19
|
+
def destroy(instance_id)
|
20
|
+
server = fog.servers.get(instance_id)
|
21
|
+
if force_or_accept?("Terminate server #{server.display_name}?")
|
22
|
+
server.destroy
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def create_server(options=nil)
|
29
|
+
options ||= CONFIGURATION[:default_server_options]
|
30
|
+
# puts("Server options: #{options.inspect}")
|
31
|
+
server = fog.servers.create(options)
|
32
|
+
print "Launching server #{server.id}"
|
33
|
+
wait_until('running!') { server.running? }
|
34
|
+
return server
|
35
|
+
end
|
36
|
+
|
37
|
+
def wait_until_host_is_available(host)
|
38
|
+
if Resolv.getaddresses(host).empty?
|
39
|
+
print("Waiting for #{host} to resolve")
|
40
|
+
wait_until('ready!') { Resolv.getaddresses(host).any? }
|
41
|
+
end
|
42
|
+
return true if remote_is_available?(host)
|
43
|
+
print("Waiting for #{host} to accept connections")
|
44
|
+
wait_until('ready!') { remote_is_available?(host) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def remote_is_available?(host)
|
48
|
+
execute(:remote_command, :command => 'exit', :host => host)
|
49
|
+
end
|
50
|
+
|
51
|
+
def remote(command, args)
|
52
|
+
args[:command] = command
|
53
|
+
execute(:remote_command, args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def upload(file_pattern, args)
|
57
|
+
args[:file_pattern] = file_pattern
|
58
|
+
execute(:upload_command, args)
|
59
|
+
end
|
60
|
+
|
61
|
+
def execute(command, args)
|
62
|
+
command = CONFIGURATION[command] if command.is_a?(Symbol)
|
63
|
+
# system(command % args)
|
64
|
+
# rescue ArgumentError # for ruby 1.8 compatibility
|
65
|
+
args.each do |key, value|
|
66
|
+
command = command.gsub("%{#{key}}", value)
|
67
|
+
end
|
68
|
+
system(command)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Breeze
|
2
|
+
|
3
|
+
# Aka Amazon Elastic IP
|
4
|
+
class Server::Address < Veur
|
5
|
+
|
6
|
+
desc 'create SERVER_ID', 'Create and associate a new elastic ip'
|
7
|
+
def create(server_id)
|
8
|
+
# TODO: fog should take server_id directly when creating an address
|
9
|
+
server = fog.servers.get(server_id)
|
10
|
+
fog.addresses.create(:server => server)
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'release IP', 'Release the ip address'
|
14
|
+
method_options :force => false
|
15
|
+
def release(ip)
|
16
|
+
if force_or_accept?("Release IP #{ip}?")
|
17
|
+
fog.addresses.get(ip).destroy
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'associate IP NEW_SERVER_ID', 'Associate an existing IP with a new server'
|
22
|
+
def associate(ip, server_id)
|
23
|
+
fog.associate_address(server_id, ip)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'breeze/tasks/server'
|
2
|
+
|
3
|
+
module Breeze
|
4
|
+
|
5
|
+
# Dealing with machine images.
|
6
|
+
class Server::Image < Server
|
7
|
+
desc 'create', 'Launch a server with the base image, wait for it to boot, invoke prepare_private_image(ip_address), ' +
|
8
|
+
'stop the server, create a new machine image as a snapshot of the root device, and destroy the server.'
|
9
|
+
method_options CONFIGURATION[:default_server_options].merge(CONFIGURATION[:create_image_options])
|
10
|
+
def create
|
11
|
+
options[:block_device_mapping] = [{:device_name => '/dev/sda1', :ebs_volume_size => options.delete(:root_device_size)}]
|
12
|
+
server = create_server(options)
|
13
|
+
prepare_private_image(server.public_ip_address)
|
14
|
+
print('Stopping the server before saving a snapshot')
|
15
|
+
server.stop
|
16
|
+
wait_until('stopped!') { server.stopped? }
|
17
|
+
thor('list:images')
|
18
|
+
image = fog.images.create(:name => ask('Image name >'), :instance_id => server.id)
|
19
|
+
server.destroy
|
20
|
+
puts
|
21
|
+
puts("===> Created image #{image.id} and terminated temporary server #{server.id}.")
|
22
|
+
puts
|
23
|
+
puts("NOTICE: it may take a while before the new image shows up in list:images")
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Breeze
|
2
|
+
|
3
|
+
class Server::Tag < Veur
|
4
|
+
|
5
|
+
desc 'create SERVER_ID KEY VALUE', 'Create or update a tag'
|
6
|
+
def create(server_id, key, value)
|
7
|
+
fog.tags.create(:resource_id => server_id, :key => key, :value => value)
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'destroy SERVER_ID KEY', 'Delete a tag'
|
11
|
+
def destroy(server_id, key)
|
12
|
+
fog.tags.get(key).detect{ |tag| tag.resource_id == server_id }.destroy
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/breeze/veur.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'breeze/fog_extensions'
|
2
|
+
|
3
|
+
module Breeze
|
4
|
+
|
5
|
+
# Thor is also known as Veur. Veur means "guard of the shrine"
|
6
|
+
# (possibly) according to Wikipedia.
|
7
|
+
class Veur < Thor
|
8
|
+
|
9
|
+
include Thor::Actions
|
10
|
+
|
11
|
+
# shorten the task names
|
12
|
+
def self.inherited(c)
|
13
|
+
c.class_eval do
|
14
|
+
namespace Thor::Util.namespace_from_thor_class(c).sub('breeze:', '')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Thor freezes the options (don't understand why)
|
21
|
+
def options
|
22
|
+
@unfrozen_options ||= super.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
# yes? in thor cannot be accepted with enter
|
26
|
+
def accept?(question)
|
27
|
+
! (ask("#{question} [YES/no] >") =~ /n/i)
|
28
|
+
end
|
29
|
+
|
30
|
+
# don't ask questions if given the --force option
|
31
|
+
def force_or_accept?(question)
|
32
|
+
options[:force] or accept?(question)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Print out dots while waiting for something.
|
36
|
+
# Usage:
|
37
|
+
# print "My task is running..."
|
38
|
+
# wait_until { my_task.completed? }
|
39
|
+
def wait_until(message='completed!')
|
40
|
+
3.times { dot_and_sleep(1) }
|
41
|
+
dot_and_sleep(2) until yield
|
42
|
+
puts message
|
43
|
+
end
|
44
|
+
|
45
|
+
# a helper for wait_until
|
46
|
+
def dot_and_sleep(interval)
|
47
|
+
print('.')
|
48
|
+
sleep(interval)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Print a table with a title and a top border of matching width.
|
52
|
+
def report(title, columns, rows)
|
53
|
+
table = capture_table([columns] + rows)
|
54
|
+
title = "=== #{title} "
|
55
|
+
title << "=" * [(table.lines.max{|s| s.size }.size - title.size), 3].max
|
56
|
+
puts title
|
57
|
+
puts table
|
58
|
+
end
|
59
|
+
|
60
|
+
# capture table in order to determine it's width
|
61
|
+
def capture_table(table)
|
62
|
+
return 'none' if table.size == 1 # the first row is for column titles
|
63
|
+
$stdout = StringIO.new # start capturing the output
|
64
|
+
print_table(table.map{ |row| row.map(&:to_s) })
|
65
|
+
output = $stdout
|
66
|
+
$stdout = STDOUT # restore normal output
|
67
|
+
return output.string
|
68
|
+
end
|
69
|
+
|
70
|
+
def fog
|
71
|
+
@fog ||= Fog::Compute.new(CONFIGURATION[:cloud_service])
|
72
|
+
end
|
73
|
+
|
74
|
+
def dns
|
75
|
+
@dns ||= Fog::DNS.new(CONFIGURATION[:cloud_service])
|
76
|
+
end
|
77
|
+
|
78
|
+
def rds
|
79
|
+
return @rds if @rds
|
80
|
+
credentials = CONFIGURATION[:cloud_service].reject{ |k,v| k == :provider }
|
81
|
+
credentials[:region] = CONFIGURATION[:db_region]
|
82
|
+
@rds = Fog::AWS::RDS.new(credentials)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Sign up for AWS credentials at http://aws.amazon.com/, and learn how to
|
2
|
+
# upload your own public ssh key at http://alestic.com/2010/10/ec2-ssh-keys.
|
3
|
+
# Use environment variables in this file if you share it with others.
|
4
|
+
|
5
|
+
require 'breeze'
|
6
|
+
|
7
|
+
Breeze::CONFIGURATION = {
|
8
|
+
|
9
|
+
# Access credentials are needed for all tasks.
|
10
|
+
:cloud_service => {
|
11
|
+
:provider => 'AWS',
|
12
|
+
:aws_access_key_id => 'YOUR-ACCESS-KEY-ID',
|
13
|
+
:aws_secret_access_key => 'YOUR-SECTET-ACCESS-KEY'
|
14
|
+
},
|
15
|
+
|
16
|
+
# Remote and upload commands are required in order to create a server image or deploy
|
17
|
+
# an application. Arguments marked with %{} are automatically replaced when the
|
18
|
+
# commands are used. Use "ssh -i /path/to/key" if not using your default ssh key.
|
19
|
+
:remote_command => "ssh ubuntu@%{host} '%{command}'",
|
20
|
+
:upload_command => 'rsync -v %{file_pattern} ubuntu@%{host}:%{remote_path}',
|
21
|
+
|
22
|
+
# :rollback_window specifies the number of minutes to keep old instances running after new ones
|
23
|
+
# have been deployed. Rollback is no longer possible when the old instances have been destroyed.
|
24
|
+
:rollback_window => 60,
|
25
|
+
|
26
|
+
# Default server options are needed when launching new servers.
|
27
|
+
:default_server_options => {
|
28
|
+
:image_id => 'YOUR-PRIVATE-AMI-OR-A-PUBLIC-ONE',
|
29
|
+
:key_name => 'THE-NAME-OF-YOUR-KEYPAIR', # http://alestic.com/2010/10/ec2-ssh-keys
|
30
|
+
:flavor_id => 't1.micro', # t1.micro m1.small c1.medium ...
|
31
|
+
:availability_zone => 'us-east-1a', # us-west-1a eu-west-1a ap-southeast-1a
|
32
|
+
:user_data_file => nil
|
33
|
+
},
|
34
|
+
|
35
|
+
# Override default_server_options when building your own private server image:
|
36
|
+
:create_image_options => {
|
37
|
+
:image_id => 'ami-ccf405a5', # a base AMI from http://alestic.com
|
38
|
+
:root_device_size => 15 # in GB
|
39
|
+
},
|
40
|
+
|
41
|
+
# machine images owned by this account are included in list:images (provided that you have access to them)
|
42
|
+
:image_owner => 'YOUR-ACCOUNT-ID-WITHOUT-DASHES', # canonical: '099720109477'
|
43
|
+
|
44
|
+
# db configuration is required in order to use Amazon RDS
|
45
|
+
:db_region => 'us-east-1', # us-west-1 eu-west-1 ap-southeast-1
|
46
|
+
:default_db_options => {
|
47
|
+
:engine => 'mysql',
|
48
|
+
:engine_version => '5.5',
|
49
|
+
:auto_minor_version_upgrade => true,
|
50
|
+
:allocated_storage => 5, # 5 - 1024 GB
|
51
|
+
:availability_zone => 'us-east-1a',
|
52
|
+
:backup_retention_period => 1, # 0 - 8 days
|
53
|
+
:preferred_backup_window => '05:30-06:00', # daily, times in UTC
|
54
|
+
:preferred_maintenance_window => 'sun:06:00-sun:06:30', # weekly
|
55
|
+
:master_username => 'admin',
|
56
|
+
:password => 'admin'
|
57
|
+
},
|
58
|
+
|
59
|
+
# you can add your own keys and access this hash as CONFIGURATION in the erb templates
|
60
|
+
:admin_email => 'YOUR-EMAIL',
|
61
|
+
:app_path => '/srv/YOUR-APP'
|
62
|
+
}.freeze
|
63
|
+
|
64
|
+
# Define Breeze::CONFIGURATION before requiring the tasks.
|
65
|
+
# This allows us to pick up default options that can be viewed
|
66
|
+
# with the "thor help" command.
|
67
|
+
require 'breeze/tasks'
|
68
|
+
|
69
|
+
class Breeze::Server::Image
|
70
|
+
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
|
+
def prepare_private_image(ip_address)
|
74
|
+
wait_until_host_is_available(ip_address)
|
75
|
+
puts("Uploading scripts...")
|
76
|
+
upload('config/breeze/scripts/*.sh', :host => ip_address, :remote_path => './')
|
77
|
+
remote('chmod 600 credentials.sh; chmod 700 deploy.sh; bash install.sh', :host => ip_address)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# You can define staging:start etc. with fixed parameters below.
|
82
|
+
|
83
|
+
class Breeze::App
|
84
|
+
private
|
85
|
+
def deploy_command(servers, public_server_name, db_server_name, branch)
|
86
|
+
servers.each do |server|
|
87
|
+
wait_until_host_is_available(ip(server))
|
88
|
+
remote("/home/ubuntu/deploy.sh #{public_server_name} #{db_endpoint(db_server_name)} #{branch}", :host => ip(server))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# thor staging:start and staging:stop
|
94
|
+
class Staging < Breeze::App
|
95
|
+
|
96
|
+
PUBLIC_SERVER_NAME = 'staging.example.com'
|
97
|
+
DB_SERVER_NAME = 'staging-db'
|
98
|
+
|
99
|
+
desc 'start', 'Start web server and db for staging'
|
100
|
+
def start
|
101
|
+
thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} --db-to-clone=#{Production::DB_SERVER_NAME} --deploy-branch=master")
|
102
|
+
end
|
103
|
+
|
104
|
+
desc 'stop', 'Stop staging and destroy server and db'
|
105
|
+
def stop
|
106
|
+
thor("app:stop #{PUBLIC_SERVER_NAME} --force")
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
# thor production:start
|
112
|
+
class Production < Breeze::App
|
113
|
+
|
114
|
+
PUBLIC_SERVER_NAME = 'production.example.com'
|
115
|
+
DB_SERVER_NAME = 'production-db'
|
116
|
+
|
117
|
+
desc 'start', 'Start web server and db for production'
|
118
|
+
def start
|
119
|
+
thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} crags --dns-ttl=300 --deploy-branch=stable")
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|