breeze 0.0.4 → 0.0.5
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 +12 -6
- data/breeze.gemspec +1 -1
- data/features/getting_started.feature +23 -0
- data/features/step_definitions/application_steps.rb +14 -0
- data/features/step_definitions/server_steps.rb +8 -0
- data/features/support/env.rb +10 -5
- data/lib/breeze.rb +1 -1
- data/lib/breeze/fog_extensions/aws.rb +5 -5
- data/lib/breeze/fog_wrapper.rb +73 -0
- data/lib/breeze/tasks/server.rb +5 -3
- data/lib/breeze/veur.rb +11 -7
- metadata +69 -83
data/README.md
CHANGED
@@ -1,14 +1,17 @@
|
|
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
|
-
and deployments
|
5
|
-
work so it should be fairly easy to add support for other cloud computing
|
4
|
+
and deployments. Currently only [Amazon's AWS cloud](http://aws.amazon.com/) is supported, but breeze uses
|
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
|
+
providers that are supported by fog.
|
6
7
|
|
7
|
-
Breeze implements zero downtime
|
8
|
-
compatible with the previous version.
|
8
|
+
Breeze implements zero downtime deploys and rollbacks by moving an elastic ip from one server to another. Db migrations have to be
|
9
|
+
compatible with the previous version. http://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/
|
9
10
|
|
10
11
|
## install
|
11
12
|
|
13
|
+
Run the following commands to install breeze and initialize a new project with configuration file templates.
|
14
|
+
|
12
15
|
gem install breeze
|
13
16
|
cd your-project
|
14
17
|
breeze init
|
@@ -21,10 +24,13 @@ for more information.
|
|
21
24
|
|
22
25
|
## create a server image
|
23
26
|
|
27
|
+
The command below installs a server and saves a private server image. When this is fully automated it can be
|
28
|
+
repeated with new software packages or a new OS version.
|
29
|
+
|
24
30
|
thor server:image:create
|
25
31
|
|
26
32
|
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)
|
33
|
+
(maybe half an hour on a small instance) and it will prompt for the image name when completed.
|
28
34
|
|
29
35
|
## use it
|
30
36
|
|
@@ -37,7 +43,7 @@ The default install.sh compiles ruby, passenger, nginx and image magick. It take
|
|
37
43
|
thor staging:start # Start web server and db for staging
|
38
44
|
thor staging:stop # Stop staging and destroy server and db
|
39
45
|
|
40
|
-
Define your staging and production in the Thorfile and the same tasks become available for both name spaces.
|
46
|
+
Define your staging and production constants in the Thorfile and the same tasks become available for both name spaces.
|
41
47
|
These tasks call app tasks with fixed parameters.
|
42
48
|
|
43
49
|
## plumbing commands
|
data/breeze.gemspec
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
Feature: Getting started
|
2
|
+
|
3
|
+
As a new user I want to quickly get an idea of how breeze works.
|
4
|
+
|
5
|
+
Scenario: Start a new project
|
6
|
+
Given I have an empty working directory
|
7
|
+
When I run `breeze init`
|
8
|
+
Then a file named "Thorfile" should exist
|
9
|
+
|
10
|
+
Scenario: Start a new server
|
11
|
+
Given my Thorfile contains access credentials and configuration
|
12
|
+
When I run `thor server:create`
|
13
|
+
And I run `thor describe:servers`
|
14
|
+
Then the output should look like:
|
15
|
+
"""
|
16
|
+
=== SERVER INSTANCES ===========================================================================
|
17
|
+
Name Instance ID IP Address .* Image ID Type Zone State
|
18
|
+
YOUR-PRIVATE-AMI-OR-A-PUBLIC-ONE t1.micro us-east-1a running
|
19
|
+
"""
|
20
|
+
|
21
|
+
Scenario: Terminate a server
|
22
|
+
Given I have started a server
|
23
|
+
Then I can terminate the server with `thor server:destroy [SERVER ID] --force`
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Given /^I have an empty working directory$/ do
|
2
|
+
step "I run `rm -rf config Thorfile`"
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^my Thorfile contains access credentials and configuration$/ do
|
6
|
+
# the Thorfile should be okay already, just check it
|
7
|
+
check_file_content('Thorfile', "CONFIGURATION", true)
|
8
|
+
end
|
9
|
+
|
10
|
+
Then /^the output should look like:$/ do |lines|
|
11
|
+
lines.each_line do |line|
|
12
|
+
all_output.should match(/#{line.strip}/)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Given /^I have started a server$/ do
|
2
|
+
step "I run `thor server:create`"
|
3
|
+
@started_server_id = $1 if all_stdout =~ /server (i-[^.])\.\.\./
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /^I can terminate the server with `thor server:destroy \[SERVER ID\] \-\-force`$/ do
|
7
|
+
step "I successfully run `thor server:destroy #{@started_server_id} --force`"
|
8
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -16,13 +16,17 @@ END_SCRIPT
|
|
16
16
|
# and commands that make changes to the local system.
|
17
17
|
system("rm -rf #{template_dir}/config/breeze/configs/*")
|
18
18
|
|
19
|
-
# Use the current source insted of the installed gem.
|
19
|
+
# Use the current source with bundler insted of the installed gem.
|
20
20
|
thorfile_path = File.join(template_dir, 'Thorfile')
|
21
21
|
thorfile_content = File.read(thorfile_path)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
{ # replace thorfile content:
|
23
|
+
"require 'breeze'" => "require 'bundler'; Bundler.setup; require 'breeze'",
|
24
|
+
"'THE-NAME-OF-YOUR-KEYPAIR'" => 'nil'
|
25
|
+
}.each do |expected, wanted|
|
26
|
+
raise "Cannot find #{expected} in #{thorfile_path}" unless thorfile_content.include?(expected)
|
27
|
+
thorfile_content.sub!(expected, wanted)
|
28
|
+
end
|
29
|
+
File.open(thorfile_path, 'w') { |f| f.puts(thorfile_content) }
|
26
30
|
|
27
31
|
# Use Fog.mock!
|
28
32
|
system("echo 'Fog.mock!' >> #{thorfile_path}")
|
@@ -30,4 +34,5 @@ system("echo 'Fog.mock!' >> #{thorfile_path}")
|
|
30
34
|
# Clone the test app for each scenario.
|
31
35
|
Before do
|
32
36
|
system("cp -r #{template_dir} tmp/aruba")
|
37
|
+
@aruba_timeout_seconds = 5
|
33
38
|
end
|
data/lib/breeze.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require 'fog/
|
2
|
-
require 'fog/
|
1
|
+
require 'fog/aws/models/compute/server'
|
2
|
+
require 'fog/aws/models/compute/image'
|
3
3
|
|
4
4
|
module Fog
|
5
5
|
|
6
|
-
module
|
7
|
-
class
|
6
|
+
module Compute
|
7
|
+
class AWS::Server
|
8
8
|
|
9
9
|
def name
|
10
10
|
breeze_data['name'] || tags['Name']
|
@@ -54,7 +54,7 @@ module Fog
|
|
54
54
|
end
|
55
55
|
|
56
56
|
end
|
57
|
-
class
|
57
|
+
class AWS::Image
|
58
58
|
|
59
59
|
def display_name
|
60
60
|
name or location
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'breeze/fog_extensions'
|
2
|
+
module Breeze
|
3
|
+
|
4
|
+
# The fog wrapper makes it possible for subsequent shell commands
|
5
|
+
# to share the same fog mock session. If Fog.mocking? is true, the
|
6
|
+
# mock data is read from and written to a yaml file.
|
7
|
+
module FogWrapper
|
8
|
+
|
9
|
+
def self.connection(type)
|
10
|
+
{:compute => Compute, :rds => RDS}[type].get_connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.flush_mock_data!
|
14
|
+
Compute.new.flush_data!
|
15
|
+
# RDS.new.flush_data!
|
16
|
+
end
|
17
|
+
|
18
|
+
class AbstractConnectionWrapper
|
19
|
+
|
20
|
+
def self.get_connection
|
21
|
+
Fog.mocking? ? new : direct_fog_connection
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(*args)
|
25
|
+
load_data
|
26
|
+
return_value = fog.send(*args)
|
27
|
+
flush_data!
|
28
|
+
return_value
|
29
|
+
end
|
30
|
+
|
31
|
+
def flush_data!
|
32
|
+
File.open(data_file, 'w') { |f| YAML::dump(get_data, f) }
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def fog
|
38
|
+
@fog ||= self.class.direct_fog_connection
|
39
|
+
end
|
40
|
+
def load_data
|
41
|
+
set_data(YAML::load_file(data_file)) if File.exists?(data_file)
|
42
|
+
end
|
43
|
+
def get_data
|
44
|
+
mock_class.instance_variable_get('@data')
|
45
|
+
end
|
46
|
+
def set_data(data)
|
47
|
+
mock_class.instance_variable_set('@data', data)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Compute < AbstractConnectionWrapper
|
52
|
+
def self.direct_fog_connection
|
53
|
+
Fog::Compute.new(CONFIGURATION[:cloud_service])
|
54
|
+
end
|
55
|
+
private
|
56
|
+
def data_file ; 'fog_compute_data.yaml' ; end
|
57
|
+
def mock_class ; Fog::Compute::AWS::Mock ; end
|
58
|
+
end
|
59
|
+
|
60
|
+
# TODO: add RDS mocks to fog so that we can start testing it
|
61
|
+
class RDS < AbstractConnectionWrapper
|
62
|
+
def self.direct_fog_connection
|
63
|
+
credentials = CONFIGURATION[:cloud_service].reject{ |k,v| k == :provider }
|
64
|
+
credentials[:region] = CONFIGURATION[:db_region]
|
65
|
+
Fog::AWS::RDS.new(credentials)
|
66
|
+
end
|
67
|
+
private
|
68
|
+
def data_file ; 'fog_rds_data.yaml' ; end
|
69
|
+
def mock_class ; Fog::AWS::RDS::Mock ; end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
data/lib/breeze/tasks/server.rb
CHANGED
@@ -33,17 +33,19 @@ module Breeze
|
|
33
33
|
server = fog.servers.create(options)
|
34
34
|
print "Launching server #{server.id}"
|
35
35
|
wait_until('running!') { server.running? }
|
36
|
+
FogWrapper.flush_mock_data! if Fog.mocking?
|
36
37
|
return server
|
37
38
|
end
|
38
39
|
|
39
40
|
# Can take a host name or an ip address. Resolves the host name
|
40
41
|
# and returns the ip address if get_ip is passed in as true.
|
41
42
|
def wait_until_host_is_available(host, get_ip=false)
|
42
|
-
|
43
|
+
resolved_host = Resolv.getaddresses(host).first
|
44
|
+
if resolved_host.nil?
|
43
45
|
print("Waiting for #{host} to resolve")
|
44
|
-
wait_until('ready!') { Resolv.getaddresses(host).
|
46
|
+
wait_until('ready!') { resolved_host = Resolv.getaddresses(host).first }
|
45
47
|
end
|
46
|
-
host =
|
48
|
+
host = resolved_host if get_ip
|
47
49
|
unless remote_is_available?(host)
|
48
50
|
print("Waiting for #{host} to accept connections")
|
49
51
|
wait_until('ready!') { remote_is_available?(host) }
|
data/lib/breeze/veur.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'breeze/
|
1
|
+
require 'breeze/fog_wrapper'
|
2
2
|
|
3
3
|
module Breeze
|
4
4
|
|
@@ -38,7 +38,14 @@ module Breeze
|
|
38
38
|
# wait_until { my_task.completed? }
|
39
39
|
def wait_until(message='completed!')
|
40
40
|
3.times { dot_and_sleep(1) }
|
41
|
-
|
41
|
+
begin
|
42
|
+
dot_and_sleep(2) until yield
|
43
|
+
rescue Excon::Errors::SocketError => e
|
44
|
+
# print out the error so the user can interrupt if necessary
|
45
|
+
print "#{e.class}: #{e.message}! Retry:"
|
46
|
+
sleep(1)
|
47
|
+
retry
|
48
|
+
end
|
42
49
|
puts message
|
43
50
|
end
|
44
51
|
|
@@ -68,7 +75,7 @@ module Breeze
|
|
68
75
|
end
|
69
76
|
|
70
77
|
def fog
|
71
|
-
@fog ||=
|
78
|
+
@fog ||= Breeze::FogWrapper.connection(:compute)
|
72
79
|
end
|
73
80
|
|
74
81
|
def dns
|
@@ -76,10 +83,7 @@ module Breeze
|
|
76
83
|
end
|
77
84
|
|
78
85
|
def rds
|
79
|
-
|
80
|
-
credentials = CONFIGURATION[:cloud_service].reject{ |k,v| k == :provider }
|
81
|
-
credentials[:region] = CONFIGURATION[:db_region]
|
82
|
-
@rds = Fog::AWS::RDS.new(credentials)
|
86
|
+
@rds ||= Breeze::FogWrapper.connection(:rds)
|
83
87
|
end
|
84
88
|
|
85
89
|
end
|
metadata
CHANGED
@@ -1,89 +1,76 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: breeze
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 4
|
9
|
-
version: 0.0.4
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Markus Bengts
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2012-01-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: thor
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70318976130880 !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
- 0
|
30
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
31
22
|
type: :runtime
|
32
|
-
version_requirements: *id001
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: fog
|
35
23
|
prerelease: false
|
36
|
-
|
24
|
+
version_requirements: *70318976130880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: fog
|
27
|
+
requirement: &70318976130460 !ruby/object:Gem::Requirement
|
37
28
|
none: false
|
38
|
-
requirements:
|
39
|
-
- -
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
- 0
|
43
|
-
- 7
|
44
|
-
version: "0.7"
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
45
33
|
type: :runtime
|
46
|
-
version_requirements: *id002
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: cucumber
|
49
34
|
prerelease: false
|
50
|
-
|
35
|
+
version_requirements: *70318976130460
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: cucumber
|
38
|
+
requirement: &70318976146200 !ruby/object:Gem::Requirement
|
51
39
|
none: false
|
52
|
-
requirements:
|
53
|
-
- -
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
|
56
|
-
- 0
|
57
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
58
44
|
type: :development
|
59
|
-
version_requirements: *id003
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: aruba
|
62
45
|
prerelease: false
|
63
|
-
|
46
|
+
version_requirements: *70318976146200
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: aruba
|
49
|
+
requirement: &70318976145400 !ruby/object:Gem::Requirement
|
64
50
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
- 0
|
70
|
-
version: "0"
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
71
55
|
type: :development
|
72
|
-
|
73
|
-
|
74
|
-
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70318976145400
|
58
|
+
description: ! 'Breeze makes it easy to automate server installation and configuration.
|
59
|
+
It provides
|
60
|
+
|
75
61
|
example scripts and configuration files that you can modify and keep in your revision
|
76
|
-
control system. Thor tasks are provided to create server images, launch server instances etc.
|
77
62
|
|
78
|
-
|
63
|
+
control system. Thor tasks are provided to create server images, launch server instances
|
64
|
+
etc.
|
65
|
+
|
66
|
+
'
|
67
|
+
email:
|
79
68
|
- markus.bengts@gmail.com
|
80
|
-
executables:
|
69
|
+
executables:
|
81
70
|
- breeze
|
82
71
|
extensions: []
|
83
|
-
|
84
72
|
extra_rdoc_files: []
|
85
|
-
|
86
|
-
files:
|
73
|
+
files:
|
87
74
|
- .gitignore
|
88
75
|
- Gemfile
|
89
76
|
- LICENSE
|
@@ -92,10 +79,14 @@ files:
|
|
92
79
|
- bin/breeze
|
93
80
|
- breeze.gemspec
|
94
81
|
- features/erb_conf.feature
|
82
|
+
- features/getting_started.feature
|
83
|
+
- features/step_definitions/application_steps.rb
|
84
|
+
- features/step_definitions/server_steps.rb
|
95
85
|
- features/support/env.rb
|
96
86
|
- lib/breeze.rb
|
97
87
|
- lib/breeze/fog_extensions.rb
|
98
88
|
- lib/breeze/fog_extensions/aws.rb
|
89
|
+
- lib/breeze/fog_wrapper.rb
|
99
90
|
- lib/breeze/initializer.rb
|
100
91
|
- lib/breeze/tasks.rb
|
101
92
|
- lib/breeze/tasks/app.rb
|
@@ -125,38 +116,33 @@ files:
|
|
125
116
|
- lib/templates/shared/scripts/deploy.sh
|
126
117
|
- lib/templates/shared/scripts/install.sh
|
127
118
|
- lib/templates/user_data.sh
|
128
|
-
has_rdoc: true
|
129
119
|
homepage: https://github.com/markus/breeze
|
130
120
|
licenses: []
|
131
|
-
|
132
121
|
post_install_message:
|
133
122
|
rdoc_options: []
|
134
|
-
|
135
|
-
require_paths:
|
123
|
+
require_paths:
|
136
124
|
- lib
|
137
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
126
|
none: false
|
139
|
-
requirements:
|
140
|
-
- -
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
|
143
|
-
|
144
|
-
version: "0"
|
145
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
132
|
none: false
|
147
|
-
requirements:
|
148
|
-
- -
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
|
151
|
-
- 0
|
152
|
-
version: "0"
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
153
137
|
requirements: []
|
154
|
-
|
155
138
|
rubyforge_project: breeze
|
156
|
-
rubygems_version: 1.
|
139
|
+
rubygems_version: 1.8.11
|
157
140
|
signing_key:
|
158
141
|
specification_version: 3
|
159
142
|
summary: Thor tasks to manage cloud computing resources and deployments
|
160
|
-
test_files:
|
143
|
+
test_files:
|
161
144
|
- features/erb_conf.feature
|
145
|
+
- features/getting_started.feature
|
146
|
+
- features/step_definitions/application_steps.rb
|
147
|
+
- features/step_definitions/server_steps.rb
|
162
148
|
- features/support/env.rb
|