capify-cloud 1.5.0.pre.1
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 +4 -0
- data/Changelog.md +121 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/Rakefile +2 -0
- data/capify-cloud.gemspec +24 -0
- data/lib/capify-cloud/capistrano.rb +146 -0
- data/lib/capify-cloud/server.rb +49 -0
- data/lib/capify-cloud/version.rb +6 -0
- data/lib/capify-cloud.rb +146 -0
- data/readme.md +207 -0
- metadata +124 -0
data/.gitignore
ADDED
data/Changelog.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
## 1.5.0 (July 9, 2012)
|
2
|
+
|
3
|
+
Notes:
|
4
|
+
|
5
|
+
- Added support for Brightbox deployment
|
6
|
+
- Change name of ec2.yml to cloud.yml
|
7
|
+
- Major change to cloud.yml to reflect Brightbox change
|
8
|
+
- Defaults to ec2 usage, still
|
9
|
+
- Don't display DNS name, only IP address, when running ec2:status
|
10
|
+
- Added Cloud Provider to ec2:status
|
11
|
+
- Added tags capability to Brightbox. Uses hack in Groups which contain a ":"
|
12
|
+
- Updated Readme
|
13
|
+
|
14
|
+
## 1.2.9 (June 29, 2012)
|
15
|
+
|
16
|
+
Bugfixes:
|
17
|
+
|
18
|
+
- No longer throws an error when a server has no name.
|
19
|
+
|
20
|
+
## 1.2.8 (May 16, 2012)
|
21
|
+
|
22
|
+
Notes:
|
23
|
+
|
24
|
+
- Minor refactoring to make the code clearer
|
25
|
+
- Updated code to allow commas and any amount of whitespace between options and roles (Thanks ennui2342)
|
26
|
+
- Updated documentation to reflect multiple correct formats.
|
27
|
+
|
28
|
+
Bugfixes:
|
29
|
+
|
30
|
+
## 1.2.5 (Jan 26, 2012)
|
31
|
+
|
32
|
+
Features:
|
33
|
+
|
34
|
+
- Added ability to connect to VPC instances. Very basic functionality.
|
35
|
+
|
36
|
+
## 1.2.4 (Jan 24, 2012)
|
37
|
+
|
38
|
+
Features:
|
39
|
+
|
40
|
+
- Remove handling of singular 'role.' It was causing unnecessary difficulties.
|
41
|
+
|
42
|
+
Bugfixes:
|
43
|
+
|
44
|
+
- Options flag not properly recognized.
|
45
|
+
- Fixed longstanding issue of handling comma-separated roles
|
46
|
+
|
47
|
+
## 1.2.2 (Dec 05, 2011)
|
48
|
+
|
49
|
+
Bugfixes:
|
50
|
+
|
51
|
+
- Mismatch between ec2:status and ec2:ssh lead to connecting to the wrong server.
|
52
|
+
|
53
|
+
## 1.2.1 (Dec 02, 2011)
|
54
|
+
|
55
|
+
Bugfixes:
|
56
|
+
|
57
|
+
- Regression bug fixed. Projects weren't being filtered properly.
|
58
|
+
|
59
|
+
## 1.2.0 (Dec 02, 2011)
|
60
|
+
|
61
|
+
Features:
|
62
|
+
|
63
|
+
- Much improved performance
|
64
|
+
- US-West-1 now available (fog upgrade)
|
65
|
+
|
66
|
+
## 1.1.16 (Sep 23, 2011)
|
67
|
+
|
68
|
+
Features:
|
69
|
+
|
70
|
+
- Added 'option' handling. Allows users to move cap options ('cron,' 'db,' 'resque,' etc.) to 'Option' field at AWS.
|
71
|
+
|
72
|
+
## 1.1.15 (Sep 02, 2011)
|
73
|
+
|
74
|
+
Bugfixes:
|
75
|
+
|
76
|
+
- Fixed problem with ec2:ssh task not terminating properly
|
77
|
+
|
78
|
+
## 1.1.14 (Aug 24, 2011)
|
79
|
+
|
80
|
+
Bugfixes:
|
81
|
+
|
82
|
+
- Fixed chaining of tasks
|
83
|
+
- Fixed handling of defaults and their interactions with specified tasks (particularly across regions)
|
84
|
+
|
85
|
+
Features:
|
86
|
+
|
87
|
+
- Moved the following to ec2 namespace to make it clearer what's part of the gem
|
88
|
+
- status (formerly ec2_status)
|
89
|
+
- register_instance
|
90
|
+
- deregister_instance
|
91
|
+
- date
|
92
|
+
- server_names
|
93
|
+
|
94
|
+
|
95
|
+
## 1.1.13 (Aug 10, 2011)
|
96
|
+
|
97
|
+
Bugfixes:
|
98
|
+
|
99
|
+
- Obscure bug fixed. Multiple roles where some instances weren't in all roles would throw an error if you tried to tell a task to only fire when particular roles were deployed to. This bug only fired if you performed your action on a single instance (cap server deploy).
|
100
|
+
|
101
|
+
## 1.1.12 (Aug 09, 2011)
|
102
|
+
|
103
|
+
Features:
|
104
|
+
|
105
|
+
- Add ability to deploy to all similar roles in a region
|
106
|
+
- Add ability to cap ssh <ec2 index number>
|
107
|
+
- Add ability to cap ssh <instance name>
|
108
|
+
- Froze dependencies to known working gems
|
109
|
+
- Allow cap deploy with a server set as default
|
110
|
+
- Added descriptions (try cap -T)
|
111
|
+
- Fix gem dependencies for cap ec2_status
|
112
|
+
- Allows registering and deregistering of instances with an ELB
|
113
|
+
- Servers can have Role or Roles on ec2
|
114
|
+
|
115
|
+
|
116
|
+
Bugfixes:
|
117
|
+
|
118
|
+
- Allow options to be passed to ec2_roles
|
119
|
+
- Deregister and register server with elb
|
120
|
+
- Fixed server_names directive to display case insensitive names. Matches with ssh
|
121
|
+
- Defaults no longer break options
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Forward
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "capify-cloud/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "capify-cloud"
|
7
|
+
s.version = Capify::Cloud::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Noah Cantor"]
|
10
|
+
s.email = ["ncantor@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/ncantor/capify-cloud"
|
12
|
+
s.summary = %q{Grabs roles from clouds' meta-data and autogenerates capistrano tasks}
|
13
|
+
s.description = %q{Grabs roles from clouds' meta-data and autogenerates capistrano tasks}
|
14
|
+
|
15
|
+
s.rubyforge_project = "capify-cloud"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_dependency('fog', '=1.4.0')
|
22
|
+
s.add_dependency('colored', '=1.2')
|
23
|
+
s.add_dependency('capistrano')
|
24
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../capify-cloud')
|
2
|
+
require 'colored'
|
3
|
+
|
4
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
5
|
+
def capify_cloud
|
6
|
+
@capify_cloud ||= CapifyCloud.new(fetch(:cloud_config, 'config/cloud.yml'))
|
7
|
+
end
|
8
|
+
|
9
|
+
namespace :cloud do
|
10
|
+
|
11
|
+
desc "Prints out all cloud instances. index, name, instance_id, size, DNS/IP, region, tags"
|
12
|
+
task :status do
|
13
|
+
capify_cloud.display_instances
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Deregisters instance from its ELB"
|
17
|
+
task :deregister_instance do
|
18
|
+
instance_name = variables[:logger].instance_variable_get("@options")[:actions].first
|
19
|
+
capify_cloud.deregister_instance_from_elb(instance_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Registers an instance with an ELB."
|
23
|
+
task :register_instance do
|
24
|
+
instance_name = variables[:logger].instance_variable_get("@options")[:actions].first
|
25
|
+
load_balancer_name = variables[:logger].instance_variable_get("@options")[:vars][:loadbalancer]
|
26
|
+
capify_cloud.register_instance_in_elb(instance_name, load_balancer_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
task :date do
|
30
|
+
run "date"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Prints list of cloud server names"
|
34
|
+
task :server_names do
|
35
|
+
puts capify_cloud.server_names.sort
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Allows ssh to instance by id. cap ssh <INSTANCE NAME>"
|
39
|
+
task :ssh do
|
40
|
+
server = variables[:logger].instance_variable_get("@options")[:actions][1]
|
41
|
+
instance = numeric?(server) ? capify_cloud.desired_instances[server.to_i] : capify_cloud.get_instance_by_name(server)
|
42
|
+
port = ssh_options[:port] || 22
|
43
|
+
command = "ssh -p #{port} #{user}@#{instance.contact_point}"
|
44
|
+
puts "Running `#{command}`"
|
45
|
+
exec(command)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
namespace :deploy do
|
50
|
+
before "deploy", "cloud:deregister_instance"
|
51
|
+
after "deploy", "cloud:register_instance"
|
52
|
+
after "deploy:rollback", "cloud:register_instance"
|
53
|
+
end
|
54
|
+
|
55
|
+
def cloud_roles(*roles)
|
56
|
+
server_name = variables[:logger].instance_variable_get("@options")[:actions].first unless variables[:logger].instance_variable_get("@options")[:actions][1].nil?
|
57
|
+
|
58
|
+
if !server_name.nil?
|
59
|
+
named_instance = capify_cloud.get_instance_by_name(server_name)
|
60
|
+
|
61
|
+
task named_instance.name.to_sym do
|
62
|
+
remove_default_roles
|
63
|
+
server_address = named_instance.contact_point
|
64
|
+
named_instance.roles.each do |role|
|
65
|
+
define_role({:name => role, :options => {:on_no_matching_servers => :continue}}, named_instance)
|
66
|
+
end
|
67
|
+
end unless named_instance.nil?
|
68
|
+
end
|
69
|
+
roles.each {|role| cloud_role(role)}
|
70
|
+
end
|
71
|
+
|
72
|
+
def cloud_role(role_name_or_hash)
|
73
|
+
role = role_name_or_hash.is_a?(Hash) ? role_name_or_hash : {:name => role_name_or_hash,:options => {}}
|
74
|
+
@roles[role[:name]]
|
75
|
+
|
76
|
+
instances = capify_cloud.get_instances_by_role(role[:name])
|
77
|
+
if role[:options].delete(:default)
|
78
|
+
instances.each do |instance|
|
79
|
+
define_role(role, instance)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
regions = capify_cloud.determine_regions
|
83
|
+
regions.each do |region|
|
84
|
+
define_regions(region, role)
|
85
|
+
end unless regions.nil?
|
86
|
+
|
87
|
+
define_role_roles(role, instances)
|
88
|
+
define_instance_roles(role, instances)
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
def define_regions(region, role)
|
93
|
+
instances = []
|
94
|
+
@roles.each do |role_name, junk|
|
95
|
+
region_instances = capify_cloud.get_instances_by_region(role_name, region)
|
96
|
+
region_instances.each {|instance| instances << instance} unless region_instances.nil?
|
97
|
+
end
|
98
|
+
task region.to_sym do
|
99
|
+
remove_default_roles
|
100
|
+
instances.each do |instance|
|
101
|
+
define_role(role, instance)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def define_instance_roles(role, instances)
|
107
|
+
instances.each do |instance|
|
108
|
+
task instance.name.to_sym do
|
109
|
+
remove_default_roles
|
110
|
+
define_role(role, instance)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def define_role_roles(role, instances)
|
116
|
+
task role[:name].to_sym do
|
117
|
+
remove_default_roles
|
118
|
+
instances.each do |instance|
|
119
|
+
define_role(role, instance)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def define_role(role, instance)
|
125
|
+
options = role[:options]
|
126
|
+
new_options = {}
|
127
|
+
options.each {|key, value| new_options[key] = true if value.to_s == instance.name}
|
128
|
+
instance.tags["Options"].split(%r{,\s*}).each { |option| new_options[option.to_sym] = true} rescue false
|
129
|
+
|
130
|
+
if new_options
|
131
|
+
role role[:name].to_sym, instance.contact_point, new_options
|
132
|
+
else
|
133
|
+
role role[:name].to_sym, instance.contact_point
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def numeric?(object)
|
138
|
+
true if Float(object) rescue false
|
139
|
+
end
|
140
|
+
|
141
|
+
def remove_default_roles
|
142
|
+
roles.reject! { true }
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fog/aws/models/compute/server'
|
3
|
+
require 'fog/brightbox/models/compute/server'
|
4
|
+
|
5
|
+
module Fog
|
6
|
+
module Compute
|
7
|
+
class AWS
|
8
|
+
class Server
|
9
|
+
def contact_point
|
10
|
+
public_ip_address || private_ip_address
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
tags["Name"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def zone_id
|
18
|
+
availability_zone
|
19
|
+
end
|
20
|
+
|
21
|
+
def provider
|
22
|
+
'AWS'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
class Brightbox
|
27
|
+
class Server
|
28
|
+
def contact_point
|
29
|
+
public_ip_address || private_ip_address
|
30
|
+
end
|
31
|
+
|
32
|
+
def tags
|
33
|
+
tags = server_groups.map {|server_group| server_group["name"]}.select{|tag| tag.include?(":")}
|
34
|
+
tags_hash = tags.inject({}) do |map, individual|
|
35
|
+
key, value = individual.split(":")
|
36
|
+
map[key] = value
|
37
|
+
map
|
38
|
+
end
|
39
|
+
tags_hash
|
40
|
+
end
|
41
|
+
|
42
|
+
def provider
|
43
|
+
'Brightbox'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
data/lib/capify-cloud.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fog'
|
3
|
+
require 'colored'
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/capify-cloud/server')
|
5
|
+
|
6
|
+
|
7
|
+
class CapifyCloud
|
8
|
+
|
9
|
+
attr_accessor :load_balancer, :instances
|
10
|
+
SLEEP_COUNT = 5
|
11
|
+
|
12
|
+
def initialize(cloud_config = "config/cloud.yml")
|
13
|
+
case cloud_config
|
14
|
+
when Hash
|
15
|
+
@cloud_config = cloud_config
|
16
|
+
when String
|
17
|
+
@cloud_config = YAML.load_file cloud_config
|
18
|
+
else
|
19
|
+
raise ArgumentError, "Invalid cloud_config: #{cloud_config.inspect}"
|
20
|
+
end
|
21
|
+
|
22
|
+
@cloud_providers = @cloud_config[:cloud_providers]
|
23
|
+
|
24
|
+
@instances = []
|
25
|
+
@cloud_providers.each do |cloud_provider|
|
26
|
+
config = @cloud_config[cloud_provider.to_sym]
|
27
|
+
case cloud_provider
|
28
|
+
when 'Brightbox'
|
29
|
+
servers = Fog::Compute.new(:provider => cloud_provider, :brightbox_client_id => config[:brightbox_client_id],
|
30
|
+
:brightbox_secret => config[:brightbox_secret]).servers
|
31
|
+
servers.each do |server|
|
32
|
+
@instances << server if server.ready?
|
33
|
+
end
|
34
|
+
else
|
35
|
+
regions = determine_regions(cloud_provider)
|
36
|
+
regions.each do |region|
|
37
|
+
servers = Fog::Compute.new(:provider => cloud_provider, :aws_access_key_id => config[:aws_access_key_id],
|
38
|
+
:aws_secret_access_key => config[:aws_secret_access_key], :region => region).servers
|
39
|
+
servers.each do |server|
|
40
|
+
@instances << server if server.ready?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def determine_regions(cloud_provider = 'AWS')
|
48
|
+
@cloud_config[cloud_provider.to_sym][:params][:regions] || [@cloud_config[cloud_provider.to_sym][:params][:region]]
|
49
|
+
end
|
50
|
+
|
51
|
+
def display_instances
|
52
|
+
desired_instances.each_with_index do |instance, i|
|
53
|
+
puts sprintf "%02d: %-40s %-20s %-20s %-20s %-25s %-20s (%s) (%s)",
|
54
|
+
i, (instance.name || "").green, instance.provider.yellow, instance.id.red, instance.flavor_id.cyan,
|
55
|
+
instance.contact_point.blue, instance.zone_id.magenta, (instance.tags["Roles"] || "").yellow,
|
56
|
+
(instance.tags["Options"] || "").yellow
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def server_names
|
61
|
+
desired_instances.map {|instance| instance.name}
|
62
|
+
end
|
63
|
+
|
64
|
+
def project_instances
|
65
|
+
@instances.select {|instance| instance.tags["Project"] == @cloud_config[:project_tag]}
|
66
|
+
end
|
67
|
+
|
68
|
+
def desired_instances
|
69
|
+
@cloud_config[:project_tag].nil? ? @instances : project_instances
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_instances_by_role(role)
|
73
|
+
desired_instances.select {|instance| instance.tags['Roles'].split(%r{,\s*}).include?(role.to_s) rescue false}
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_instances_by_region(roles, region)
|
77
|
+
return unless region
|
78
|
+
desired_instances.select {|instance| instance.availability_zone.match(region) && instance.roles == roles.to_s rescue false}
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_instance_by_name(name)
|
82
|
+
desired_instances.select {|instance| instance.name == name}.first
|
83
|
+
end
|
84
|
+
|
85
|
+
def instance_health(load_balancer, instance)
|
86
|
+
elb.describe_instance_health(load_balancer.id, instance.id).body['DescribeInstanceHealthResult']['InstanceStates'][0]['State']
|
87
|
+
end
|
88
|
+
|
89
|
+
def elb
|
90
|
+
Fog::AWS::ELB.new(:aws_access_key_id => @cloud_config[:aws_access_key_id], :aws_secret_access_key => @cloud_config[:aws_secret_access_key], :region => @cloud_config[:aws_params][:region])
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_load_balancer_by_instance(instance_id)
|
94
|
+
hash = elb.load_balancers.inject({}) do |collect, load_balancer|
|
95
|
+
load_balancer.instances.each {|load_balancer_instance_id| collect[load_balancer_instance_id] = load_balancer}
|
96
|
+
collect
|
97
|
+
end
|
98
|
+
hash[instance_id]
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_load_balancer_by_name(load_balancer_name)
|
102
|
+
lbs = {}
|
103
|
+
elb.load_balancers.each do |load_balancer|
|
104
|
+
lbs[load_balancer.id] = load_balancer
|
105
|
+
end
|
106
|
+
lbs[load_balancer_name]
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def deregister_instance_from_elb(instance_name)
|
111
|
+
return unless @cloud_config[:load_balanced]
|
112
|
+
instance = get_instance_by_name(instance_name)
|
113
|
+
return if instance.nil?
|
114
|
+
@@load_balancer = get_load_balancer_by_instance(instance.id)
|
115
|
+
return if @@load_balancer.nil?
|
116
|
+
|
117
|
+
elb.deregister_instances_from_load_balancer(instance.id, @@load_balancer.id)
|
118
|
+
end
|
119
|
+
|
120
|
+
def register_instance_in_elb(instance_name, load_balancer_name = '')
|
121
|
+
return if !@cloud_config[:load_balanced]
|
122
|
+
instance = get_instance_by_name(instance_name)
|
123
|
+
return if instance.nil?
|
124
|
+
load_balancer = get_load_balancer_by_name(load_balancer_name) || @@load_balancer
|
125
|
+
return if load_balancer.nil?
|
126
|
+
|
127
|
+
elb.register_instances_with_load_balancer(instance.id, load_balancer.id)
|
128
|
+
|
129
|
+
fail_after = @cloud_config[:fail_after] || 30
|
130
|
+
state = instance_health(load_balancer, instance)
|
131
|
+
time_elapsed = 0
|
132
|
+
|
133
|
+
while time_elapsed < fail_after
|
134
|
+
break if state == "InService"
|
135
|
+
sleep SLEEP_COUNT
|
136
|
+
time_elapsed += SLEEP_COUNT
|
137
|
+
STDERR.puts 'Verifying Instance Health'
|
138
|
+
state = instance_health(load_balancer, instance)
|
139
|
+
end
|
140
|
+
if state == 'InService'
|
141
|
+
STDERR.puts "#{instance.name}: Healthy"
|
142
|
+
else
|
143
|
+
STDERR.puts "#{instance.name}: tests timed out after #{time_elapsed} seconds."
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
Capify Cloud
|
2
|
+
====================================================
|
3
|
+
|
4
|
+
capify-cloud is used to generate capistrano namespaces using ec2 tags and a hack with Brightbox server-groups to emulate tags.
|
5
|
+
Tags are simulated on Brightbox using a server_group containing a ":" (e.g. Roles:web)
|
6
|
+
|
7
|
+
eg: If you have 2 servers on amazon's ec2 and a DB server at Brightbox
|
8
|
+
|
9
|
+
server-1 Tag: Roles => "web", Options => "cron,resque, db"
|
10
|
+
server-2 Server-Group: Roles:db
|
11
|
+
server-3 Tag: Roles => "web,db, app"
|
12
|
+
|
13
|
+
Installing
|
14
|
+
|
15
|
+
gem install capify-cloud
|
16
|
+
|
17
|
+
In your deploy.rb:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require "capify-cloud/capistrano"
|
21
|
+
cloud_roles :web
|
22
|
+
```
|
23
|
+
|
24
|
+
Will generate
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
task :server-1 do
|
28
|
+
role :web, {server-1 public dns fetched from Amazon}, :cron=>true, :resque=>true
|
29
|
+
end
|
30
|
+
|
31
|
+
task :server-3 do
|
32
|
+
role :web, {server-1 public dns fetched from Amazon}
|
33
|
+
end
|
34
|
+
|
35
|
+
task :web do
|
36
|
+
role :web, {server-1 public dns fetched from Amazon}, :cron=>true, :resque=>true
|
37
|
+
role :web, {server-3 public dns fetched from Amazon}
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
Additionally
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require "capify-cloud/capistrano"
|
45
|
+
cloud_roles :db
|
46
|
+
```
|
47
|
+
|
48
|
+
Will generate
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
task :server-2 do
|
52
|
+
role :db, {server-2 public or private IP, fetched from Brightbox}
|
53
|
+
end
|
54
|
+
|
55
|
+
task :server-3 do
|
56
|
+
role :db, {server-3 public dns fetched from Amazon}
|
57
|
+
end
|
58
|
+
|
59
|
+
task :db do
|
60
|
+
role :db, {server-2 public or private IP, fetched from Brightbox}
|
61
|
+
role :db, {server-3 public dns fetched from Amazon}
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
Running
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
cap web cloud:date
|
69
|
+
```
|
70
|
+
|
71
|
+
will run the date command on all server's tagged with the web role
|
72
|
+
|
73
|
+
Running
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
cap server-1 cloud:register_instance -s loadbalancer=elb-1
|
77
|
+
```
|
78
|
+
|
79
|
+
will register server-1 to be used by elb-1
|
80
|
+
|
81
|
+
Running
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
cap server-1 cloud:deregister_instance
|
85
|
+
```
|
86
|
+
|
87
|
+
will remove server-1 from whatever instance it is currently
|
88
|
+
registered against.
|
89
|
+
|
90
|
+
Running
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
cap cloud:status
|
94
|
+
```
|
95
|
+
|
96
|
+
will list the currently running servers and their associated details
|
97
|
+
(public dns, instance id, roles etc)
|
98
|
+
|
99
|
+
Running
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
cap cloud:ssh #
|
103
|
+
```
|
104
|
+
|
105
|
+
will launch ssh using the user and port specified in your configuration.
|
106
|
+
The # argument is the index of the server to ssh into. Use the 'cloud:status'
|
107
|
+
command to see the list of servers with their indices.
|
108
|
+
|
109
|
+
More options
|
110
|
+
====================================================
|
111
|
+
|
112
|
+
In addition to specifying options (e.g. 'cron') at the server level, it is also possible to specify it at the project level.
|
113
|
+
Use with caution! This does not work with autoscaling.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
cloud_roles {:name=>"web", :options=>{:cron=>"server-1"}}
|
117
|
+
```
|
118
|
+
|
119
|
+
Will generate
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
task :server-1 do
|
123
|
+
role :web, {server-1 public dns fetched from Amazon}, :cron=>true
|
124
|
+
end
|
125
|
+
|
126
|
+
task :server-3 do
|
127
|
+
role :web, {server-1 public dns fetched from Amazon}
|
128
|
+
end
|
129
|
+
|
130
|
+
task :web do
|
131
|
+
role :web, {server-1 public dns fetched from Amazon}, :cron=>true
|
132
|
+
role :web, {server-3 public dns fetched from Amazon}
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
Which is cool if you want a task like this in deploy.rb
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
task :update_cron => :web, :only=>{:cron} do
|
140
|
+
Do something to a server with cron on it
|
141
|
+
end
|
142
|
+
|
143
|
+
cloud_roles :name=>:web, :options=>{ :default => true }
|
144
|
+
```
|
145
|
+
|
146
|
+
Will make :web the default role so you can just type 'cap deploy'.
|
147
|
+
Multiple roles can be defaults so:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
cloud_roles :name=>:web, :options=>{ :default => true }
|
151
|
+
cloud_roles :name=>:app, :options=>{ :default => true }
|
152
|
+
```
|
153
|
+
|
154
|
+
would be the equivalent of 'cap app web deploy'
|
155
|
+
|
156
|
+
Cloud config
|
157
|
+
====================================================
|
158
|
+
|
159
|
+
This gem requires 'config/cloud.yml' in your project.
|
160
|
+
The yml file needs to look something like this:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
:cloud_providers: ['AWS', 'Brightbox']
|
164
|
+
|
165
|
+
:AWS:
|
166
|
+
:aws_access_key_id: "YOUR ACCESS KEY"
|
167
|
+
:aws_secret_access_key: "YOUR SECRET"
|
168
|
+
:params:
|
169
|
+
:region: 'eu-west-1'
|
170
|
+
:load_balanced: true
|
171
|
+
:project_tag: "YOUR APP NAME"
|
172
|
+
|
173
|
+
:Brightbox:
|
174
|
+
:brightbox_client_id: "YOUR CLIENT ID"
|
175
|
+
:brightbox_secret: "YOUR SECRET"
|
176
|
+
```
|
177
|
+
aws_access_key_id, aws_secret_access_key, and region are required for AWS. Other settings are optional.
|
178
|
+
brightbox_client_id and brightbox_secret: are required for Brightbox.
|
179
|
+
If you do not specify a cloud_provider, AWS is assumed.
|
180
|
+
|
181
|
+
If :load_balanced is set to true, the gem uses pre and post-deploy
|
182
|
+
hooks to deregister the instance, reregister it, and validate its
|
183
|
+
health.
|
184
|
+
:load_balanced only works for individual instances, not for roles.
|
185
|
+
|
186
|
+
The :project_tag parameter is optional. It will limit any commands to
|
187
|
+
running against those instances with a "Project" tag set to the value
|
188
|
+
"YOUR APP NAME".
|
189
|
+
|
190
|
+
## Development
|
191
|
+
|
192
|
+
Source hosted at [GitHub](http://github.com/ncantor/capify-cloud).
|
193
|
+
Report Issues/Feature requests on [GitHub Issues](http://github.com/ncantor/capify-cloud/issues).
|
194
|
+
|
195
|
+
### Note on Patches/Pull Requests
|
196
|
+
|
197
|
+
* Fork the project.
|
198
|
+
* Make your feature addition or bug fix.
|
199
|
+
* Add tests for it. This is important so I don't break it in a
|
200
|
+
future version unintentionally.
|
201
|
+
* Commit, do not mess with rakefile, version, or history.
|
202
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
203
|
+
* Send me a pull request. Bonus points for topic branches.
|
204
|
+
|
205
|
+
## Copyright
|
206
|
+
|
207
|
+
Original version: Copyright (c) 2012 Forward. See [LICENSE](https://github.com/ncantor/capify-cloud/blob/master/LICENSE) for details.
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capify-cloud
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 2577870447
|
5
|
+
prerelease: 6
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
- pre
|
11
|
+
- 1
|
12
|
+
version: 1.5.0.pre.1
|
13
|
+
platform: ruby
|
14
|
+
authors:
|
15
|
+
- Noah Cantor
|
16
|
+
autorequire:
|
17
|
+
bindir: bin
|
18
|
+
cert_chain: []
|
19
|
+
|
20
|
+
date: 2012-07-10 00:00:00 Z
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: fog
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - "="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 7
|
31
|
+
segments:
|
32
|
+
- 1
|
33
|
+
- 4
|
34
|
+
- 0
|
35
|
+
version: 1.4.0
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: colored
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - "="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 11
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 2
|
50
|
+
version: "1.2"
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: capistrano
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :runtime
|
66
|
+
version_requirements: *id003
|
67
|
+
description: Grabs roles from clouds' meta-data and autogenerates capistrano tasks
|
68
|
+
email:
|
69
|
+
- ncantor@gmail.com
|
70
|
+
executables: []
|
71
|
+
|
72
|
+
extensions: []
|
73
|
+
|
74
|
+
extra_rdoc_files: []
|
75
|
+
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Changelog.md
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE
|
81
|
+
- Rakefile
|
82
|
+
- capify-cloud.gemspec
|
83
|
+
- lib/capify-cloud.rb
|
84
|
+
- lib/capify-cloud/capistrano.rb
|
85
|
+
- lib/capify-cloud/server.rb
|
86
|
+
- lib/capify-cloud/version.rb
|
87
|
+
- readme.md
|
88
|
+
homepage: http://github.com/ncantor/capify-cloud
|
89
|
+
licenses: []
|
90
|
+
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 25
|
111
|
+
segments:
|
112
|
+
- 1
|
113
|
+
- 3
|
114
|
+
- 1
|
115
|
+
version: 1.3.1
|
116
|
+
requirements: []
|
117
|
+
|
118
|
+
rubyforge_project: capify-cloud
|
119
|
+
rubygems_version: 1.8.24
|
120
|
+
signing_key:
|
121
|
+
specification_version: 3
|
122
|
+
summary: Grabs roles from clouds' meta-data and autogenerates capistrano tasks
|
123
|
+
test_files: []
|
124
|
+
|