rubber 1.0.2 → 1.1.0
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/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: []
|