rubber 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/generators/vulcanize/templates/apache/config/rubber/rubber-apache.yml +0 -1
- data/generators/vulcanize/templates/base/config/rubber/deploy-setup.rb +3 -20
- data/generators/vulcanize/templates/base/config/rubber/rubber-dns.yml +79 -0
- data/generators/vulcanize/templates/base/config/rubber/rubber.yml +6 -24
- data/generators/vulcanize/templates/complete_passenger_mysql/config/rubber/role/haproxy/haproxy-passenger.conf +2 -0
- data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +1 -1
- data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/passenger.conf +3 -3
- data/lib/rubber/cloud/aws.rb +1 -0
- 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 +4 -1
- data/lib/rubber/recipes/rubber/setup.rb +152 -52
- data/lib/rubber/tasks/rubber.rb +64 -6
- data/rails/init.rb +9 -0
- data/test/environment_test.rb +15 -0
- data/test/test_helper.rb +4 -0
- metadata +4 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
@@ -20,26 +20,9 @@ namespace :rubber do
|
|
20
20
|
if ent_ruby_hosts.size > 0
|
21
21
|
|
22
22
|
task :_install_enterprise_ruby, :hosts => ent_ruby_hosts do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
Package: *
|
27
|
-
Pin: release l=brightbox
|
28
|
-
Pin-Priority: 1001
|
29
|
-
|
30
|
-
Package: ruby1.8-elisp
|
31
|
-
Pin: release l=Ubuntu
|
32
|
-
Pin-Priority: 1001
|
33
|
-
DATA
|
34
|
-
|
35
|
-
prefs.gsub!(/^ */, '') # remove leading whitespace
|
36
|
-
put(prefs, '/etc/apt/preferences')
|
37
|
-
|
38
|
-
rubber.sudo_script 'install_enterprise_ruby', <<-ENDSCRIPT
|
39
|
-
wget http://apt.brightbox.net/release.asc -O - | apt-key add -
|
40
|
-
echo "deb http://apt.brightbox.net/ hardy rubyee" > /etc/apt/sources.list.d/brightbox-rubyee.list
|
41
|
-
ENDSCRIPT
|
42
|
-
|
23
|
+
custom_package('http://rubyforge.org/frs/download.php/64479',
|
24
|
+
'ruby-enterprise', '1.8.7-20090928',
|
25
|
+
'! `ruby --version 2> /dev/null` =~ "Ruby Enterprise Edition 20090928"')
|
43
26
|
end
|
44
27
|
|
45
28
|
_install_enterprise_ruby
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# OPTIONAL: The dns provider to use. Need to exist in dns_providers below
|
2
|
+
# dns_provider: nettica
|
3
|
+
|
4
|
+
# OPTIONAL: The configuration for each dns provider (nettica|zerigo|dyndns)
|
5
|
+
# This lets rubber update a dynamic dns service with the instance alias and ip
|
6
|
+
#
|
7
|
+
dns_providers:
|
8
|
+
nettica:
|
9
|
+
user: joe
|
10
|
+
password: sekret
|
11
|
+
type: A
|
12
|
+
ttl: 300
|
13
|
+
zerigo:
|
14
|
+
customer_id: 1234
|
15
|
+
email: foo@bar.com
|
16
|
+
token: hexxy
|
17
|
+
type: A
|
18
|
+
ttl: 300
|
19
|
+
dyndns:
|
20
|
+
user: joe
|
21
|
+
password: sekret
|
22
|
+
update_url: https://members.dyndns.org/nic/update?hostname=%host%&myip=%ip%'
|
23
|
+
|
24
|
+
# OPTIONAL: Lets you configure your dns service, for example to add other CNAMES
|
25
|
+
# or setup dns round robin, etc. Run "cap rubber:setup_dns_records"
|
26
|
+
# to apply them as rubber only sets up instance aliases as part of
|
27
|
+
# the standard lifecycle
|
28
|
+
#
|
29
|
+
# dns_records:
|
30
|
+
# # simple A record
|
31
|
+
# - host: bar
|
32
|
+
# data: 1.1.1.1
|
33
|
+
#
|
34
|
+
# # more detailed A record
|
35
|
+
# - host: bar
|
36
|
+
# domain: otherdomain.com
|
37
|
+
# data: 1.1.1.1
|
38
|
+
# type: A
|
39
|
+
# ttl: 300
|
40
|
+
#
|
41
|
+
# # tld A record
|
42
|
+
# - host: ''
|
43
|
+
# data: 1.1.1.1
|
44
|
+
# type: A
|
45
|
+
#
|
46
|
+
# # simple CNAME record
|
47
|
+
# - host: otherbar
|
48
|
+
# domain: foo.com
|
49
|
+
# data: bar.foo.com
|
50
|
+
# type: CNAME
|
51
|
+
# ttl: 300
|
52
|
+
#
|
53
|
+
# # 2 of the same A records is a round robin dns
|
54
|
+
# - host: rr
|
55
|
+
# domain: foo.com
|
56
|
+
# data: 1.1.1.1
|
57
|
+
# type: A
|
58
|
+
# ttl: 300
|
59
|
+
# - host: rr
|
60
|
+
# domain: foo.com
|
61
|
+
# data: 1.1.1.2
|
62
|
+
# type: A
|
63
|
+
# ttl: 300
|
64
|
+
#
|
65
|
+
# # A record, grabbing ip from instance config
|
66
|
+
# - host: baz
|
67
|
+
# domain: foo.com
|
68
|
+
# data: "#{rubber_instances.for_role('web').first.external_ip}"
|
69
|
+
# type: A
|
70
|
+
# ttl: 300
|
71
|
+
#
|
72
|
+
# # MX record
|
73
|
+
# - host: ''
|
74
|
+
# domain: foo.com
|
75
|
+
# data: mail.foo.com
|
76
|
+
# type: MX
|
77
|
+
# ttl: 300
|
78
|
+
# priority: 10
|
79
|
+
|
@@ -32,28 +32,10 @@ timezone: US/Eastern
|
|
32
32
|
#
|
33
33
|
domain: foo.com
|
34
34
|
|
35
|
-
# OPTIONAL:
|
36
|
-
#
|
37
|
-
#
|
38
|
-
|
39
|
-
nettica:
|
40
|
-
user: joe
|
41
|
-
password: sekret
|
42
|
-
record_type: A
|
43
|
-
ttl: 300
|
44
|
-
zerigo:
|
45
|
-
customer_id: 1234
|
46
|
-
email: foo@bar.com
|
47
|
-
token: hexxy
|
48
|
-
record_type: A
|
49
|
-
ttl: 300
|
50
|
-
dyndns:
|
51
|
-
user: joe
|
52
|
-
password: sekret
|
53
|
-
update_url: https://members.dyndns.org/nic/update?hostname=%host%&myip=%ip%'
|
54
|
-
|
55
|
-
# OPTIONAL: The dns provider to use
|
56
|
-
# dns_provider: nettica
|
35
|
+
# OPTIONAL: See rubber-dns.yml for dns configuration
|
36
|
+
# This lets rubber update a dynamic dns service with the instance alias
|
37
|
+
# and ip when they are created. It also allows setting up arbitrary
|
38
|
+
# dns records (CNAME, MX, Round Robin DNS, etc)
|
57
39
|
|
58
40
|
# OPTIONAL: Additional rubber file to pull config from if it exists. This file will
|
59
41
|
# also be pushed to remote host at RUBBER_ROOT/config/rubber/rubber-secret.yml
|
@@ -144,12 +126,12 @@ use_enterprise_ruby: false
|
|
144
126
|
packages: [postfix, build-essential, ruby-full, ruby1.8-dev, rake, irb]
|
145
127
|
|
146
128
|
# OPTIONAL: gem sources to setup for rubygems
|
147
|
-
gemsources: ["http://gems.rubyforge.org/", "http://gems.github.com"]
|
129
|
+
gemsources: ["http://gemcutter.org", "http://gems.rubyforge.org/", "http://gems.github.com"]
|
148
130
|
|
149
131
|
# OPTIONAL: The gems to install on all instances
|
150
132
|
# You can install a specific version of a gem by using a sub-array of gem, version
|
151
133
|
# For example, gem: [[rails, 2.2.2], open4, aws-s3]
|
152
|
-
gems: [
|
134
|
+
gems: [rubber, rails, open4, aws-s3]
|
153
135
|
|
154
136
|
# OPTIONAL: A string prepended to shell command strings that cause multi
|
155
137
|
# statement shell commands to fail fast. You may need to comment this out
|
@@ -8,12 +8,14 @@
|
|
8
8
|
%>
|
9
9
|
|
10
10
|
listen passenger_proxy 0.0.0.0:<%= rubber_env.web_port %>
|
11
|
+
option forwardfor
|
11
12
|
<% backend_hosts.each do |server| %>
|
12
13
|
server <%= server %> <%= server %>:<%= rubber_env.passenger_listen_port %> maxconn <%= rubber_env.max_app_connections %> check
|
13
14
|
<% end %>
|
14
15
|
|
15
16
|
listen passenger_proxy 0.0.0.0:<%= rubber_env.web_ssl_port %>
|
16
17
|
mode tcp
|
18
|
+
option forwardfor
|
17
19
|
<% backend_hosts.each do |server| %>
|
18
20
|
server <%= server %> <%= server %>:<%= rubber_env.passenger_listen_ssl_port %> maxconn <%= rubber_env.max_app_connections %> check
|
19
21
|
<% end %>
|
@@ -9,7 +9,7 @@ namespace :rubber do
|
|
9
9
|
|
10
10
|
task :custom_install, :roles => :passenger do
|
11
11
|
rubber.sudo_script 'install_passenger', <<-ENDSCRIPT
|
12
|
-
if [[ -z `ls /usr/lib/ruby/gems/*/gems/passenger-#{rubber_env.passenger_version}/ext/apache2/mod_passenger.so 2> /dev/null` ]]; then
|
12
|
+
if [[ -z `ls /usr/local/lib/ruby/gems/*/gems/passenger-#{rubber_env.passenger_version}/ext/apache2/mod_passenger.so 2> /dev/null` ]]; then
|
13
13
|
echo -en "\n\n\n\n" | passenger-install-apache2-module
|
14
14
|
fi
|
15
15
|
ENDSCRIPT
|
@@ -2,9 +2,9 @@
|
|
2
2
|
@path = '/etc/apache2/mods-available/passenger.conf'
|
3
3
|
@post = 'cd /etc/apache2/mods-enabled && ln -fs ../mods-available/passenger.conf'
|
4
4
|
%>
|
5
|
-
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-<%= rubber_env.passenger_version %>/ext/apache2/mod_passenger.so
|
6
|
-
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-<%= rubber_env.passenger_version %>
|
7
|
-
PassengerRuby /usr/bin/ruby
|
5
|
+
LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-<%= rubber_env.passenger_version %>/ext/apache2/mod_passenger.so
|
6
|
+
PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-<%= rubber_env.passenger_version %>
|
7
|
+
PassengerRuby /usr/local/bin/ruby
|
8
8
|
PassengerUseGlobalQueue on
|
9
9
|
|
10
10
|
PassengerMaxPoolSize <%= rubber_env.max_app_connections %>
|
data/lib/rubber/cloud/aws.rb
CHANGED
@@ -255,6 +255,7 @@ module Rubber
|
|
255
255
|
|
256
256
|
def destroy_image(image_id)
|
257
257
|
image = describe_images(image_id).first
|
258
|
+
raise "Could not find image: #{image_id}, aborting destroy_image"
|
258
259
|
image_location = image[:location]
|
259
260
|
bucket = image_location.split('/').first
|
260
261
|
image_name = image_location.split('/').last.gsub(/\.manifest\.xml$/, '')
|
data/lib/rubber/dns/base.rb
CHANGED
@@ -3,65 +3,80 @@ module Rubber
|
|
3
3
|
|
4
4
|
class Base
|
5
5
|
|
6
|
-
attr_reader :env
|
6
|
+
attr_reader :env, :provider_env, :provider_name
|
7
7
|
|
8
|
-
def initialize(env)
|
8
|
+
def initialize(env, provider_name)
|
9
9
|
@env = env
|
10
|
+
@provider_name = provider_name
|
11
|
+
@provider_env = @env.dns_providers[provider_name]
|
10
12
|
end
|
11
13
|
|
12
14
|
def update(host, ip)
|
13
15
|
if up_to_date(host, ip)
|
14
16
|
puts "IP has not changed for #{host}, not updating dynamic DNS"
|
15
17
|
else
|
16
|
-
if
|
18
|
+
if find_host_records(:host => host).size == 0
|
17
19
|
puts "Creating dynamic DNS: #{host} => #{ip}"
|
18
|
-
create_host_record(host, ip)
|
20
|
+
create_host_record(:host => host, :data => ip)
|
19
21
|
else
|
20
22
|
puts "Updating dynamic DNS: #{host} => #{ip}"
|
21
|
-
update_host_record(host, ip)
|
23
|
+
update_host_record({:host => host}, {:host => host, :data => ip})
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
def destroy(host)
|
27
|
-
if
|
29
|
+
if find_host_records(:host => host).size != 0
|
28
30
|
puts "Destroying dynamic DNS record: #{host}"
|
29
|
-
destroy_host_record(host)
|
31
|
+
destroy_host_record(:host => host)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
def hostname(host)
|
34
|
-
"#{host}.#{@env.domain}"
|
35
|
-
end
|
36
|
-
|
37
35
|
def up_to_date(host, ip)
|
38
|
-
|
39
|
-
current_ip = nil
|
40
|
-
Resolv::DNS.open(:nameserver => [nameserver], :search => [], :ndots => 1) do |dns|
|
41
|
-
current_ip = dns.getaddress(hostname(host)).to_s rescue nil
|
42
|
-
end
|
43
|
-
return ip == current_ip
|
36
|
+
find_host_records(:host => host).any? {|host| host[:data] == ip}
|
44
37
|
end
|
45
38
|
|
46
|
-
def
|
47
|
-
raise "
|
39
|
+
def create_host_record(opts = {})
|
40
|
+
raise "create_host_record not implemented"
|
48
41
|
end
|
49
42
|
|
50
|
-
def
|
51
|
-
raise "
|
43
|
+
def find_host_records(opts = {})
|
44
|
+
raise "find_host_records not implemented"
|
52
45
|
end
|
53
46
|
|
54
|
-
def
|
55
|
-
raise "
|
47
|
+
def update_host_record(old_opts={}, new_opts={})
|
48
|
+
raise "update_host_record not implemented"
|
56
49
|
end
|
57
50
|
|
58
|
-
def destroy_host_record(
|
51
|
+
def destroy_host_record(opts = {})
|
59
52
|
raise "destroy_host_record not implemented"
|
60
53
|
end
|
61
54
|
|
62
|
-
def
|
63
|
-
|
55
|
+
def host_records_equal?(lhs_opts = {}, rhs_opts = {})
|
56
|
+
lhs = setup_opts(lhs_opts)
|
57
|
+
rhs = setup_opts(rhs_opts)
|
58
|
+
[lhs, rhs].each {|h| h.delete(:id); h.delete(:priority) if h[:priority] == 0}
|
59
|
+
lhs == rhs
|
60
|
+
end
|
61
|
+
|
62
|
+
def setup_opts(opts, required=[])
|
63
|
+
default_opts = {:domain => @env.domain,
|
64
|
+
:type => @provider_env['type'] || @provider_env.record_type || 'A',
|
65
|
+
:ttl => @provider_env.ttl || 300}
|
66
|
+
|
67
|
+
if opts.delete(:no_defaults)
|
68
|
+
actual_opts = Rubber::Util::symbolize_keys(opts)
|
69
|
+
else
|
70
|
+
actual_opts = default_opts.merge(Rubber::Util::symbolize_keys(opts))
|
71
|
+
end
|
72
|
+
|
73
|
+
required.each do |r|
|
74
|
+
raise "Missing required options: #{r}" unless actual_opts[r]
|
75
|
+
end
|
76
|
+
|
77
|
+
return actual_opts
|
64
78
|
end
|
79
|
+
|
65
80
|
|
66
81
|
end
|
67
82
|
|
data/lib/rubber/dns/dyndns.rb
CHANGED
@@ -4,10 +4,9 @@ module Rubber
|
|
4
4
|
class Dyndns < Base
|
5
5
|
|
6
6
|
def initialize(env)
|
7
|
-
super(env)
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@update_url = @dyndns_env.update_url || 'https://members.dyndns.org/nic/update?hostname=%host%&myip=%ip%'
|
7
|
+
super(env, 'dyndns')
|
8
|
+
@user, @pass = provider_env.user, provider_env.password
|
9
|
+
@update_url = provider_env.update_url || 'https://members.dyndns.org/nic/update?hostname=%host%&myip=%ip%'
|
11
10
|
@update_url = @update_url.gsub(/%([^%]+)%/, '#{\1}')
|
12
11
|
end
|
13
12
|
|
@@ -15,10 +14,22 @@ module Rubber
|
|
15
14
|
"ns1.mydyndns.org"
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
17
|
+
def up_to_date(host, ip)
|
18
|
+
# This queries dns server directly instead of using hosts file
|
19
|
+
current_ip = nil
|
20
|
+
Resolv::DNS.open(:nameserver => [nameserver], :search => [], :ndots => 1) do |dns|
|
21
|
+
current_ip = dns.getaddress("#{host}.#{provider_env.domain}").to_s rescue nil
|
22
|
+
end
|
23
|
+
return ip == current_ip
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_host_records(opts={})
|
27
|
+
opts = setup_opts(opts, [:host, :domain])
|
28
|
+
hostname = "#{opts[:host]}.#{opts[:domain]}"
|
19
29
|
begin
|
20
30
|
Resolv::DNS.open(:nameserver => [nameserver], :search => [], :ndots => 1) do |dns|
|
21
|
-
dns.getresource(hostname
|
31
|
+
r = dns.getresource(hostname, Resolv::DNS::Resource::IN::A)
|
32
|
+
result = [{:host =>host, :data => r.address}]
|
22
33
|
end
|
23
34
|
rescue
|
24
35
|
raise "Domain needs to exist in dyndns as an A record before record can be updated"
|
@@ -26,16 +37,20 @@ module Rubber
|
|
26
37
|
return true
|
27
38
|
end
|
28
39
|
|
29
|
-
def create_host_record(
|
40
|
+
def create_host_record(opts={})
|
30
41
|
puts "WARNING: No create record available for dyndns, you need to do so manually"
|
31
42
|
end
|
32
43
|
|
33
|
-
def destroy_host_record(
|
44
|
+
def destroy_host_record(opts={})
|
34
45
|
puts "WARNING: No destroy record available for dyndns, you need to do so manually"
|
35
46
|
end
|
36
47
|
|
37
|
-
def update_host_record(
|
38
|
-
|
48
|
+
def update_host_record(old_opts={}, new_opts={})
|
49
|
+
old_opts = setup_opts(opts, [:host, :domain])
|
50
|
+
new_opts = setup_opts(opts, [:data])
|
51
|
+
|
52
|
+
host = hostname(old_opts[:host])
|
53
|
+
ip = new_opts[:data]
|
39
54
|
update_url = eval('%Q{' + @update_url + '}')
|
40
55
|
|
41
56
|
# This header is required by dyndns.org
|
data/lib/rubber/dns/nettica.rb
CHANGED
@@ -5,15 +5,8 @@ module Rubber
|
|
5
5
|
class Nettica < Base
|
6
6
|
|
7
7
|
def initialize(env)
|
8
|
-
super(env)
|
9
|
-
@
|
10
|
-
@client = ::Nettica::Client.new(@nettica_env.user, @nettica_env.password)
|
11
|
-
@ttl = (@nettica_env.ttl || 300).to_i
|
12
|
-
@record_type = @nettica_env.record_type || "A"
|
13
|
-
end
|
14
|
-
|
15
|
-
def nameserver
|
16
|
-
"dns1.nettica.com"
|
8
|
+
super(env, "nettica")
|
9
|
+
@client = ::Nettica::Client.new(provider_env.user, provider_env.password)
|
17
10
|
end
|
18
11
|
|
19
12
|
def check_status(response)
|
@@ -33,40 +26,91 @@ module Rubber
|
|
33
26
|
return response
|
34
27
|
end
|
35
28
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
29
|
+
def find_host_records(opts = {})
|
30
|
+
opts = setup_opts(opts, [:host, :domain])
|
31
|
+
|
32
|
+
result = []
|
33
|
+
hn = opts[:host]
|
34
|
+
ht = opts[:type]
|
35
|
+
hd = opts[:data]
|
36
|
+
|
37
|
+
domain_info = find_or_create_zone(opts[:domain])
|
38
|
+
|
39
|
+
domain_info.record.each do |h|
|
40
|
+
keep = true
|
41
|
+
if hn && h.hostName != hn && hn != '*'
|
42
|
+
keep = false
|
43
|
+
end
|
44
|
+
if ht && h.recordType != ht && ht != '*'
|
45
|
+
keep = false
|
46
|
+
end
|
47
|
+
if hd && h.data != hd
|
48
|
+
keep = false
|
49
|
+
end
|
50
|
+
result << record_to_opts(h) if keep
|
51
|
+
end
|
52
|
+
|
53
|
+
return result
|
40
54
|
end
|
41
55
|
|
42
|
-
def create_host_record(
|
43
|
-
|
44
|
-
|
56
|
+
def create_host_record(opts = {})
|
57
|
+
opts = setup_opts(opts, [:host, :data, :domain, :type, :ttl])
|
58
|
+
find_or_create_zone(opts[:domain])
|
59
|
+
record = opts_to_record(opts)
|
60
|
+
check_status @client.add_record(record)
|
45
61
|
end
|
46
62
|
|
47
|
-
def destroy_host_record(
|
48
|
-
|
49
|
-
|
50
|
-
|
63
|
+
def destroy_host_record(opts = {})
|
64
|
+
find_host_records(opts).each do |h|
|
65
|
+
record = opts_to_record(h)
|
66
|
+
check_status @client.delete_record(record)
|
67
|
+
end
|
51
68
|
end
|
52
69
|
|
53
|
-
def update_host_record(
|
54
|
-
|
55
|
-
|
70
|
+
def update_host_record(old_opts = {}, new_opts = {})
|
71
|
+
old_opts = setup_opts(old_opts, [:host, :domain])
|
72
|
+
new_opts = setup_opts(new_opts.merge(:no_defaults =>true), [])
|
73
|
+
find_host_records(old_opts).each do |h|
|
74
|
+
old_record = opts_to_record(h)
|
75
|
+
new_record = opts_to_record(h.merge(new_opts))
|
76
|
+
check_status @client.update_record(old_record, new_record)
|
77
|
+
end
|
56
78
|
end
|
57
79
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
80
|
+
private
|
81
|
+
|
82
|
+
def find_or_create_zone(domain)
|
83
|
+
domain_info = @client.list_domain(domain)
|
84
|
+
if domain_info.record
|
85
|
+
check_status domain_info
|
86
|
+
else
|
87
|
+
check_status @client.create_zone(domain)
|
88
|
+
domain_info = check_status @client.list_domain(domain)
|
89
|
+
raise "Could not create zone in nettica: #{domain}" unless domain_info.record
|
90
|
+
end
|
91
|
+
return domain_info
|
62
92
|
end
|
63
93
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
94
|
+
def opts_to_record(opts)
|
95
|
+
record = @client.create_domain_record(opts[:domain],
|
96
|
+
opts[:host],
|
97
|
+
opts[:type],
|
98
|
+
opts[:data],
|
99
|
+
opts[:ttl],
|
100
|
+
opts[:priority] || 0)
|
101
|
+
return record
|
68
102
|
end
|
69
103
|
|
104
|
+
def record_to_opts(record)
|
105
|
+
opts = {}
|
106
|
+
opts[:host] = record.hostName || ''
|
107
|
+
opts[:domain] = record.domainName
|
108
|
+
opts[:type] = record.recordType
|
109
|
+
opts[:data] = record.data if record.data
|
110
|
+
opts[:ttl] = record.tTL if record.tTL
|
111
|
+
opts[:priority] = record.priority if record.priority
|
112
|
+
return opts
|
113
|
+
end
|
70
114
|
end
|
71
115
|
|
72
116
|
end
|
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
|
@@ -95,6 +97,7 @@ module Rubber
|
|
95
97
|
end
|
96
98
|
|
97
99
|
def expand_string(val)
|
100
|
+
rubber_instances = Rubber::Configuration::rubber_instances
|
98
101
|
while val =~ /\#\{[^\}]+\}/
|
99
102
|
val = eval('%Q{' + val + '}', binding)
|
100
103
|
end
|
@@ -61,6 +61,83 @@ namespace :rubber do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
desc <<-DESC
|
65
|
+
Sets up the additional dns records supplied in the dns_records config in rubber.yml
|
66
|
+
DESC
|
67
|
+
required_task :setup_dns_records do
|
68
|
+
records = rubber_env.dns_records
|
69
|
+
if records && rubber_env.dns_provider
|
70
|
+
provider = Rubber::Dns::get_provider(rubber_env.dns_provider, rubber_env)
|
71
|
+
|
72
|
+
# collect the round robin records (those with the same host/domain/type)
|
73
|
+
rr_records = []
|
74
|
+
records.each_with_index do |record, i|
|
75
|
+
m = records.find_all {|r| record['host'] == r['host'] && record['domain'] == r['domain'] && record['type'] == r['type']}
|
76
|
+
m = m.sort {|a,b| a.object_id <=> b.object_id}
|
77
|
+
rr_records << m if m.size > 1 && ! rr_records.include?(m)
|
78
|
+
end
|
79
|
+
|
80
|
+
# simple records are those that aren't round robin ones
|
81
|
+
simple_records = records - rr_records.flatten
|
82
|
+
|
83
|
+
# for each simple record, create or update as necessary
|
84
|
+
simple_records.each do |record|
|
85
|
+
matching = provider.find_host_records(:host => record['host'], :domain =>record['domain'], :type => record['type'])
|
86
|
+
if matching.size > 1
|
87
|
+
msg = "Multiple records in dns provider, but not in rubber.yml\n"
|
88
|
+
msg << "Round robin records need to be in both, or neither.\n"
|
89
|
+
msg << "Please fix manually:\n"
|
90
|
+
msg << matching.pretty_inspect
|
91
|
+
fatal(msg)
|
92
|
+
end
|
93
|
+
|
94
|
+
record = provider.setup_opts(record)
|
95
|
+
if matching.size == 1
|
96
|
+
match = matching.first
|
97
|
+
if provider.host_records_equal?(record, match)
|
98
|
+
logger.info "Simple dns record already up to date: #{record[:host]}.#{record[:domain]}:#{record[:type]} => #{record[:data]}"
|
99
|
+
else
|
100
|
+
logger.info "Updating simple dns record: #{record[:host]}.#{record[:domain]}:#{record[:type]} => #{record[:data]}"
|
101
|
+
provider.update_host_record(match, record)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
logger.info "Creating simple dns record: #{record[:host]}.#{record[:domain]}:#{record[:type]} => #{record[:data]}"
|
105
|
+
provider.create_host_record(record)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# group round robin records
|
110
|
+
rr_records.each do |rr_group|
|
111
|
+
host = rr_group.first['host']
|
112
|
+
domain = rr_group.first['domain']
|
113
|
+
type = rr_group.first['type']
|
114
|
+
matching = provider.find_host_records(:host => host, :domain => domain, :type => type)
|
115
|
+
|
116
|
+
# remove from consideration the local records that are the same as remote ones
|
117
|
+
matching.clone.each do |r|
|
118
|
+
rr_group.delete_if {|rg| provider.host_records_equal?(r, rg) }
|
119
|
+
matching.delete_if {|rg| provider.host_records_equal?(r, rg) }
|
120
|
+
end
|
121
|
+
if rr_group.size == 0 && matching.size == 0
|
122
|
+
logger.info "Round robin dns records already up to date: #{host}.#{domain}:#{type}"
|
123
|
+
end
|
124
|
+
|
125
|
+
# create the local records that don't exist remotely
|
126
|
+
rr_group.each do |r|
|
127
|
+
r = provider.setup_opts(r)
|
128
|
+
logger.info "Creating round robin dns record: #{r[:host]}.#{r[:domain]}:#{r[:type]} => #{r[:data]}"
|
129
|
+
provider.create_host_record(r)
|
130
|
+
end
|
131
|
+
|
132
|
+
# remove the remote records that don't exist locally
|
133
|
+
matching.each do |r|
|
134
|
+
logger.info "Removing round robin dns record: #{r[:host]}.#{r[:domain]}:#{r[:type]} => #{r[:data]}"
|
135
|
+
provider.destroy_host_record(r)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
64
141
|
desc <<-DESC
|
65
142
|
Sets up aliases for instance hostnames based on contents of instance.yml.
|
66
143
|
Generates /etc/hosts for remote machines and sets hostname on remote instances
|
@@ -144,11 +221,33 @@ namespace :rubber do
|
|
144
221
|
desc <<-DESC
|
145
222
|
Install ruby gems defined in the rails environment.rb
|
146
223
|
DESC
|
147
|
-
after "
|
224
|
+
after "rubber:config", "rubber:install_rails_gems" if Rubber::Util.is_rails?
|
148
225
|
task :install_rails_gems do
|
149
226
|
sudo "sh -c 'cd #{current_path} && RAILS_ENV=#{RUBBER_ENV} rake gems:install'"
|
150
227
|
end
|
151
228
|
|
229
|
+
desc <<-DESC
|
230
|
+
Convenience task for installing your defined set of ruby gems locally.
|
231
|
+
DESC
|
232
|
+
required_task :install_local_gems do
|
233
|
+
fatal("install_local_gems can only be run in development") if RUBBER_ENV != 'development'
|
234
|
+
env = rubber_cfg.environment.bind(rubber_cfg.environment.known_roles)
|
235
|
+
gems = env['gems']
|
236
|
+
expanded_gem_list = []
|
237
|
+
gems.each do |gem_spec|
|
238
|
+
if gem_spec.is_a?(Array)
|
239
|
+
expanded_gem_list << "#{gem_spec[0]}:#{gem_spec[1]}"
|
240
|
+
else
|
241
|
+
expanded_gem_list << gem_spec
|
242
|
+
end
|
243
|
+
end
|
244
|
+
expanded_gem_list = expanded_gem_list.join(' ')
|
245
|
+
|
246
|
+
logger.info "Installing gems:#{expanded_gem_list}"
|
247
|
+
open("/tmp/gem_helper", "w") {|f| f.write(gem_helper_script)}
|
248
|
+
system "sh /tmp/gem_helper install #{expanded_gem_list}"
|
249
|
+
end
|
250
|
+
|
152
251
|
desc <<-DESC
|
153
252
|
Setup ruby gems sources. Set 'gemsources' in rubber.yml to \
|
154
253
|
be an array of URI strings.
|
@@ -280,11 +379,61 @@ namespace :rubber do
|
|
280
379
|
end
|
281
380
|
end
|
282
381
|
|
382
|
+
# Rubygems always installs even if the gem is already installed
|
383
|
+
# When providing versions, rubygems fails unless versions are provided for all gems
|
384
|
+
# This helper script works around these issues by installing gems only if they
|
385
|
+
# aren't already installed, and separates versioned/unversioned into two separate
|
386
|
+
# calls to rubygems
|
387
|
+
#
|
388
|
+
set :gem_helper_script, <<-'ENDSCRIPT'
|
389
|
+
ruby - $@ <<-'EOF'
|
390
|
+
|
391
|
+
gem_cmd = ARGV[0]
|
392
|
+
gems = ARGV[1..-1]
|
393
|
+
cmd = "gem #{gem_cmd} --no-rdoc --no-ri"
|
394
|
+
|
395
|
+
to_install = {}
|
396
|
+
to_install_ver = {}
|
397
|
+
# gem list passed in, possibly with versions, as "gem1 gem2:1.2 gem3"
|
398
|
+
gems.each do |gem_spec|
|
399
|
+
parts = gem_spec.split(':')
|
400
|
+
if parts[1]
|
401
|
+
to_install_ver[parts[0]] = parts[1]
|
402
|
+
else
|
403
|
+
to_install[parts[0]] = true
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
installed = {}
|
408
|
+
`gem list --local`.each do |line|
|
409
|
+
parts = line.scan(/(.*) \((.*)\)/).first
|
410
|
+
next unless parts && parts.size == 2
|
411
|
+
installed[parts[0]] = parts[1].split(",")
|
412
|
+
end
|
413
|
+
|
414
|
+
to_install.delete_if {|g, v| installed.has_key?(g) } if gem_cmd == 'install'
|
415
|
+
to_install_ver.delete_if {|g, v| installed.has_key?(g) && installed[g].include?(v) }
|
416
|
+
|
417
|
+
# rubygems can only do asingle versioned gem at a time so we need
|
418
|
+
# to do the two groups separately
|
419
|
+
# install versioned ones first so unversioned don't pull in a newer version
|
420
|
+
to_install_ver.each do |g, v|
|
421
|
+
system "#{cmd} #{g} -v #{v}"
|
422
|
+
fail "Unable to install versioned gem #{g}:#{v}" if $?.exitstatus > 0
|
423
|
+
end
|
424
|
+
if to_install.size > 0
|
425
|
+
gem_list = to_install.keys.join(' ')
|
426
|
+
system "#{cmd} #{gem_list}"
|
427
|
+
fail "Unable to install gems" if $?.exitstatus > 0
|
428
|
+
end
|
429
|
+
|
430
|
+
'EOF'
|
431
|
+
ENDSCRIPT
|
432
|
+
|
283
433
|
# Helper for installing gems,allows one to respond to prompts
|
284
434
|
def gem_helper(update=false)
|
285
435
|
cmd = update ? "update" : "install"
|
286
436
|
|
287
|
-
|
288
437
|
opts = get_host_options('gems') do |gem_list|
|
289
438
|
expanded_gem_list = []
|
290
439
|
gem_list.each do |gem_spec|
|
@@ -298,56 +447,7 @@ namespace :rubber do
|
|
298
447
|
end
|
299
448
|
|
300
449
|
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
|
-
|
450
|
+
script = prepare_script('gem_helper', gem_helper_script)
|
351
451
|
sudo "sh #{script} #{cmd} $CAPISTRANO:VAR$", opts do |ch, str, data|
|
352
452
|
handle_gem_prompt(ch, data, str)
|
353
453
|
end
|
data/lib/rubber/tasks/rubber.rb
CHANGED
@@ -98,11 +98,70 @@ namespace :rubber do
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
|
102
|
+
desc <<-DESC
|
103
|
+
Backup database to given backup directory
|
104
|
+
The following arguments affect behavior:
|
105
|
+
BACKUP_DIR (required): Directory where backups will be stored
|
106
|
+
BACKUP_NAME (required): What to name the backup
|
107
|
+
BACKUP_CMD (required): Command used to backup
|
108
|
+
BACKUP_AGE (3): Delete rotated logs older than this many days in the past
|
109
|
+
DESC
|
110
|
+
task :backup do
|
111
|
+
dir = get_env('BACKUP_DIR', true)
|
112
|
+
name = get_env('BACKUP_NAME', true)
|
113
|
+
cmd = get_env('BACKUP_CMD', true)
|
114
|
+
age = (get_env('BACKUP_AGE') || 3).to_i
|
115
|
+
|
116
|
+
time_stamp = Time.now.strftime("%Y-%m-%d_%H-%M")
|
117
|
+
FileUtils.mkdir_p(dir)
|
118
|
+
|
119
|
+
backup_cmd = cmd.gsub(/%([^%]+)%/, '#{\1}')
|
120
|
+
backup_cmd = eval('%Q{' + backup_cmd + '}')
|
121
|
+
|
122
|
+
puts "Backing up with command:"
|
123
|
+
sh backup_cmd
|
124
|
+
puts "Backup created"
|
125
|
+
|
126
|
+
s3_prefix = "#{name}/"
|
127
|
+
backup_bucket = cloud_provider.backup_bucket
|
128
|
+
if backup_bucket
|
129
|
+
init_s3
|
130
|
+
unless AWS::S3::Bucket.list.find { |b| b.name == backup_bucket }
|
131
|
+
AWS::S3::Bucket.create(backup_bucket)
|
132
|
+
end
|
133
|
+
newest = Dir.entries(dir).sort_by {|f| File.mtime(File.join(dir,f))}.last
|
134
|
+
dest = "#{s3_prefix}#{newest}"
|
135
|
+
puts "Saving backup to S3: #{backup_bucket}:#{dest}"
|
136
|
+
AWS::S3::S3Object.store(dest, open(File.join(dir, newest)), backup_bucket)
|
137
|
+
end
|
138
|
+
|
139
|
+
tdate = Date.today - age
|
140
|
+
threshold = Time.local(tdate.year, tdate.month, tdate.day)
|
141
|
+
puts "Cleaning backups older than #{age} days"
|
142
|
+
Dir["#{dir}/*"].each do |file|
|
143
|
+
if File.mtime(file) < threshold
|
144
|
+
puts "Deleting #{file}"
|
145
|
+
FileUtils.rm_f(file)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
if backup_bucket
|
150
|
+
puts "Cleaning S3 backups older than #{age} days from: #{backup_bucket}:#{s3_prefix}"
|
151
|
+
AWS::S3::Bucket.objects(backup_bucket, :prefix => s3_prefix).clone.each do |obj|
|
152
|
+
if Time.parse(obj.about["last-modified"]) < threshold
|
153
|
+
puts "Deleting #{obj.key}"
|
154
|
+
obj.delete
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
101
160
|
desc <<-DESC
|
102
161
|
Backup database to given backup directory
|
103
162
|
The following arguments affect behavior:
|
104
163
|
BACKUP_DIR (required): Directory where db backups will be stored
|
105
|
-
BACKUP_AGE (
|
164
|
+
BACKUP_AGE (3): Delete rotated logs older than this many days in the past
|
106
165
|
DBUSER (required) User to connect to the db as
|
107
166
|
DBPASS (optional): Pass to connect to the db with
|
108
167
|
DBHOST (required): Host where the db is
|
@@ -120,15 +179,15 @@ namespace :rubber do
|
|
120
179
|
pass = nil if pass.strip.size == 0
|
121
180
|
host = get_env('DBHOST', true)
|
122
181
|
name = get_env('DBNAME', true)
|
123
|
-
|
182
|
+
|
124
183
|
raise "No db_backup_cmd defined in rubber.yml, cannot backup!" unless rubber_env.db_backup_cmd
|
125
184
|
db_backup_cmd = rubber_env.db_backup_cmd.gsub(/%([^%]+)%/, '#{\1}')
|
126
185
|
db_backup_cmd = eval('%Q{' + db_backup_cmd + '}')
|
127
|
-
|
186
|
+
|
128
187
|
puts "Backing up database with command:"
|
129
188
|
sh db_backup_cmd
|
130
189
|
puts "Created backup: #{backup_file}"
|
131
|
-
|
190
|
+
|
132
191
|
s3_prefix = "db/"
|
133
192
|
backup_bucket = cloud_provider.backup_bucket
|
134
193
|
if backup_bucket
|
@@ -150,7 +209,7 @@ namespace :rubber do
|
|
150
209
|
FileUtils.rm_f(file)
|
151
210
|
end
|
152
211
|
end
|
153
|
-
|
212
|
+
|
154
213
|
if backup_bucket
|
155
214
|
puts "Cleaning S3 backups older than #{age} days from: #{backup_bucket}:#{s3_prefix}"
|
156
215
|
AWS::S3::Bucket.objects(backup_bucket, :prefix => s3_prefix).clone.each do |obj|
|
@@ -211,7 +270,6 @@ namespace :rubber do
|
|
211
270
|
|
212
271
|
end
|
213
272
|
|
214
|
-
|
215
273
|
def get_env(name, required=false)
|
216
274
|
value = ENV[name]
|
217
275
|
raise("#{name} is required, pass using environment") if required && ! value
|
data/rails/init.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# this file just makes it easy to refer to rubber config
|
2
|
+
# variables in your apps's config'
|
3
|
+
#
|
4
|
+
|
5
|
+
require "rubber"
|
6
|
+
Rubber::initialize(RAILS_ROOT, RAILS_ENV)
|
7
|
+
|
8
|
+
::RUBBER_CONFIG = Rubber::Configuration.rubber_env
|
9
|
+
::RUBBER_INSTANCES = Rubber::Configuration.rubber_instances
|
data/test/environment_test.rb
CHANGED
@@ -115,4 +115,19 @@ class EnvironmentTest < Test::Unit::TestCase
|
|
115
115
|
assert_equal 'val5', e.var2.var9, 'env not retrieving right val'
|
116
116
|
end
|
117
117
|
|
118
|
+
def test_instances_in_expansion
|
119
|
+
instance = InstanceItem.new('host1', 'domain.com', [RoleItem.new('role1')], '')
|
120
|
+
instance.external_ip = "1.2.3.4"
|
121
|
+
instances = Instance.new(Tempfile.new('testforinstanceexpansion').path)
|
122
|
+
instances.add(instance)
|
123
|
+
|
124
|
+
File.expects(:exist?).returns(true)
|
125
|
+
YAML.expects(:load_file).returns({'var1' =>'"#{rubber_instances.for_role("role1").first.external_ip}"'})
|
126
|
+
Rubber::Configuration.expects(:rubber_instances).returns(instances)
|
127
|
+
env = Rubber::Configuration::Environment.new(nil)
|
128
|
+
e = env.bind()
|
129
|
+
|
130
|
+
assert_equal "\"1.2.3.4\"", e['var1']
|
131
|
+
end
|
132
|
+
|
118
133
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Conway
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-10-06 00:00:00 -04:00
|
13
13
|
default_executable: vulcanize
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- generators/vulcanize/templates/base/config/rubber/common/crontab
|
106
106
|
- generators/vulcanize/templates/base/config/rubber/common/profile.rc
|
107
107
|
- generators/vulcanize/templates/base/config/rubber/deploy-setup.rb
|
108
|
+
- generators/vulcanize/templates/base/config/rubber/rubber-dns.yml
|
108
109
|
- generators/vulcanize/templates/base/config/rubber/rubber.yml
|
109
110
|
- generators/vulcanize/templates/base/lib/tasks/rubber.rake
|
110
111
|
- generators/vulcanize/templates/base/script/cron-rake
|
@@ -238,6 +239,7 @@ files:
|
|
238
239
|
- lib/rubber/recipes/rubber/volumes.rb
|
239
240
|
- lib/rubber/tasks/rubber.rb
|
240
241
|
- lib/rubber/util.rb
|
242
|
+
- rails/init.rb
|
241
243
|
has_rdoc: true
|
242
244
|
homepage: http://github.com/wr0ngway/rubber
|
243
245
|
licenses: []
|