rails_pwnerer 0.4 → 0.4.5

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/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