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 CHANGED
@@ -1,3 +1,5 @@
1
+ v0.4.5. Implemented 'restore'.
2
+
1
3
  v0.4. Implemented 'backup'.
2
4
 
3
5
  v0.3.5. Implemented 'go live' and 'go panic' to take all application processes up / down.
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
- Live without +rails_pwnerer+:
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
- Live with +rails_pwnerer+:
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
- 6) Keep your application updated
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
- # TODO: reconfigure the mongrels if the configuration database changed
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
@@ -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 create_databse(app_name)
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 creation script
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/create_db.sql', 'w') { |f| f.write sql_commands }
23
- system "mysql -uroot < tmp/create_db.sql"
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/create_db.sql')
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 so it's ready
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
- create_databse app_name
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
- timestamp = Time.now.strftime '%Y%m%d%H%M%S'
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
- # TODO: rollback
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
 
@@ -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
@@ -40,33 +40,63 @@ class RailsPwnage::App::Svn
40
40
  end
41
41
  end
42
42
 
43
- def backup(app_name, action)
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
- case action
49
- when :checkpoint
50
- timestamp = Time.now.strftime '%Y%m%d%H%M%S'
51
- dump_file = "files/#{app_name}_#{timestamp}.tar.gz"
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
- with_dir(RailsPwnage::Config.path_to(:backup, app_name)) do
54
- # create a cold copy of the application files
55
- cold_copy = "tmp#{File::SEPARATOR}#{app_name}"
56
- FileUtils.rm_r cold_copy if File.exists? cold_copy
57
- FileUtils.cp_r RailsPwnage::Config.path_to(app_name), 'tmp'
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
 
@@ -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
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_pwnerer
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.4"
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Costan