Class: RailsPwnerer::App::Database

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/rails_pwnerer/app/db/mysql.rb

Instance Method Summary collapse

Methods included from Base

_setup_unix, _setup_windows, all_packages, all_packages_without_caching, #atomic_erase, #atomic_read, #atomic_write, #best_package_matching, #check_rails_root, #control_boot_script, #cpu_cores, #current_user, #gem_exists?, #gid_for_username, #group_for_username, #hook_boot_script, #install_gem, #install_gems, #install_package, #install_package_impl, #install_package_matching, #install_packages, #kill_tree, #os_distro, package_info_hash, #path_to_boot_script, #path_to_boot_script_defaults, #path_to_gemdir, #process_info, #prompt_user_for_password, #remove_package, #remove_packages, #search_packages, #uid_for_username, #unroll_collection, #update_all_packages, #update_all_packages_impl, #update_gems, #update_package_metadata, #upgrade_gem, #upgrade_gems, #upgrade_package, #upgrade_package_impl, #upgrade_packages, #with_package_source, #with_temp_dir

Instance Method Details

#admin_database(app_name, instance_name, action = :create) ⇒ Object

creates/drops the mysql database for the application



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 9

def admin_database(app_name, instance_name, action = :create)
  app_config = RailsPwnerer::Config[app_name, instance_name]
  # exit and don't complain if the app is busted
  return unless app_config and File.exists? app_config[:app_path]

  db_name, db_user, db_pass = app_config[:db_name], app_config[:db_user], app_config[:db_pass]
  
  with_temp_dir do
    # put together the admin script
    case action
    when :create
    sql_commands = <<ENDSQL
      CREATE DATABASE #{db_name} DEFAULT CHARSET=utf8;
      GRANT ALL ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_pass}' WITH GRANT OPTION;
ENDSQL
    when :rekey
    sql_commands = <<ENDSQL
      GRANT ALL ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_pass}' WITH GRANT OPTION;
ENDSQL
    
    when :drop
    sql_commands = <<ENDSQL
      DROP DATABASE #{db_name};
ENDSQL
    end
    
    # run it
    File.open('admin_db.sql', 'w') { |f| f.write sql_commands }
    dbroot_name = RailsPwnerer::Config[:host][:dbroot_name]
    dbroot_pass = RailsPwnerer::Config[:host][:dbroot_pass]
    dbpass_arg = dbroot_pass.empty? ? '' : "-p#{dbroot_pass}"
    system "mysql -u#{dbroot_name} #{dbpass_arg} < admin_db.sql"
    
    # cleanup
    File.delete('admin_db.sql')
  end    
end

#configure_rails(app_name, instance_name) ⇒ Object

configures rails to use the database in the production environment



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 69

def configure_rails(app_name, instance_name)
  app_config = RailsPwnerer::Config[app_name, instance_name]
  db_name, db_user, db_pass = app_config[:db_name], app_config[:db_user], app_config[:db_pass]
  
  config_file = File.join app_config[:app_path], 'config', 'database.yml'
  configuration = File.open(config_file, 'r') { |f| YAML.load f }
  configuration['production'] ||= {}
  if !configuration['production']['adapter'] or
     !(/mysql/ =~ configuration['production']['adapter'])
    configuration['production']['adapter'] = 'mysql2'
  end
  configuration['production']['encoding'] ||= 'utf8'
  configuration['production'].merge! 'database' => db_name, 'username' => db_user, 'password' => db_pass
  configuration['production'].merge! mysql_host_info()    
  File.open(config_file, 'w') { |f| YAML.dump(configuration, f) }
  
  # bonus: lock down the database so only the right user can access it
  pwnerer_user = app_config[:pwnerer_user]
  File.chmod(0600, config_file)
  File.chown(uid_for_username(pwnerer_user), gid_for_username(pwnerer_user), config_file)
end

#control_all(action) ⇒ Object



178
179
180
181
182
183
184
185
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 178

def control_all(action)
  case action
  when :start
    control_boot_script('mysql', :start)
  when :stop
    control_boot_script('mysql', :stop)
  end
end

#dump_database(app_name, instance_name) ⇒ Object

creates a database dump in the backup area



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 104

