breeze 0.0.3 → 0.0.4
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/.gitignore +1 -0
- data/breeze.gemspec +3 -1
- data/features/erb_conf.feature +76 -0
- data/features/support/env.rb +33 -0
- data/lib/breeze.rb +1 -1
- data/lib/breeze/fog_extensions/aws.rb +5 -0
- data/lib/breeze/tasks/app.rb +14 -3
- data/lib/breeze/tasks/configuration.rb +3 -3
- data/lib/breeze/tasks/describe.rb +1 -1
- data/lib/breeze/tasks/server.rb +28 -12
- data/lib/breeze/tasks/server/image.rb +11 -0
- data/lib/templates/Thorfile +4 -7
- data/lib/templates/profiles/rails_and_image_magick/configs/database.yml +1 -1
- data/lib/templates/profiles/rails_and_image_magick/scripts/install_cust.sh +1 -0
- metadata +35 -6
data/.gitignore
CHANGED
data/breeze.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Markus Bengts"]
|
10
10
|
s.email = ["markus.bengts@gmail.com"]
|
11
11
|
s.homepage = "https://github.com/markus/breeze"
|
12
|
-
s.summary = %q{Thor tasks to manage
|
12
|
+
s.summary = %q{Thor tasks to manage cloud computing resources and deployments}
|
13
13
|
s.description = <<-END_DESCRIPTION
|
14
14
|
Breeze makes it easy to automate server installation and configuration. It provides
|
15
15
|
example scripts and configuration files that you can modify and keep in your revision
|
@@ -25,4 +25,6 @@ END_DESCRIPTION
|
|
25
25
|
|
26
26
|
s.add_dependency('thor')
|
27
27
|
s.add_dependency('fog', '>= 0.7')
|
28
|
+
s.add_development_dependency "cucumber"
|
29
|
+
s.add_development_dependency "aruba"
|
28
30
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
Feature: ERb Configuration
|
2
|
+
|
3
|
+
Server configuration files can be transformed from ERb templates
|
4
|
+
in config/breeze/configs and deployed to any path on the server.
|
5
|
+
This allows us to keep configuration files under revision control
|
6
|
+
and to deploy the same configuration to multiple servers.
|
7
|
+
|
8
|
+
Scenario: Transform and deploy a configuration file
|
9
|
+
Given a file named "config/breeze/configs/test" with:
|
10
|
+
"""
|
11
|
+
<%
|
12
|
+
@path = 'test.conf'
|
13
|
+
@perms = 0600
|
14
|
+
@post = 'ls -l test.conf'
|
15
|
+
%>
|
16
|
+
http {
|
17
|
+
root <%= CONFIGURATION[:app_path] %>/public
|
18
|
+
}
|
19
|
+
"""
|
20
|
+
When I run `thor configuration:deploy_to_localhost`
|
21
|
+
Then the file "test.conf" should contain exactly:
|
22
|
+
"""
|
23
|
+
|
24
|
+
http {
|
25
|
+
root /srv/YOUR-APP/public
|
26
|
+
}
|
27
|
+
"""
|
28
|
+
And the output should contain "-rw-------"
|
29
|
+
|
30
|
+
Scenario: Read and write using custom commands
|
31
|
+
Given a file named "config/breeze/configs/test" with:
|
32
|
+
"""
|
33
|
+
<%
|
34
|
+
@read_cmd = 'echo "previous content"'
|
35
|
+
@write_cmd = 'cat'
|
36
|
+
%>
|
37
|
+
new content
|
38
|
+
"""
|
39
|
+
When I run `thor configuration:deploy_to_localhost`
|
40
|
+
Then the output should contain "new content"
|
41
|
+
|
42
|
+
Scenario: Define transformation order with file names
|
43
|
+
Given a file named "config/breeze/configs/a_file" with:
|
44
|
+
"""
|
45
|
+
<%
|
46
|
+
@path = 'ab_test'
|
47
|
+
@perms = 0700
|
48
|
+
%>
|
49
|
+
this file is transformed first and then backed up
|
50
|
+
"""
|
51
|
+
And a file named "config/breeze/configs/b_file" with:
|
52
|
+
"""
|
53
|
+
<%
|
54
|
+
@path = 'ab_test'
|
55
|
+
@perms = 0700
|
56
|
+
@post = 'ls -l ab_test.backup'
|
57
|
+
%>
|
58
|
+
this overwrites the first ab_test
|
59
|
+
"""
|
60
|
+
When I run `thor configuration:deploy_to_localhost`
|
61
|
+
Then the file "ab_test" should contain "this overwrites the first ab_test"
|
62
|
+
And the file "ab_test.backup" should contain "transformed first and then backed up"
|
63
|
+
And the output should contain "-rwx------"
|
64
|
+
|
65
|
+
Scenario: Transform and deploy only one file
|
66
|
+
Given a file named "config/breeze/configs/a_file" with:
|
67
|
+
"""
|
68
|
+
<% @path = 'a_file' %> this is a
|
69
|
+
"""
|
70
|
+
And a file named "config/breeze/configs/b_file" with:
|
71
|
+
"""
|
72
|
+
<% @path = 'b_file' %> this is b
|
73
|
+
"""
|
74
|
+
When I run `thor configuration:deploy_to_localhost config/breeze/configs/b*`
|
75
|
+
Then a file named "b_file" should exist
|
76
|
+
And a file named "a_file" should not exist
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
|
3
|
+
# We need a clean test app template that can be cloned into
|
4
|
+
# tmp/aruba for each scenario.
|
5
|
+
template_dir = File.expand_path('tmp/test_app_template')
|
6
|
+
|
7
|
+
# Create the test app with `breeze init`.
|
8
|
+
system <<-END_SCRIPT
|
9
|
+
rm -rf #{template_dir}
|
10
|
+
mkdir -p #{template_dir}
|
11
|
+
cd #{template_dir}
|
12
|
+
bundle exec ../../bin/breeze init > /dev/null
|
13
|
+
END_SCRIPT
|
14
|
+
|
15
|
+
# Remove all configuration file templates because they may contain absolute paths
|
16
|
+
# and commands that make changes to the local system.
|
17
|
+
system("rm -rf #{template_dir}/config/breeze/configs/*")
|
18
|
+
|
19
|
+
# Use the current source insted of the installed gem.
|
20
|
+
thorfile_path = File.join(template_dir, 'Thorfile')
|
21
|
+
thorfile_content = File.read(thorfile_path)
|
22
|
+
expected_require = "require 'breeze'"
|
23
|
+
wanted_require = "require 'bundler'; Bundler.setup; require 'breeze'"
|
24
|
+
raise "Cannot find #{expected_require} in #{thorfile_path}" unless thorfile_content.include?(expected_require)
|
25
|
+
File.open(thorfile_path, 'w') { |f| f.puts(thorfile_content.sub(expected_require, wanted_require)) }
|
26
|
+
|
27
|
+
# Use Fog.mock!
|
28
|
+
system("echo 'Fog.mock!' >> #{thorfile_path}")
|
29
|
+
|
30
|
+
# Clone the test app for each scenario.
|
31
|
+
Before do
|
32
|
+
system("cp -r #{template_dir} tmp/aruba")
|
33
|
+
end
|
data/lib/breeze.rb
CHANGED
@@ -11,6 +11,7 @@ module Fog
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def display_name
|
14
|
+
return "#{state}:#{name}" if name and state != 'running'
|
14
15
|
name || public_ip_address || "#{state} #{flavor_id} #{id}"
|
15
16
|
end
|
16
17
|
|
@@ -55,6 +56,10 @@ module Fog
|
|
55
56
|
end
|
56
57
|
class Compute::Image
|
57
58
|
|
59
|
+
def display_name
|
60
|
+
name or location
|
61
|
+
end
|
62
|
+
|
58
63
|
def full_type
|
59
64
|
"#{type}, #{architecture}, #{root_device_type}"
|
60
65
|
end
|
data/lib/breeze/tasks/app.rb
CHANGED
@@ -17,9 +17,12 @@ module Breeze
|
|
17
17
|
end
|
18
18
|
server = create_server
|
19
19
|
server.breeze_data(:name => public_server_name, :db => db_server_name)
|
20
|
-
|
21
|
-
|
20
|
+
if options[:elastic_ip]
|
21
|
+
thor("server:address:create #{server.id}")
|
22
|
+
server.reload until server.addresses.first
|
23
|
+
end
|
22
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]}")
|
23
26
|
end
|
24
27
|
|
25
28
|
desc 'stop PUBLIC_SERVER_NAME', 'Destroy web server and db'
|
@@ -55,7 +58,7 @@ module Breeze
|
|
55
58
|
new_server = create_server
|
56
59
|
new_server.breeze_data(:name => public_server_name, :db => db_server_name)
|
57
60
|
deploy_command([new_server], public_server_name, db_server_name, branch)
|
58
|
-
puts("The new server should soon be available at #{ip(new_server)}
|
61
|
+
puts("The new server should soon be available at: #{ip(new_server)}")
|
59
62
|
if ask("Ready to continue and move the elastic_ip for #{public_server_name} to the new server? [YES/rollback] >") =~ /r|n/i
|
60
63
|
new_server.destroy
|
61
64
|
else
|
@@ -153,6 +156,10 @@ module Breeze
|
|
153
156
|
super(task + (options[:force] ? ' --force' : ''))
|
154
157
|
end
|
155
158
|
|
159
|
+
def log_in_to(server)
|
160
|
+
system("#{CONFIGURATION[:ssh][:ssh_command]} #{CONFIGURATION[:ssh][:ssh_user]}@#{server}")
|
161
|
+
end
|
162
|
+
|
156
163
|
# Don't know how to include or inherit thor tasks and descriptions.
|
157
164
|
# These may be included in Staging and Production.
|
158
165
|
def self.inherited(c)
|
@@ -173,6 +180,10 @@ module Breeze
|
|
173
180
|
def enable
|
174
181
|
thor("app:enable \#{PUBLIC_SERVER_NAME}")
|
175
182
|
end
|
183
|
+
desc 'ssh', 'Log in with ssh'
|
184
|
+
def ssh
|
185
|
+
log_in_to(PUBLIC_SERVER_NAME)
|
186
|
+
end
|
176
187
|
END_TASKS
|
177
188
|
end
|
178
189
|
|
@@ -9,11 +9,11 @@ module Breeze
|
|
9
9
|
# See https://github.com/wr0ngway/rubber/wiki/Configuration
|
10
10
|
class Configuration < Veur
|
11
11
|
|
12
|
-
desc 'deploy_to_localhost',
|
12
|
+
desc 'deploy_to_localhost [FILE]',
|
13
13
|
'Transform and deploy server configuration files to the local file system based on ERB templates in config/server'
|
14
14
|
method_option :force, :default => false, :desc => 'Overwrite and execute @post commands even if files would not change'
|
15
|
-
def deploy_to_localhost
|
16
|
-
Dir[
|
15
|
+
def deploy_to_localhost(file_pattern='config/breeze/configs/**/*')
|
16
|
+
Dir[file_pattern].sort.each do |path|
|
17
17
|
transform_and_deploy(path, options[:force]) unless File.directory?(path)
|
18
18
|
end
|
19
19
|
end
|
@@ -19,7 +19,7 @@ module Breeze
|
|
19
19
|
report 'MACHINE IMAGES',
|
20
20
|
['Name or Location', 'Image ID', 'Owner', 'Image Type', 'Public'],
|
21
21
|
fog.images.all('Owner' => Breeze::CONFIGURATION[:image_owner]).map{ |i|
|
22
|
-
[i.
|
22
|
+
[i.display_name, i.id, i.owner_id, i.full_type, i.is_public]
|
23
23
|
}
|
24
24
|
end
|
25
25
|
|
data/lib/breeze/tasks/server.rb
CHANGED
@@ -14,12 +14,14 @@ module Breeze
|
|
14
14
|
create_server(options)
|
15
15
|
end
|
16
16
|
|
17
|
-
desc 'destroy INSTANCE_ID', 'Terminate a running (or stopped) server instance'
|
17
|
+
desc 'destroy INSTANCE_ID [...]', 'Terminate a running (or stopped) server instance'
|
18
18
|
method_options :force => false
|
19
|
-
def destroy(
|
20
|
-
|
21
|
-
|
22
|
-
server.
|
19
|
+
def destroy(*instance_ids)
|
20
|
+
instance_ids.each do |instance_id|
|
21
|
+
server = fog.servers.get(instance_id)
|
22
|
+
if force_or_accept?("Terminate server #{server.display_name}?")
|
23
|
+
server.destroy
|
24
|
+
end
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -34,31 +36,45 @@ module Breeze
|
|
34
36
|
return server
|
35
37
|
end
|
36
38
|
|
37
|
-
|
39
|
+
# Can take a host name or an ip address. Resolves the host name
|
40
|
+
# and returns the ip address if get_ip is passed in as true.
|
41
|
+
def wait_until_host_is_available(host, get_ip=false)
|
38
42
|
if Resolv.getaddresses(host).empty?
|
39
43
|
print("Waiting for #{host} to resolve")
|
40
44
|
wait_until('ready!') { Resolv.getaddresses(host).any? }
|
41
45
|
end
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
host = Resolv.getaddresses(host).first if get_ip
|
47
|
+
unless remote_is_available?(host)
|
48
|
+
print("Waiting for #{host} to accept connections")
|
49
|
+
wait_until('ready!') { remote_is_available?(host) }
|
50
|
+
end
|
51
|
+
return host
|
45
52
|
end
|
46
53
|
|
47
54
|
def remote_is_available?(host)
|
48
|
-
execute(
|
55
|
+
execute("%{ssh_command} -q %{ssh_user}@%{host} exit", :host => host)
|
49
56
|
end
|
50
57
|
|
58
|
+
# Execute a command on the remote host. Args is a hash that must include :host.
|
51
59
|
def remote(command, args)
|
52
60
|
args[:command] = command
|
53
|
-
execute(
|
61
|
+
execute("%{ssh_command} %{ssh_user}@%{host} '%{command}'", args)
|
54
62
|
end
|
55
63
|
|
56
64
|
def upload(file_pattern, args)
|
57
65
|
args[:file_pattern] = file_pattern
|
58
|
-
|
66
|
+
args[:remote_path] ||= './'
|
67
|
+
execute('rsync -e "%{ssh_command}" -v %{file_pattern} %{ssh_user}@%{host}:%{remote_path}', args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def download(remote_path, args)
|
71
|
+
args[:remote_path] = remote_path
|
72
|
+
args[:local_path] ||= './'
|
73
|
+
execute('rsync -e "%{ssh_command}" -v %{ssh_user}@%{host}:%{remote_path} %{local_path}', args)
|
59
74
|
end
|
60
75
|
|
61
76
|
def execute(command, args)
|
77
|
+
args = CONFIGURATION[:ssh].merge(args)
|
62
78
|
command = CONFIGURATION[command] if command.is_a?(Symbol)
|
63
79
|
# system(command % args)
|
64
80
|
# rescue ArgumentError # for ruby 1.8 compatibility
|
@@ -28,5 +28,16 @@ module Breeze
|
|
28
28
|
puts("NOTICE: it may take a while before the new image shows up in describe:images")
|
29
29
|
end
|
30
30
|
|
31
|
+
desc 'destroy IMAGE_ID [...]', 'Deregister the image and destroy the related volume snapshot'
|
32
|
+
method_options :force => false
|
33
|
+
def destroy(*image_ids)
|
34
|
+
image_ids.each do |image_id|
|
35
|
+
image = fog.images.get(image_id)
|
36
|
+
if force_or_accept?("Destroy image #{image.display_name}?")
|
37
|
+
image.deregister(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
31
42
|
end
|
32
43
|
end
|
data/lib/templates/Thorfile
CHANGED
@@ -13,12 +13,9 @@ Breeze::CONFIGURATION = {
|
|
13
13
|
:aws_secret_access_key => 'YOUR-SECTET-ACCESS-KEY'
|
14
14
|
},
|
15
15
|
|
16
|
-
#
|
17
|
-
# an application.
|
18
|
-
|
19
|
-
:remote_available? => 'ssh -q ubuntu@%{host} exit',
|
20
|
-
:remote_command => "ssh ubuntu@%{host} '%{command}'",
|
21
|
-
:upload_command => 'rsync -v %{file_pattern} ubuntu@%{host}:%{remote_path}',
|
16
|
+
# ssh_command and ssh_user are required in order to create a server image or deploy
|
17
|
+
# an application. Use "ssh -i /path/to/key" if not using your default ssh key.
|
18
|
+
:ssh => {:ssh_command => "ssh -o 'UserKnownHostsFile /dev/null'", :ssh_user => 'ubuntu'},
|
22
19
|
|
23
20
|
# :rollback_window specifies the number of minutes to keep old instances running after new ones
|
24
21
|
# have been deployed. Rollback is no longer possible when the old instances have been destroyed.
|
@@ -91,7 +88,7 @@ class Breeze::App
|
|
91
88
|
end
|
92
89
|
|
93
90
|
# Define staging:start etc. below. The constants are also needed by
|
94
|
-
# inherited tasks: deploy, rollback, enable and
|
91
|
+
# inherited tasks: deploy, rollback, enable, disable and ssh.
|
95
92
|
|
96
93
|
class Staging < Breeze::App
|
97
94
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
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-
|
17
|
+
date: 2011-04-19 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -44,6 +44,32 @@ dependencies:
|
|
44
44
|
version: "0.7"
|
45
45
|
type: :runtime
|
46
46
|
version_requirements: *id002
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: cucumber
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id003
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: aruba
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
type: :development
|
72
|
+
version_requirements: *id004
|
47
73
|
description: |
|
48
74
|
Breeze makes it easy to automate server installation and configuration. It provides
|
49
75
|
example scripts and configuration files that you can modify and keep in your revision
|
@@ -65,6 +91,8 @@ files:
|
|
65
91
|
- Rakefile
|
66
92
|
- bin/breeze
|
67
93
|
- breeze.gemspec
|
94
|
+
- features/erb_conf.feature
|
95
|
+
- features/support/env.rb
|
68
96
|
- lib/breeze.rb
|
69
97
|
- lib/breeze/fog_extensions.rb
|
70
98
|
- lib/breeze/fog_extensions/aws.rb
|
@@ -128,6 +156,7 @@ rubyforge_project: breeze
|
|
128
156
|
rubygems_version: 1.3.7
|
129
157
|
signing_key:
|
130
158
|
specification_version: 3
|
131
|
-
summary: Thor tasks to manage
|
132
|
-
test_files:
|
133
|
-
|
159
|
+
summary: Thor tasks to manage cloud computing resources and deployments
|
160
|
+
test_files:
|
161
|
+
- features/erb_conf.feature
|
162
|
+
- features/support/env.rb
|