axtro-rubber 1.0.2.8 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +124 -0
- data/VERSION +1 -1
- data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-apache-vhost.conf +4 -0
- data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-index.html +6 -2
- data/generators/vulcanize/templates/apache/config/rubber/rubber-apache.yml +0 -1
- data/generators/vulcanize/templates/base/config/rubber/common/crontab +2 -1
- data/generators/vulcanize/templates/base/config/rubber/common/monit-postfix.conf +8 -0
- data/generators/vulcanize/templates/base/config/rubber/common/rubber.profile +14 -0
- data/generators/vulcanize/templates/base/config/rubber/deploy-setup.rb +21 -41
- data/generators/vulcanize/templates/base/config/rubber/rubber-dns.yml +79 -0
- data/generators/vulcanize/templates/base/config/rubber/rubber.yml +29 -30
- data/generators/vulcanize/templates/complete_passenger_mysql/config/rubber/role/haproxy/haproxy-passenger.conf +2 -0
- data/generators/vulcanize/templates/jetty/config/rubber/deploy-jetty.rb +59 -0
- data/generators/vulcanize/templates/jetty/config/rubber/role/jetty/jetty.sh +589 -0
- data/generators/vulcanize/templates/jetty/config/rubber/role/jetty/jetty.xml +199 -0
- data/generators/vulcanize/templates/jetty/config/rubber/role/jetty/monit-jetty.conf +9 -0
- data/generators/vulcanize/templates/jetty/config/rubber/rubber-jetty.yml +10 -0
- data/generators/vulcanize/templates/jetty/templates.yml +1 -0
- data/generators/vulcanize/templates/mongrel/config/rubber/role/mongrel/monit-mongrel.conf +2 -2
- data/generators/vulcanize/templates/munin/config/rubber/common/munin-plugins.conf +9 -0
- data/generators/vulcanize/templates/munin/config/rubber/rubber-munin.yml +1 -1
- data/generators/vulcanize/templates/munin/script/munin/example_mysql_query.rb +3 -3
- data/generators/vulcanize/templates/mysql/config/rubber/rubber-mysql.yml +1 -0
- data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +1 -1
- data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger-memory.conf +34 -0
- data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger-sudoers.conf +2 -1
- data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger.conf +1 -1
- data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/passenger.conf +3 -3
- data/generators/vulcanize/templates/passenger/config/rubber/rubber-passenger.yml +5 -2
- data/generators/vulcanize/templates/passenger/templates.yml +3 -1
- data/generators/vulcanize/templates/redis/config/rubber/deploy-redis.rb +36 -0
- data/generators/vulcanize/templates/redis/config/rubber/role/redis/crontab +8 -0
- data/generators/vulcanize/templates/redis/config/rubber/role/redis/monit-redis.conf +9 -0
- data/generators/vulcanize/templates/redis/config/rubber/role/redis/redis.conf +141 -0
- data/generators/vulcanize/templates/redis/config/rubber/rubber-redis.yml +4 -0
- data/generators/vulcanize/templates/redis/templates.yml +1 -0
- data/generators/vulcanize/templates/resque/config/rubber/deploy-resque-worker-default.rb +38 -0
- data/generators/vulcanize/templates/resque/config/rubber/deploy-resque.rb +39 -0
- data/generators/vulcanize/templates/resque/config/rubber/role/resque_worker_default/monit-resque_worker_default.conf +19 -0
- data/generators/vulcanize/templates/resque/config/rubber/rubber-resque.yml +10 -0
- data/generators/vulcanize/templates/resque/templates.yml +3 -0
- data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/crontab +2 -2
- data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/monit-sphinx.conf +2 -2
- data/lib/rubber/cloud/aws.rb +32 -2
- data/lib/rubber/dns/base.rb +41 -26
- data/lib/rubber/dns/dyndns.rb +25 -10
- data/lib/rubber/dns/nettica.rb +75 -31
- data/lib/rubber/dns/zerigo.rb +96 -53
- data/lib/rubber/environment.rb +11 -3
- data/lib/rubber/instance.rb +11 -0
- data/lib/rubber/recipes/rubber/instances.rb +59 -6
- data/lib/rubber/recipes/rubber/security_groups.rb +1 -1
- data/lib/rubber/recipes/rubber/setup.rb +155 -52
- data/lib/rubber/recipes/rubber/spot_requests.rb +23 -0
- data/lib/rubber/recipes/rubber/static_ips.rb +83 -0
- data/lib/rubber/recipes/rubber/utils.rb +2 -2
- data/lib/rubber/recipes/rubber.rb +10 -3
- data/lib/rubber/tasks/rubber.rb +64 -6
- data/lib/rubber.rb +1 -1
- data/rails/init.rb +9 -0
- data/test/environment_test.rb +18 -0
- data/test/generator_test.rb +3 -0
- data/test/instance_test.rb +3 -0
- data/test/test_helper.rb +4 -0
- data/test/util_test.rb +3 -0
- metadata +28 -4
- data/generators/vulcanize/templates/base/config/rubber/common/profile.rc +0 -9
data/lib/rubber/dns/zerigo.rb
CHANGED
@@ -9,6 +9,11 @@ module Rubber
|
|
9
9
|
include HTTParty
|
10
10
|
format :xml
|
11
11
|
|
12
|
+
@@zones = {}
|
13
|
+
def self.get_zone(domain, provider_env)
|
14
|
+
@@zones[domain] ||= Zone.new(provider_env.customer_id, provider_env.email, provider_env.token, domain)
|
15
|
+
end
|
16
|
+
|
12
17
|
def initialize(customer_id, email, token, domain)
|
13
18
|
self.class.basic_auth email, token
|
14
19
|
self.class.base_uri "https://ns.zerigo.com/accounts/#{customer_id}"
|
@@ -26,31 +31,49 @@ module Rubber
|
|
26
31
|
return response
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
34
|
+
def create_host(opts)
|
35
|
+
host = opts_to_host(opts, new_host())
|
36
|
+
check_status self.class.post("/zones/#{@zone['id']}/hosts.xml", :body => {:host => host})
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
def find_host_records(opts={})
|
40
|
+
result = []
|
41
|
+
hn = opts[:host]
|
42
|
+
ht = opts[:type]
|
43
|
+
hd = opts[:data]
|
44
|
+
has_host = hn && hn != '*'
|
38
45
|
|
39
|
-
|
40
|
-
|
41
|
-
|
46
|
+
url = "/zones/#{@zone['id']}/hosts.xml"
|
47
|
+
if has_host
|
48
|
+
url << "?fqdn="
|
49
|
+
url << "#{hn}." if hn.strip.size > 0
|
50
|
+
url << "#{@domain}"
|
51
|
+
end
|
52
|
+
hosts = self.class.get(url)
|
42
53
|
|
43
|
-
|
44
|
-
|
54
|
+
# returns 404 on not found, so don't check status
|
55
|
+
hosts = check_status hosts unless has_host
|
56
|
+
|
57
|
+
hosts['hosts'].each do |h|
|
58
|
+
keep = true
|
59
|
+
if ht && h['host_type'] != ht && ht != '*'
|
60
|
+
keep = false
|
61
|
+
end
|
62
|
+
if hd && h['data'] != hd
|
63
|
+
keep = false
|
64
|
+
end
|
65
|
+
result << host_to_opts(h) if keep
|
66
|
+
end if hosts['hosts']
|
67
|
+
|
68
|
+
return result
|
45
69
|
end
|
46
70
|
|
47
|
-
def update_host(
|
48
|
-
|
71
|
+
def update_host(host_id, opts)
|
72
|
+
host = opts_to_host(opts, new_host())
|
49
73
|
check_status self.class.put("/zones/#{@zone['id']}/hosts/#{host_id}.xml", :body => {:host => host})
|
50
74
|
end
|
51
75
|
|
52
|
-
def delete_host(
|
53
|
-
host_id = host(hostname)['id']
|
76
|
+
def delete_host(host_id)
|
54
77
|
check_status self.class.delete("/zones/#{@zone['id']}/hosts/#{host_id}.xml")
|
55
78
|
end
|
56
79
|
|
@@ -62,67 +85,87 @@ module Rubber
|
|
62
85
|
zones = check_status self.class.get('/zones.xml')
|
63
86
|
@zone = zones["zones"].find {|z| z["domain"] == @domain }
|
64
87
|
end
|
88
|
+
if ! @zone
|
89
|
+
zone = new_zone()
|
90
|
+
zone['domain'] = @domain
|
91
|
+
zones = check_status self.class.post('/zones.xml', :body => {:zone => zone})
|
92
|
+
@zone = zones['zone']
|
93
|
+
end
|
65
94
|
end
|
66
95
|
|
67
|
-
def
|
96
|
+
def zone_record
|
68
97
|
return @zone
|
69
98
|
end
|
70
99
|
|
71
|
-
|
100
|
+
private
|
72
101
|
|
73
|
-
def
|
74
|
-
check_status
|
102
|
+
def new_host
|
103
|
+
check_status(self.class.get("/zones/#{@zone['id']}/hosts/new.xml"))['host']
|
104
|
+
end
|
105
|
+
|
106
|
+
def new_zone
|
107
|
+
check_status(self.class.get("/zones/new.xml"))['zone']
|
108
|
+
end
|
109
|
+
|
110
|
+
def opts_to_host(opts, host={})
|
111
|
+
host['hostname'] = opts[:host]
|
112
|
+
host['host_type'] = opts[:type]
|
113
|
+
host['data'] = opts[:data] if opts[:data]
|
114
|
+
host['ttl'] = opts[:ttl] if opts[:ttl]
|
115
|
+
host['priority'] = opts[:priority] if opts[:priority]
|
116
|
+
return host
|
75
117
|
end
|
76
118
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
119
|
+
def host_to_opts(host)
|
120
|
+
opts = {}
|
121
|
+
opts[:id] = host['id']
|
122
|
+
opts[:domain] = @domain
|
123
|
+
opts[:host] = host['hostname'] || ''
|
124
|
+
opts[:type] = host['host_type']
|
125
|
+
opts[:data] = host['data'] if host['data']
|
126
|
+
opts[:ttl] = host['ttl'] if host['ttl']
|
127
|
+
opts[:priority] = host['priority'] if host['priority']
|
128
|
+
return opts
|
80
129
|
end
|
81
|
-
|
82
130
|
end
|
83
131
|
|
84
132
|
class Zerigo < Base
|
85
133
|
|
86
134
|
def initialize(env)
|
87
|
-
super(env)
|
88
|
-
@zerigo_env = env.dns_providers.zerigo
|
89
|
-
@ttl = (@zerigo_env.ttl || 300).to_i
|
90
|
-
@record_type = @zerigo_env.record_type || "A"
|
91
|
-
@zone = Zone.new(@zerigo_env.customer_id, @zerigo_env.email, @zerigo_env.token, env.domain)
|
135
|
+
super(env, "zerigo")
|
92
136
|
end
|
93
137
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
138
|
+
def find_host_records(opts = {})
|
139
|
+
opts = setup_opts(opts, [:host, :domain])
|
140
|
+
zone = Zone.get_zone(opts[:domain], provider_env)
|
97
141
|
|
98
|
-
|
99
|
-
@zone.host(host)
|
142
|
+
zone.find_host_records(opts)
|
100
143
|
end
|
101
144
|
|
102
|
-
def create_host_record(
|
103
|
-
|
104
|
-
|
105
|
-
host['ttl'] = @ttl
|
106
|
-
host['hostname'] = hostname
|
107
|
-
host['data'] = ip
|
108
|
-
@zone.create_host(host)
|
109
|
-
end
|
145
|
+
def create_host_record(opts = {})
|
146
|
+
opts = setup_opts(opts, [:host, :data, :domain, :type, :ttl])
|
147
|
+
zone = Zone.get_zone(opts[:domain], provider_env)
|
110
148
|
|
111
|
-
|
112
|
-
@zone.delete_host(host)
|
149
|
+
zone.create_host(opts)
|
113
150
|
end
|
114
151
|
|
115
|
-
def
|
116
|
-
|
117
|
-
|
118
|
-
|
152
|
+
def destroy_host_record(opts = {})
|
153
|
+
opts = setup_opts(opts, [:host, :domain])
|
154
|
+
zone = Zone.get_zone(opts[:domain], provider_env)
|
155
|
+
|
156
|
+
find_host_records(opts).each do |h|
|
157
|
+
zone.delete_host(h[:id])
|
158
|
+
end
|
119
159
|
end
|
120
160
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
161
|
+
def update_host_record(old_opts={}, new_opts={})
|
162
|
+
old_opts = setup_opts(old_opts, [:host, :domain])
|
163
|
+
new_opts = setup_opts(new_opts.merge(:no_defaults =>true), [])
|
164
|
+
zone = Zone.get_zone(old_opts[:domain], provider_env)
|
165
|
+
|
166
|
+
find_host_records(old_opts).each do |h|
|
167
|
+
zone.update_host(h[:id], h.merge(new_opts))
|
168
|
+
end
|
126
169
|
end
|
127
170
|
|
128
171
|
end
|
data/lib/rubber/environment.rb
CHANGED
@@ -32,6 +32,8 @@ module Rubber
|
|
32
32
|
roles_dir = File.join(@config_root, "role")
|
33
33
|
roles = Dir.entries(roles_dir)
|
34
34
|
roles.delete_if {|d| d =~ /(^\..*)/}
|
35
|
+
roles += @items['roles'].keys
|
36
|
+
return roles.compact.uniq
|
35
37
|
end
|
36
38
|
|
37
39
|
def current_host
|
@@ -41,7 +43,7 @@ module Rubber
|
|
41
43
|
def current_full_host
|
42
44
|
Socket::gethostname
|
43
45
|
end
|
44
|
-
|
46
|
+
|
45
47
|
def bind(roles = nil, host = nil)
|
46
48
|
BoundEnv.new(@items, roles, host)
|
47
49
|
end
|
@@ -77,6 +79,10 @@ module Rubber
|
|
77
79
|
replace(receiver)
|
78
80
|
end
|
79
81
|
|
82
|
+
def rubber_instances
|
83
|
+
@rubber_instances ||= Rubber::Configuration::rubber_instances
|
84
|
+
end
|
85
|
+
|
80
86
|
def [](name)
|
81
87
|
value = super(name)
|
82
88
|
value = global[name] if global && !value
|
@@ -122,14 +128,16 @@ module Rubber
|
|
122
128
|
class BoundEnv < HashValueProxy
|
123
129
|
attr_reader :roles
|
124
130
|
attr_reader :host
|
125
|
-
attr_reader :full_host
|
126
131
|
|
127
132
|
def initialize(global, roles, host)
|
128
133
|
@roles = roles
|
129
134
|
@host = host
|
130
135
|
bound_global = bind_config(global)
|
131
136
|
super(nil, bound_global)
|
132
|
-
|
137
|
+
end
|
138
|
+
|
139
|
+
def full_host
|
140
|
+
@full_host ||= "#{host}.#{domain}" rescue nil
|
133
141
|
end
|
134
142
|
|
135
143
|
# Forces role/host overrides into config
|
data/lib/rubber/instance.rb
CHANGED
@@ -81,6 +81,8 @@ module Rubber
|
|
81
81
|
attr_accessor :external_host, :external_ip
|
82
82
|
attr_accessor :internal_host, :internal_ip
|
83
83
|
attr_accessor :static_ip, :volumes, :partitions
|
84
|
+
attr_accessor :spot_instance_request_id
|
85
|
+
attr_accessor :platform
|
84
86
|
|
85
87
|
def initialize(name, domain, roles, instance_id, security_group_list=[])
|
86
88
|
@name = name
|
@@ -97,6 +99,15 @@ module Rubber
|
|
97
99
|
def role_names()
|
98
100
|
roles.collect {|r| r.name}
|
99
101
|
end
|
102
|
+
|
103
|
+
def platform
|
104
|
+
# Deal with old instance configurations that don't have a platform value persisted.
|
105
|
+
@platform || 'linux'
|
106
|
+
end
|
107
|
+
|
108
|
+
def windows?
|
109
|
+
platform == 'windows'
|
110
|
+
end
|
100
111
|
end
|
101
112
|
|
102
113
|
# The configuration for a single role contained in the list
|
@@ -5,7 +5,13 @@ namespace :rubber do
|
|
5
5
|
DESC
|
6
6
|
required_task :create do
|
7
7
|
instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
|
8
|
-
|
8
|
+
|
9
|
+
env = rubber_cfg.environment.bind(nil, instance_alias)
|
10
|
+
default_roles = env.instance_roles
|
11
|
+
r = get_env("ROLES", "Instance roles (e.g. web,app,db:primary=true)", true, default_roles)
|
12
|
+
|
13
|
+
create_spot_instance = ENV.delete("SPOT_INSTANCE") || env.cloud_providers[env.cloud_provider].spot_instance
|
14
|
+
|
9
15
|
if r == '*'
|
10
16
|
instance_roles = rubber_cfg.environment.known_roles
|
11
17
|
instance_roles = instance_roles.collect {|role| role == "db" ? "db:primary=true" : role }
|
@@ -29,7 +35,7 @@ namespace :rubber do
|
|
29
35
|
# Add in roles that the given set of roles depends on
|
30
36
|
ir = Rubber::Configuration::RoleItem.expand_role_dependencies(ir, get_role_dependencies)
|
31
37
|
|
32
|
-
create_instance(instance_alias, ir)
|
38
|
+
create_instance(instance_alias, ir, create_spot_instance)
|
33
39
|
end
|
34
40
|
|
35
41
|
desc <<-DESC
|
@@ -83,6 +89,10 @@ namespace :rubber do
|
|
83
89
|
|
84
90
|
instance.roles = (instance.roles + ir).uniq
|
85
91
|
rubber_instances.save()
|
92
|
+
logger.info "Roles for #{instance_alias} are now:"
|
93
|
+
logger.info instance.role_names.sort.join("\n")
|
94
|
+
logger.info ''
|
95
|
+
logger.info "Run 'cap rubber:bootstrap' if done adding roles"
|
86
96
|
end
|
87
97
|
|
88
98
|
desc <<-DESC
|
@@ -105,6 +115,8 @@ namespace :rubber do
|
|
105
115
|
|
106
116
|
instance.roles = (instance.roles - ir).uniq
|
107
117
|
rubber_instances.save()
|
118
|
+
logger.info "Roles for #{instance_alias} are now:"
|
119
|
+
logger.info instance.role_names.sort.join("\n")
|
108
120
|
end
|
109
121
|
|
110
122
|
desc <<-DESC
|
@@ -144,7 +156,7 @@ namespace :rubber do
|
|
144
156
|
|
145
157
|
# Creates a new ec2 instance with the given alias and roles
|
146
158
|
# Configures aliases (/etc/hosts) on local and remote machines
|
147
|
-
def create_instance(instance_alias, instance_roles)
|
159
|
+
def create_instance(instance_alias, instance_roles, create_spot_instance=false)
|
148
160
|
fatal "Instance already exists: #{instance_alias}" if rubber_instances[instance_alias]
|
149
161
|
|
150
162
|
role_names = instance_roles.collect{|x| x.name}
|
@@ -157,12 +169,45 @@ namespace :rubber do
|
|
157
169
|
ami = env.cloud_providers[env.cloud_provider].image_id
|
158
170
|
ami_type = env.cloud_providers[env.cloud_provider].image_type
|
159
171
|
availability_zone = env.availability_zone
|
160
|
-
|
161
|
-
|
172
|
+
|
173
|
+
if create_spot_instance
|
174
|
+
spot_price = env.cloud_providers[env.cloud_provider].spot_price.to_s
|
175
|
+
|
176
|
+
logger.info "Creating spot instance request for instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
|
177
|
+
request_id = cloud.create_spot_instance_request(spot_price, ami, ami_type, security_groups, availability_zone)
|
178
|
+
|
179
|
+
print "Waiting for spot instance request to be fulfilled"
|
180
|
+
max_wait_time = env.cloud_providers[env.cloud_provider].spot_instance_request_timeout || (1.0 / 0) # Use the specified timeout value or default to infinite.
|
181
|
+
instance_id = nil
|
182
|
+
while instance_id.nil? do
|
183
|
+
print "."
|
184
|
+
sleep 2
|
185
|
+
max_wait_time -= 2
|
186
|
+
|
187
|
+
request = cloud.describe_spot_instance_requests(request_id).first
|
188
|
+
instance_id = request[:instance_id]
|
189
|
+
|
190
|
+
if max_wait_time < 0 && instance_id.nil?
|
191
|
+
cloud.destroy_spot_instance_request(request[:id])
|
192
|
+
|
193
|
+
print "\n"
|
194
|
+
print "Failed to fulfill spot instance in the time specified. Falling back to on-demand instance creation."
|
195
|
+
break
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
print "\n"
|
200
|
+
end
|
201
|
+
|
202
|
+
if !create_spot_instance || (create_spot_instance && max_wait_time < 0)
|
203
|
+
logger.info "Creating instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
|
204
|
+
instance_id = cloud.create_instance(ami, ami_type, security_groups, availability_zone)
|
205
|
+
end
|
162
206
|
|
163
207
|
logger.info "Instance #{instance_id} created"
|
164
208
|
|
165
209
|
instance_item = Rubber::Configuration::InstanceItem.new(instance_alias, env.domain, instance_roles, instance_id, security_groups)
|
210
|
+
instance_item.spot_instance_request_id = request_id if create_spot_instance
|
166
211
|
rubber_instances.add(instance_item)
|
167
212
|
rubber_instances.save()
|
168
213
|
|
@@ -180,6 +225,7 @@ namespace :rubber do
|
|
180
225
|
instance_item.external_ip = instance[:external_ip]
|
181
226
|
instance_item.internal_host = instance[:internal_host]
|
182
227
|
instance_item.zone = instance[:zone]
|
228
|
+
instance_item.platform = instance[:platform]
|
183
229
|
rubber_instances.save()
|
184
230
|
|
185
231
|
# setup amazon elastic ips if configured to do so
|
@@ -196,7 +242,14 @@ namespace :rubber do
|
|
196
242
|
# so that we can update all aliases
|
197
243
|
|
198
244
|
task :_get_ip, :hosts => instance_item.external_ip do
|
199
|
-
|
245
|
+
# There's no good way to get the internal IP for a Windows host, so just set it to the external
|
246
|
+
# and let the router handle mapping to the internal network.
|
247
|
+
if instance_item.windows?
|
248
|
+
instance_item.internal_ip = instance_item.external_ip
|
249
|
+
else
|
250
|
+
instance_item.internal_ip = capture(print_ip_command).strip
|
251
|
+
end
|
252
|
+
|
200
253
|
rubber_instances.save()
|
201
254
|
end
|
202
255
|
|
@@ -36,7 +36,7 @@ namespace :rubber do
|
|
36
36
|
security_groups << host
|
37
37
|
security_groups += roles
|
38
38
|
end
|
39
|
-
security_groups = security_groups.uniq.compact
|
39
|
+
security_groups = security_groups.uniq.compact.reject {|x| x.empty? }
|
40
40
|
security_groups = security_groups.collect {|x| isolate_group_name(x) } if env.isolate_security_groups
|
41
41
|
return security_groups
|
42
42
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
namespace :rubber do
|
2
2
|
|
3
|
+
# Disable connecting to any Windows instance.
|
4
|
+
set :default_run_options, :except => { :platform => 'windows' }
|
5
|
+
|
3
6
|
desc <<-DESC
|
4
7
|
Bootstraps instances by setting timezone, installing packages and gems
|
5
8
|
DESC
|
@@ -61,6 +64,83 @@ namespace :rubber do
|
|
61
64
|
end
|
62
65
|
end
|
63
66
|
|
67
|
+
desc <<-DESC
|
68
|
+
Sets up the additional dns records supplied in the dns_records config in rubber.yml
|
69
|
+
DESC
|
70
|
+
required_task :setup_dns_records do
|
71
|
+
records = rubber_env.dns_records
|
72
|
+
if records && rubber_env.dns_provider
|
73
|
+
provider = Rubber::Dns::get_provider(rubber_env.dns_provider, rubber_env)
|
74
|
+
|
75
|
+
# collect the round robin records (those with the same host/domain/type)
|
76
|
+
rr_records = []
|
77
|
+
records.each_with_index do |record, i|
|
78
|
+
m = records.find_all {|r| record['host'] == r['host'] && record['domain'] == r['domain'] && record['type'] == r['type']}
|
79
|
+
m = m.sort {|a,b| a.object_id <=> b.object_id}
|
80
|
+
rr_records << m if m.size > 1 && ! rr_records.include?(m)
|
81
|
+
end
|
82
|
+
|
83
|
+
# simple records are those that aren't round robin ones
|
84
|
+
simple_records = records - rr_records.flatten
|
85
|
+
|
86
|
+
# for each simple record, create or update as necessary
|
87
|
+
simple_records.each do |record|
|
88
|
+
matching = provider.find_host_records(:host => record['host'], :domain =>record['domain'], :type => record['type'])
|
89
|
+
if matching.size > 1
|
90
|
+
msg = "Multiple records in dns provider, but not in rubber.yml\n"
|
91
|
+
msg << "Round robin records need to be in both, or neither.\n"
|
92
|
+
msg << "Please fix manually:\n"
|
93
|
+
msg << matching.pretty_inspect
|
94
|
+
fatal(msg)
|
95
|
+
end
|
96
|
+
|
97
|
+
record = provider.setup_opts(record)
|
98
|
+
if matching.size == 1
|
99
|
+
match = matching.first
|
100
|
+
if provider.host_records_equal?(record, match)
|
101
|
+
logger.info "Simple dns record already up to date: #{record[:host]}.#{record[:domain]}:#{record[:type]} => #{record[:data]}"
|
102
|
+
else
|
103
|
+
logger.info "Updating simple dns record: #{record[:host]}.#{record[:domain]}:#{record[:type]} => #{record[:data]}"
|
104
|
+
provider.update_host_record(match, record)
|
105
|
+
end
|
106
|
+
else
|
107
|
+
logger.info "Creating simple dns record: #{record[:host]}.#{record[:domain]}:#{record[:type]} => #{record[:data]}"
|
108
|
+
provider.create_host_record(record)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# group round robin records
|
113
|
+
rr_records.each do |rr_group|
|
114
|
+
host = rr_group.first['host']
|
115
|
+
domain = rr_group.first['domain']
|
116
|
+
type = rr_group.first['type']
|
117
|
+
matching = provider.find_host_records(:host => host, :domain => domain, :type => type)
|
118
|
+
|
119
|
+
# remove from consideration the local records that are the same as remote ones
|
120
|
+
matching.clone.each do |r|
|
121
|
+
rr_group.delete_if {|rg| provider.host_records_equal?(r, rg) }
|
122
|
+
matching.delete_if {|rg| provider.host_records_equal?(r, rg) }
|
123
|
+
end
|
124
|
+
if rr_group.size == 0 && matching.size == 0
|
125
|
+
logger.info "Round robin dns records already up to date: #{host}.#{domain}:#{type}"
|
126
|
+
end
|
127
|
+
|
128
|
+
# create the local records that don't exist remotely
|
129
|
+
rr_group.each do |r|
|
130
|
+
r = provider.setup_opts(r)
|
131
|
+
logger.info "Creating round robin dns record: #{r[:host]}.#{r[:domain]}:#{r[:type]} => #{r[:data]}"
|
132
|
+
provider.create_host_record(r)
|
133
|
+
end
|
134
|
+
|
135
|
+
# remove the remote records that don't exist locally
|
136
|
+
matching.each do |r|
|
137
|
+
logger.info "Removing round robin dns record: #{r[:host]}.#{r[:domain]}:#{r[:type]} => #{r[:data]}"
|
138
|
+
provider.destroy_host_record(r)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
64
144
|
desc <<-DESC
|
65
145
|
Sets up aliases for instance hostnames based on contents of instance.yml.
|
66
146
|
Generates /etc/hosts for remote machines and sets hostname on remote instances
|
@@ -144,11 +224,33 @@ namespace :rubber do
|
|
144
224
|
desc <<-DESC
|
145
225
|
Install ruby gems defined in the rails environment.rb
|
146
226
|
DESC
|
147
|
-
after "
|
227
|
+
after "rubber:config", "rubber:install_rails_gems" if Rubber::Util.is_rails?
|
148
228
|
task :install_rails_gems do
|
149
229
|
sudo "sh -c 'cd #{current_path} && RAILS_ENV=#{RUBBER_ENV} rake gems:install'"
|
150
230
|
end
|
151
231
|
|
232
|
+
desc <<-DESC
|
233
|
+
Convenience task for installing your defined set of ruby gems locally.
|
234
|
+
DESC
|
235
|
+
required_task :install_local_gems do
|
236
|
+
fatal("install_local_gems can only be run in development") if RUBBER_ENV != 'development'
|
237
|
+
env = rubber_cfg.environment.bind(rubber_cfg.environment.known_roles)
|
238
|
+
gems = env['gems']
|
239
|
+
expanded_gem_list = []
|
240
|
+
gems.each do |gem_spec|
|
241
|
+
if gem_spec.is_a?(Array)
|
242
|
+
expanded_gem_list << "#{gem_spec[0]}:#{gem_spec[1]}"
|
243
|
+
else
|
244
|
+
expanded_gem_list << gem_spec
|
245
|
+
end
|
246
|
+
end
|
247
|
+
expanded_gem_list = expanded_gem_list.join(' ')
|
248
|
+
|
249
|
+
logger.info "Installing gems:#{expanded_gem_list}"
|
250
|
+
open("/tmp/gem_helper", "w") {|f| f.write(gem_helper_script)}
|
251
|
+
system "sh /tmp/gem_helper install #{expanded_gem_list}"
|
252
|
+
end
|
253
|
+
|
152
254
|
desc <<-DESC
|
153
255
|
Setup ruby gems sources. Set 'gemsources' in rubber.yml to \
|
154
256
|
be an array of URI strings.
|
@@ -280,11 +382,61 @@ namespace :rubber do
|
|
280
382
|
end
|
281
383
|
end
|
282
384
|
|
385
|
+
# Rubygems always installs even if the gem is already installed
|
386
|
+
# When providing versions, rubygems fails unless versions are provided for all gems
|
387
|
+
# This helper script works around these issues by installing gems only if they
|
388
|
+
# aren't already installed, and separates versioned/unversioned into two separate
|
389
|
+
# calls to rubygems
|
390
|
+
#
|
391
|
+
set :gem_helper_script, <<-'ENDSCRIPT'
|
392
|
+
ruby - $@ <<-'EOF'
|
393
|
+
|
394
|
+
gem_cmd = ARGV[0]
|
395
|
+
gems = ARGV[1..-1]
|
396
|
+
cmd = "gem #{gem_cmd} --no-rdoc --no-ri"
|
397
|
+
|
398
|
+
to_install = {}
|
399
|
+
to_install_ver = {}
|
400
|
+
# gem list passed in, possibly with versions, as "gem1 gem2:1.2 gem3"
|
401
|
+
gems.each do |gem_spec|
|
402
|
+
parts = gem_spec.split(':')
|
403
|
+
if parts[1]
|
404
|
+
to_install_ver[parts[0]] = parts[1]
|
405
|
+
else
|
406
|
+
to_install[parts[0]] = true
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
installed = {}
|
411
|
+
`gem list --local`.each do |line|
|
412
|
+
parts = line.scan(/(.*) \((.*)\)/).first
|
413
|
+
next unless parts && parts.size == 2
|
414
|
+
installed[parts[0]] = parts[1].split(",")
|
415
|
+
end
|
416
|
+
|
417
|
+
to_install.delete_if {|g, v| installed.has_key?(g) } if gem_cmd == 'install'
|
418
|
+
to_install_ver.delete_if {|g, v| installed.has_key?(g) && installed[g].include?(v) }
|
419
|
+
|
420
|
+
# rubygems can only do asingle versioned gem at a time so we need
|
421
|
+
# to do the two groups separately
|
422
|
+
# install versioned ones first so unversioned don't pull in a newer version
|
423
|
+
to_install_ver.each do |g, v|
|
424
|
+
system "#{cmd} #{g} -v #{v}"
|
425
|
+
fail "Unable to install versioned gem #{g}:#{v}" if $?.exitstatus > 0
|
426
|
+
end
|
427
|
+
if to_install.size > 0
|
428
|
+
gem_list = to_install.keys.join(' ')
|
429
|
+
system "#{cmd} #{gem_list}"
|
430
|
+
fail "Unable to install gems" if $?.exitstatus > 0
|
431
|
+
end
|
432
|
+
|
433
|
+
'EOF'
|
434
|
+
ENDSCRIPT
|
435
|
+
|
283
436
|
# Helper for installing gems,allows one to respond to prompts
|
284
437
|
def gem_helper(update=false)
|
285
438
|
cmd = update ? "update" : "install"
|
286
439
|
|
287
|
-
|
288
440
|
opts = get_host_options('gems') do |gem_list|
|
289
441
|
expanded_gem_list = []
|
290
442
|
gem_list.each do |gem_spec|
|
@@ -298,56 +450,7 @@ namespace :rubber do
|
|
298
450
|
end
|
299
451
|
|
300
452
|
if opts.size > 0
|
301
|
-
|
302
|
-
# When providing versions, rubygems fails unless versions are provided for all gems
|
303
|
-
# This helper script works around these issues by installing gems only if they
|
304
|
-
# aren't already installed, and separates versioned/unversioned into two separate
|
305
|
-
# calls to rubygems
|
306
|
-
script = prepare_script 'gem_helper', <<-'ENDSCRIPT'
|
307
|
-
ruby - $@ <<-'EOF'
|
308
|
-
|
309
|
-
gem_cmd = ARGV[0]
|
310
|
-
gems = ARGV[1..-1]
|
311
|
-
cmd = "gem #{gem_cmd} --no-rdoc --no-ri"
|
312
|
-
|
313
|
-
to_install = {}
|
314
|
-
to_install_ver = {}
|
315
|
-
# gem list passed in, possibly with versions, as "gem1 gem2:1.2 gem3"
|
316
|
-
gems.each do |gem_spec|
|
317
|
-
parts = gem_spec.split(':')
|
318
|
-
if parts[1]
|
319
|
-
to_install_ver[parts[0]] = parts[1]
|
320
|
-
else
|
321
|
-
to_install[parts[0]] = true
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
installed = {}
|
326
|
-
`gem list --local`.each do |line|
|
327
|
-
parts = line.scan(/(.*) \((.*)\)/).first
|
328
|
-
next unless parts && parts.size == 2
|
329
|
-
installed[parts[0]] = parts[1].split(",")
|
330
|
-
end
|
331
|
-
|
332
|
-
to_install.delete_if {|g, v| installed.has_key?(g) } if gem_cmd == 'install'
|
333
|
-
to_install_ver.delete_if {|g, v| installed.has_key?(g) && installed[g].include?(v) }
|
334
|
-
|
335
|
-
# rubygems can only do asingle versioned gem at a time so we need
|
336
|
-
# to do the two groups separately
|
337
|
-
# install versioned ones first so unversioned don't pull in a newer version
|
338
|
-
to_install_ver.each do |g, v|
|
339
|
-
system "#{cmd} #{g} -v #{v}"
|
340
|
-
fail "Unable to install versioned gem #{g}:#{v}" if $?.exitstatus > 0
|
341
|
-
end
|
342
|
-
if to_install.size > 0
|
343
|
-
gem_list = to_install.keys.join(' ')
|
344
|
-
system "#{cmd} #{gem_list}"
|
345
|
-
fail "Unable to install gems" if $?.exitstatus > 0
|
346
|
-
end
|
347
|
-
|
348
|
-
'EOF'
|
349
|
-
ENDSCRIPT
|
350
|
-
|
453
|
+
script = prepare_script('gem_helper', gem_helper_script)
|
351
454
|
sudo "sh #{script} #{cmd} $CAPISTRANO:VAR$", opts do |ch, str, data|
|
352
455
|
handle_gem_prompt(ch, data, str)
|
353
456
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
namespace :rubber do
|
2
|
+
|
3
|
+
desc "Describes all your spot instance requests"
|
4
|
+
required_task :describe_spot_instance_requests do
|
5
|
+
requests = cloud.describe_spot_instance_requests()
|
6
|
+
requests.each do |request|
|
7
|
+
logger.info "======================"
|
8
|
+
logger.info "ID: #{request[:id]}"
|
9
|
+
logger.info "Created at: #{request[:created_at]}"
|
10
|
+
logger.info "Max. price: $#{request[:spot_price]}"
|
11
|
+
logger.info "State: #{request[:state]}"
|
12
|
+
logger.info "Instance type: #{request[:type]}"
|
13
|
+
logger.info "AMI: #{request[:image_id]}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Cancel the spot instances request for the given id"
|
18
|
+
required_task :cancel_spot_instances_request do
|
19
|
+
request_id = get_env('SPOT_INSTANCE_REQUEST_ID', 'The id of the spot instances request to cancel', true)
|
20
|
+
cloud.destroy_spot_instance_request(request_id)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|