def dump_database(app_name, instance_name)
  app_config = RailsPwnerer::Config[app_name, instance_name]
  db_name, db_user, db_pass = app_config[:db_name], app_config[:db_user], app_config[:db_pass]

  pwnerer_user = app_config[:pwnerer_user]
  pwnerer_uid = uid_for_username(pwnerer_user)
  pwnerer_gid = gid_for_username(pwnerer_user)
  
  timestamp = Time.now.strftime '%Y%m%d%H%M%S'
  dump_file = "db/#{app_name}.#{instance_name}_#{timestamp}.sql"
  Dir.chdir app_config[:backup_path] do
    system("mysqldump --add-drop-database --add-drop-table" +
           " --skip-extended-insert --single-transaction" +
           " -u#{db_user} -p#{db_pass} #{db_name} > #{dump_file}")
    # lockdown the file
    File.chmod(0400, dump_file)
    File.chown(pwnerer_uid, pwnerer_gid, dump_file)
  end
end

#load_database(app_name, instance_name) ⇒ Object

loads the latest database dump from the backup area



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 125

def load_database(app_name, instance_name)
  app_config = RailsPwnerer::Config[app_name, instance_name]
  db_name, db_user, db_pass = app_config[:db_name], app_config[:db_user], app_config[:db_pass]
  
  Dir.chdir app_config[:backup_path] do
    # find the latest dump and load it in
    dump_file = Dir.glob("db/#{app_name}.#{instance_name}_*").max
    unless dump_file
      dump_file = Dir.glob("db/#{app_name}.*").max
    end
    Kernel.system "mysql -u#{db_user} -p#{db_pass} #{db_name} < #{dump_file}"
  end
end

#manage(app_name, instance_name, action) ⇒ Object

backs up or restores the database



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 158

def manage(app_name, instance_name, action)
  case action
  when :checkpoint
    dump_database app_name, instance_name
  when :rollback
    admin_database app_name, instance_name, :drop
    admin_database app_name, instance_name, :create
    load_database app_name, instance_name
    configure_rails app_name, instance_name
    migrate_database app_name, instance_name
  when :rekey
    admin_database app_name, instance_name, :rekey
    configure_rails app_name, instance_name
  when :db_reset
    admin_database app_name, instance_name, :drop
    admin_database app_name, instance_name, :create
    migrate_database app_name, instance_name
  end
end

#migrate_database(app_name, instance_name) ⇒ Object

migrates the database to the latest schema version



92
93
94
95
96
97
98
99
100
101
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 92

def migrate_database(app_name, instance_name)
  Dir.chdir RailsPwnerer::Config[app_name, instance_name][:app_path] do
    # now migrate the database
    if File.exist?('Gemfile')
      Kernel.system 'bundle exec rake db:migrate RAILS_ENV=production'
    else
      Kernel.system 'rake db:migrate RAILS_ENV=production'
    end
  end
end

#mysql_host_infoObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 47

def mysql_host_info()
  # try UNIX sockets first, for best performance
  begin
    socket_line = `mysql_config --socket`
    socket_line.strip!
    return {'socket' => socket_line} unless socket_line.empty?
  rescue
  end
    
  # oh well, TCP will have to suffice
  begin
    port_line = `mysql_config --port`
    port = port_line.strip.to_i
    return {'host' => 'localhost', 'port' => port} unless port == 0    
  rescue
  end
  
  # giving up, the mysql gem will have to figure it out
  return {}
end

#remove(app_name, instance_name) ⇒ Object



152
153
154
155
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 152

def remove(app_name, instance_name)
  control_boot_script('mysql', :start)
  admin_database app_name, instance_name, :drop    
end

#setup(app_name, instance_name) ⇒ Object



139
140
141
142
143
144
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 139

def setup(app_name, instance_name)
  control_boot_script('mysql', :start)
  admin_database app_name, instance_name, :create
  configure_rails app_name, instance_name
  migrate_database app_name, instance_name
end

#update(app_name, instance_name) ⇒ Object



146
147
148
149
150
# File 'lib/rails_pwnerer/app/db/mysql.rb', line 146

def update(app_name, instance_name)
  control_boot_script('mysql', :start)
  configure_rails app_name, instance_name
  migrate_database app_name, instance_name
end