rails_pwnerer 0.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/README +17 -3
- data/lib/pwnage/app/cluster_config.rb +22 -1
- data/lib/pwnage/app/database.rb +54 -24
- data/lib/pwnage/app/main.rb +3 -1
- data/lib/pwnage/app/svn.rb +49 -19
- data/rails_pwnerer.gemspec +2 -2
- metadata +1 -1
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -9,13 +9,18 @@ welcome to test/update for other systems, and I'll be happy to merge patches,
|
|
9
9
|
or add you to the RubyForge project.
|
10
10
|
|
11
11
|
|
12
|
-
|
12
|
+
Life without +rails_pwnerer+:
|
13
13
|
|
14
14
|
Read a 20-page guide, and spend the better half of a day getting a box
|
15
15
|
ready for production. You'll be frustrated in the process, but feel
|
16
16
|
accomplished at the end. Assuming you don't do something wrong.
|
17
17
|
|
18
|
-
|
18
|
+
Read a couple more 20-page guides, and learn to push newer versions
|
19
|
+
of your application. You'll become lazy, and take shortcuts, like having
|
20
|
+
production passwords in the repository, insecure file permissions.
|
21
|
+
I won't even mention backups.
|
22
|
+
|
23
|
+
Life with +rails_pwnerer+:
|
19
24
|
|
20
25
|
1) Install rubygems:
|
21
26
|
sudo apt-get install rubygems
|
@@ -32,5 +37,14 @@ sudo rpwn install svn+ssh://your.repository.host/path/to/your_application
|
|
32
37
|
5) Reboot, or start the services right away:
|
33
38
|
sudo rpwn go live
|
34
39
|
|
35
|
-
|
40
|
+
* Keep your application updated:
|
36
41
|
sudo rpwn update your_application
|
42
|
+
|
43
|
+
* Create a backup:
|
44
|
+
sudo rpwn backup your_application
|
45
|
+
|
46
|
+
* Restore from the latest backup:
|
47
|
+
sudo rpwn restore your_application
|
48
|
+
|
49
|
+
* Bring down all the applications (panic mode):
|
50
|
+
sudo rpwn go down
|
@@ -35,6 +35,9 @@ class RailsPwnage::App::ClusterConfig
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def stop_mongrels(app_name)
|
38
|
+
# silently die if the app was completely busted
|
39
|
+
return unless File.exists? RailsPwnage::Config.path_to(app_name)
|
40
|
+
|
38
41
|
with_dir(RailsPwnage::Config.path_to(app_name)) do
|
39
42
|
system 'mongrel_rails cluster::stop'
|
40
43
|
|
@@ -44,6 +47,9 @@ class RailsPwnage::App::ClusterConfig
|
|
44
47
|
end
|
45
48
|
|
46
49
|
def start_mongrels(app_name)
|
50
|
+
# silently die if the app was completely busted
|
51
|
+
return unless File.exists? RailsPwnage::Config.path_to(app_name)
|
52
|
+
|
47
53
|
with_dir(RailsPwnage::Config.path_to(app_name)) do
|
48
54
|
system 'mongrel_rails cluster::start'
|
49
55
|
end
|
@@ -58,10 +64,21 @@ class RailsPwnage::App::ClusterConfig
|
|
58
64
|
stop_mongrels(app_name)
|
59
65
|
yield
|
60
66
|
ensure
|
61
|
-
|
67
|
+
configure_mongrels app_name
|
68
|
+
fix_permissions app_name
|
62
69
|
start_mongrels(app_name)
|
63
70
|
end
|
64
71
|
|
72
|
+
def backup(app_name, action)
|
73
|
+
case action
|
74
|
+
when :checkpoint
|
75
|
+
# nothing to do here
|
76
|
+
when :rollback
|
77
|
+
configure_mongrels app_name
|
78
|
+
fix_permissions app_name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
65
82
|
def control_all(action)
|
66
83
|
case action
|
67
84
|
when :start
|
@@ -79,6 +96,10 @@ class RailsPwnage::App::ClusterConfig
|
|
79
96
|
self.new.update(app_name, &update_proc)
|
80
97
|
end
|
81
98
|
|
99
|
+
def self.backup(app_name, action)
|
100
|
+
self.new.backup(app_name, action)
|
101
|
+
end
|
102
|
+
|
82
103
|
def self.control_all(action = :start)
|
83
104
|
self.new.control_all(action)
|
84
105
|
end
|
data/lib/pwnage/app/database.rb
CHANGED
@@ -5,25 +5,32 @@ require 'yaml'
|
|
5
5
|
class RailsPwnage::App::Database
|
6
6
|
include RailsPwnage::Base
|
7
7
|
|
8
|
-
# creates the mysql database for the application
|
9
|
-
def
|
8
|
+
# creates/drops the mysql database for the application
|
9
|
+
def admin_database(app_name, action = :create)
|
10
10
|
db_name = RailsPwnage::Config.app_dbname(app_name)
|
11
11
|
db_user = RailsPwnage::Config.app_db_user(app_name)
|
12
12
|
db_pass = RailsPwnage::Config.app_db_password(app_name)
|
13
13
|
|
14
14
|
with_dir(RailsPwnage::Config.path_to(app_name)) do
|
15
|
-
# put together the
|
15
|
+
# put together the admin script
|
16
|
+
case action
|
17
|
+
when :create
|
16
18
|
sql_commands = <<ENDSQL
|
17
19
|
CREATE DATABASE #{db_name};
|
18
20
|
GRANT ALL ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_pass}' WITH GRANT OPTION;
|
19
21
|
ENDSQL
|
22
|
+
when :drop
|
23
|
+
sql_commands = <<ENDSQL
|
24
|
+
DROP DATABASE #{db_name};
|
25
|
+
ENDSQL
|
26
|
+
end
|
20
27
|
|
21
28
|
# run it
|
22
|
-
File.open('tmp/
|
23
|
-
system "mysql -uroot < tmp/
|
29
|
+
File.open('tmp/admin_db.sql', 'w') { |f| f.write sql_commands }
|
30
|
+
system "mysql -uroot < tmp/admin_db.sql"
|
24
31
|
|
25
32
|
# cleanup
|
26
|
-
File.delete('tmp/
|
33
|
+
File.delete('tmp/admin_db.sql')
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
@@ -44,16 +51,49 @@ ENDSQL
|
|
44
51
|
File.chown(uid_for_username(pwnerer_user), gid_for_username(pwnerer_user), config_file)
|
45
52
|
end
|
46
53
|
|
47
|
-
# migrates the database
|
54
|
+
# migrates the database to the latest schema version
|
48
55
|
def migrate_database(app_name)
|
49
56
|
with_dir(RailsPwnage::Config.path_to(app_name)) do
|
50
57
|
# now migrate the database
|
51
58
|
system "rake db:migrate RAILS_ENV=production"
|
52
59
|
end
|
53
60
|
end
|
61
|
+
|
62
|
+
# creates a database dump in the backup area
|
63
|
+
def dump_database(app_name)
|
64
|
+
db_name = RailsPwnage::Config.app_dbname(app_name)
|
65
|
+
db_user = RailsPwnage::Config.app_db_user(app_name)
|
66
|
+
db_pass = RailsPwnage::Config.app_db_password(app_name)
|
67
|
+
|
68
|
+
pwnerer_user = RailsPwnage::Config.pwnerer_user
|
69
|
+
pwnerer_uid = uid_for_username(pwnerer_user)
|
70
|
+
pwnerer_gid = gid_for_username(pwnerer_user)
|
71
|
+
|
72
|
+
timestamp = Time.now.strftime '%Y%m%d%H%M%S'
|
73
|
+
dump_file = "db/#{app_name}_#{timestamp}.sql"
|
74
|
+
with_dir(RailsPwnage::Config.path_to(:backup, app_name)) do
|
75
|
+
system "mysqldump --add-drop-database --add-drop-table --extended-insert --single-transaction -u#{db_user} -p#{db_pass} #{db_name} > #{dump_file}"
|
76
|
+
# lockdown the file
|
77
|
+
File.chmod(0400, dump_file)
|
78
|
+
File.chown(pwnerer_uid, pwnerer_gid, dump_file)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# loads the latest database dump from the backup area
|
83
|
+
def load_database(app_name)
|
84
|
+
db_name = RailsPwnage::Config.app_dbname(app_name)
|
85
|
+
db_user = RailsPwnage::Config.app_db_user(app_name)
|
86
|
+
db_pass = RailsPwnage::Config.app_db_password(app_name)
|
87
|
+
|
88
|
+
with_dir(RailsPwnage::Config.path_to(:backup, app_name)) do
|
89
|
+
# find the latest dump and load it in
|
90
|
+
dump_file = Dir.glob("db/#{app_name}_*").max
|
91
|
+
system "mysql -u#{db_user} -p#{db_pass} #{db_name} < #{dump_file}"
|
92
|
+
end
|
93
|
+
end
|
54
94
|
|
55
95
|
def setup(app_name)
|
56
|
-
|
96
|
+
admin_database app_name, :create
|
57
97
|
configure_rails app_name
|
58
98
|
migrate_database app_name
|
59
99
|
end
|
@@ -65,26 +105,16 @@ ENDSQL
|
|
65
105
|
|
66
106
|
# backs up or restores the database
|
67
107
|
def backup(app_name, action)
|
68
|
-
db_name = RailsPwnage::Config.app_dbname(app_name)
|
69
|
-
db_user = RailsPwnage::Config.app_db_user(app_name)
|
70
|
-
db_pass = RailsPwnage::Config.app_db_password(app_name)
|
71
|
-
|
72
|
-
pwnerer_user = RailsPwnage::Config.pwnerer_user
|
73
|
-
pwnerer_uid = uid_for_username(pwnerer_user)
|
74
|
-
pwnerer_gid = gid_for_username(pwnerer_user)
|
75
108
|
|
76
109
|
case action
|
77
110
|
when :checkpoint
|
78
|
-
|
79
|
-
dump_file = "db/#{app_name}_#{timestamp}.sql"
|
80
|
-
with_dir(RailsPwnage::Config.path_to(:backup, app_name)) do
|
81
|
-
system "mysqldump --add-drop-database --add-drop-table --extended-insert --single-transaction -u#{db_user} -p#{db_pass} #{db_name} > #{dump_file}"
|
82
|
-
# lockdown the file
|
83
|
-
File.chmod(0400, dump_file)
|
84
|
-
File.chown(pwnerer_uid, pwnerer_gid, dump_file)
|
85
|
-
end
|
111
|
+
dump_database app_name
|
86
112
|
when :rollback
|
87
|
-
|
113
|
+
admin_database app_name, :drop
|
114
|
+
admin_database app_name, :create
|
115
|
+
load_database app_name
|
116
|
+
configure_rails app_name
|
117
|
+
migrate_database app_name
|
88
118
|
end
|
89
119
|
end
|
90
120
|
|
data/lib/pwnage/app/main.rb
CHANGED
@@ -20,14 +20,16 @@ module RailsPwnage::App
|
|
20
20
|
def self.backup(app_name, action = :checkpoint)
|
21
21
|
case action
|
22
22
|
when :checkpoint
|
23
|
+
ClusterConfig.backup app_name, action
|
23
24
|
Svn.backup app_name, action
|
24
|
-
ClusterConfig.update(app_name) do
|
25
|
+
ClusterConfig.update(app_name) do
|
25
26
|
Database.backup app_name, action
|
26
27
|
end
|
27
28
|
when :rollback
|
28
29
|
ClusterConfig.update(app_name) do
|
29
30
|
Svn.backup app_name, action
|
30
31
|
Database.backup app_name, action
|
32
|
+
ClusterConfig.backup app_name, action
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
data/lib/pwnage/app/svn.rb
CHANGED
@@ -40,33 +40,63 @@ class RailsPwnage::App::Svn
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
# dump the application files to the backup area
|
44
|
+
def dump_files(app_name)
|
44
45
|
pwnerer_user = RailsPwnage::Config.pwnerer_user
|
45
46
|
pwnerer_uid = uid_for_username(pwnerer_user)
|
46
47
|
pwnerer_gid = gid_for_username(pwnerer_user)
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
timestamp = Time.now.strftime '%Y%m%d%H%M%S'
|
50
|
+
dump_file = "files/#{app_name}_#{timestamp}.tar.gz"
|
51
|
+
|
52
|
+
with_dir(RailsPwnage::Config.path_to(:backup, app_name)) do
|
53
|
+
# create a cold copy of the application files
|
54
|
+
cold_copy = "tmp#{File::SEPARATOR}#{app_name}"
|
55
|
+
FileUtils.rm_r cold_copy if File.exists? cold_copy
|
56
|
+
FileUtils.cp_r RailsPwnage::Config.path_to(app_name), 'tmp'
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
# pack and protect the cold copy
|
60
|
-
with_dir 'tmp' do
|
61
|
-
system "tar -czf ../#{dump_file} #{app_name}"
|
58
|
+
# remove the temp garbage in the cold copy
|
59
|
+
fs = File::SEPARATOR
|
60
|
+
["cache#{fs}*", "pids#{fs}*.pid", "sessions#{fs}*"].each do |pattern|
|
61
|
+
Dir.glob("tmp#{fs}#{app_name}#{pattern}") do |entry|
|
62
|
+
next if entry =~ /\.svn$/
|
63
|
+
FileUtils.rm_r entry
|
62
64
|
end
|
63
|
-
File.chmod(400, dump_file)
|
64
|
-
File.chown(pwnerer_uid, pwnerer_gid, dump_file)
|
65
|
-
|
66
|
-
# clean up
|
67
|
-
FileUtils.rm_r cold_copy
|
68
65
|
end
|
66
|
+
|
67
|
+
# pack and protect the cold copy
|
68
|
+
with_dir 'tmp' do
|
69
|
+
system "tar -czf ../#{dump_file} #{app_name}"
|
70
|
+
end
|
71
|
+
File.chmod(400, dump_file)
|
72
|
+
File.chown(pwnerer_uid, pwnerer_gid, dump_file)
|
73
|
+
|
74
|
+
# clean up
|
75
|
+
FileUtils.rm_r cold_copy
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# loads the latest file dump from the backup area
|
80
|
+
def load_files(app_name)
|
81
|
+
dump_file = Dir.glob(RailsPwnage::Config.path_to(:backup, app_name) + File::SEPARATOR + "files/#{app_name}_*").max
|
82
|
+
with_dir(RailsPwnage::Config.path_to(:prod_apps)) do
|
83
|
+
# find the latest dump and load it in
|
84
|
+
system "tar -xzf #{dump_file}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# remove the application files
|
89
|
+
def drop_files(app_name)
|
90
|
+
FileUtils.rm_r RailsPwnage::Config.path_to(app_name) if File.exists? RailsPwnage::Config.path_to(app_name)
|
91
|
+
end
|
92
|
+
|
93
|
+
def backup(app_name, action)
|
94
|
+
case action
|
95
|
+
when :checkpoint
|
96
|
+
dump_files app_name
|
69
97
|
when :rollback
|
98
|
+
drop_files app_name
|
99
|
+
load_files app_name
|
70
100
|
end
|
71
101
|
end
|
72
102
|
|
data/rails_pwnerer.gemspec
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Rails_pwnerer-0.4
|
2
|
+
# Gem::Specification for Rails_pwnerer-0.4.5
|
3
3
|
# Originally generated by Echoe
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = %q{rails_pwnerer}
|
7
|
-
s.version = "0.4"
|
7
|
+
s.version = "0.4.5"
|
8
8
|
|
9
9
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
10
|
|