snapback 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ desc 'Drop an existing database'
2
+ arg_name 'database [, ...]'
3
+ command :drop do |c|
4
+ c.action do |global_options,options,args|
5
+ help_now!('database(s) required') if args.empty?
6
+
7
+ # Load the configuration
8
+ config = Snapback::ConfigurationLoader.factory global_options[:config]
9
+
10
+ # Connect to MySQL
11
+ mysql_client = config.mysql_client
12
+
13
+ args.each do |database|
14
+
15
+ # Start the transaction
16
+ Snapback::Transaction.new do
17
+ run_command "Selecting database: #{database}" do
18
+ mysql_client.database_select(database)
19
+ end
20
+
21
+ vg_name = config.lvm_volume_group
22
+ lv_name = "#{config.lvm_database_prefix}-#{database}"
23
+ lv_path = "/dev/#{vg_name}/#{lv_name}"
24
+
25
+ mount_database_directory = config.filesystem_mount_directory(database)
26
+ mysql_database_directory = "#{mysql_client.get_data_directory}/#{database}"
27
+
28
+ # Drop tablespaces
29
+ tables = run_command "Getting list of tables in database" do
30
+ mysql_client.database_tables
31
+ end
32
+
33
+ tables.each do |table|
34
+ table = table.to_s
35
+ run_command "Changing table engine to MyISAM: #{table}" do
36
+ mysql_client.table_set_engine(table, "MyISAM")
37
+ end
38
+
39
+ run_command "Dropping table: #{table}" do
40
+ mysql_client.table_drop(table)
41
+ end
42
+ end
43
+
44
+ # Flush
45
+ run_command "Flush tables with read lock" do
46
+ mysql_client.flush_tables
47
+ end
48
+
49
+ # Stop MySQL
50
+ run_command "Stop MySQL server" do
51
+ Snapback::MySQL::ServiceControl.stop
52
+ end
53
+
54
+ revert do
55
+ run_command "Start MySQL server" do
56
+ Snapback::MySQL::ServiceControl.start
57
+ end
58
+ end
59
+
60
+ run_command "Unlinking mysql data directory",
61
+ "unlink #{mysql_database_directory}"
62
+
63
+ revert do
64
+ run_command "Linking mysql data directory",
65
+ "ln -s #{mount_database_directory} #{mysql_database_directory}"
66
+ end
67
+
68
+ # Mount the new logical volume
69
+ run_command "Unmounting logical volume",
70
+ "umount #{mount_database_directory}"
71
+
72
+ revert do
73
+ run_command "Mounting logical volume",
74
+ "mount #{lv_path} #{mount_database_directory}"
75
+ end
76
+
77
+ # Remove logical volume
78
+ run_command "Remove logical volume",
79
+ "lvremove -f #{lv_path}"
80
+
81
+ # Start MySQL
82
+ run_command "Starting MySQL server" do
83
+ Snapback::MySQL::ServiceControl.start
84
+ end
85
+
86
+ revert do
87
+ run_command "Stopping MySQL server" do
88
+ Snapback::MySQL::ServiceControl.stop
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,179 @@
1
+ require 'lvm'
2
+ require 'snapback/configuration_loader'
3
+
4
+ desc 'Ensure the environment is setup'
5
+ command :install do |c|
6
+ c.action do |global_options,options,args|
7
+ help_now!('found arguments, none expected') if !args.empty?
8
+
9
+ Snapback::Transaction.new do
10
+
11
+ puts ""
12
+ puts "Hi!"
13
+ puts ""
14
+ puts "I'm going to guide you through setting up #{"snapback".colorize(:green)}. "
15
+ puts "This script will check to see if your environment can run "
16
+ puts "Snapback and will setup configuration files for you."
17
+ puts ""
18
+
19
+ run_command "Checking LVM is installed",
20
+ "lvm version"
21
+
22
+ lvm = nil
23
+ volume_groups = nil
24
+
25
+ # Get information from LVM
26
+ run_command "Retrieving volume group information" do
27
+ lvm = LVM::LVM.new({:command => "sudo lvm", :version => "2.02.30"})
28
+ volume_groups = lvm.volume_groups.to_a
29
+
30
+ if volume_groups.size == 0 then
31
+ raise "LVM is not setup: you do not have any volume groups"
32
+ end
33
+
34
+ true
35
+ end
36
+
37
+ puts ""
38
+
39
+ selected_volume_group = nil
40
+
41
+ # Decide which volume group to use
42
+ if volume_groups.size == 1 then
43
+ selected_volume_group = volume_groups[0];
44
+ puts "There is one volume group available"
45
+ else
46
+ puts "There are multiple volume groups available:"
47
+
48
+ volume_groups.each_with_index.map { |volume_group, index|
49
+ puts " #{index + 1}.\t#{volume_group.name.colorize(:yellow)}"
50
+ }
51
+
52
+ puts ""
53
+
54
+ volume_group_number = ask_int "Which volume group would you like Snapback use", volume_groups.size
55
+ selected_volume_group = volume_groups[volume_group_number - 1];
56
+ end
57
+
58
+ puts "Snapback will use the volume group #{selected_volume_group.name.colorize(:green)}"
59
+ puts ""
60
+
61
+ # Check for mount directory
62
+ mysql_mount_directory = ask_string "Where do you want to mount your logical volumes [/mnt/mysql]"
63
+ mysql_mount_directory = "/mnt/mysql" if mysql_mount_directory.empty?
64
+
65
+ run_command "Changing owner to mysql: #{mysql_mount_directory}",
66
+ "chown -R mysql:mysql #{mysql_mount_directory}"
67
+
68
+ has_mysql_mount_directory = run_command "Checking for directory #{mysql_mount_directory}" do
69
+ File.directory? mysql_mount_directory
70
+ end
71
+
72
+ if !has_mysql_mount_directory then
73
+ run_command "Creating directory #{mysql_mount_directory}",
74
+ "mkdir -p #{mysql_mount_directory}"
75
+
76
+ revert do
77
+ run_command "Removing directory #{mysql_mount_directory}",
78
+ "rm -rf #{mysql_mount_directory}"
79
+ end
80
+ end
81
+
82
+ # MySQL connection
83
+ mysql_client = Snapback::MySQL::ClientControl.instance
84
+
85
+ while true
86
+ puts ""
87
+ puts "Enter the credentials to connect to MySQL on localhost"
88
+
89
+ mysql_client.hostname = "localhost"
90
+
91
+ # Ask for username
92
+ mysql_client.username = ask_string "MySQL username [root]"
93
+ mysql_client.username = "root" if mysql_client.username.empty?
94
+
95
+ # Ask for password
96
+ mysql_client.password = ask_string "MySQL password"
97
+
98
+ connected = run_command "Connecting to MySQL database" do
99
+ begin
100
+ mysql_client.connect
101
+ true
102
+ rescue
103
+ false
104
+ end
105
+ end
106
+
107
+ if connected then
108
+ break
109
+ else
110
+ next
111
+ end
112
+ end
113
+
114
+ # MySQL properties
115
+
116
+ has_innodb_file_per_table = run_command "Checking innodb_file_per_table is activated" do
117
+ mysql_client.has_innodb_file_per_table?
118
+ end
119
+
120
+ if !has_innodb_file_per_table then
121
+ run_command "Setting innodb_file_per_table to ON" do
122
+ mysql_client.set_innodb_file_per_table true
123
+ end
124
+
125
+ revert do
126
+ run_command "Setting innodb_file_per_table to OFF" do
127
+ mysql_client.set_innodb_file_per_table false
128
+ end
129
+ end
130
+ end
131
+
132
+ run_command "Writing configuration to file" do
133
+ config = {
134
+ 'version' => Snapback::VERSION,
135
+ 'lvm' => {
136
+ 'volume_group' => "#{selected_volume_group.name}",
137
+ 'database_prefix' => "snapback-database",
138
+ 'snapshot_prefix' => "snapback-snapshot"
139
+ },
140
+
141
+ 'mysql' => {
142
+ 'hostname' => mysql_client.hostname,
143
+ 'username' => mysql_client.username,
144
+ 'password' => mysql_client.password
145
+ },
146
+
147
+ 'filesystem' => {
148
+ 'mount' => mysql_mount_directory
149
+ }
150
+ }
151
+
152
+ File.open(global_options[:config], 'w+') { |f| f.write(config.to_yaml) }
153
+ end
154
+
155
+ revert do
156
+ run_command "Removing configuration file" do
157
+ File.unlink global_options[:config]
158
+ end
159
+ end
160
+
161
+ puts ""
162
+ puts "Snapback has now been configured."
163
+ puts "To start using Snapback, run the following command: "
164
+ puts ""
165
+ puts "sudo snapback help".colorize(:yellow)
166
+ puts ""
167
+ puts "If your operating system uses AppArmor (e.g.: Ubuntu) you will need to "
168
+ puts "manually update your #{"/etc/apparmor.d/usr/sbin/mysqld".colorize(:green)} file "
169
+ puts "to include the following lines:"
170
+ puts "\t#{"/mnt/mysql/ rwk,".colorize(:green)}"
171
+ puts "\t#{"/mnt/mysql/** rwk,".colorize(:green)}"
172
+ puts ""
173
+ puts "Then manually restart AppArmor and MySQL using: "
174
+ puts "\t#{"service apparmor restart".colorize(:green)}"
175
+ puts "\t#{"service mysql restart".colorize(:green)}"
176
+ puts ""
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,97 @@
1
+ desc 'Mount an existing database'
2
+ arg_name 'database [, ...]'
3
+ command :mount do |c|
4
+ c.action do |global_options,options,args|
5
+ # Ensure all flags and switches are present
6
+ help_now!('database(s) required') if args.empty?
7
+
8
+ # Load the configuration
9
+ config = Snapback::ConfigurationLoader.factory global_options[:config]
10
+
11
+ # Connect to MySQL
12
+ mysql_client = config.mysql_client
13
+
14
+ # For each database
15
+ args.each do |database|
16
+
17
+ # Start the transaction
18
+ Snapback::Transaction.new do
19
+ run_command "Selecting database: #{database}" do
20
+ mysql_client.database_select(database)
21
+ end
22
+
23
+ vg_name = config.lvm_volume_group
24
+ lv_name = config.lvm_logical_database database
25
+ lv_path = "/dev/#{vg_name}/#{lv_name}"
26
+
27
+ mount_database_directory = config.filesystem_mount_directory(database)
28
+ mysql_database_directory = "#{mysql_client.get_data_directory}/#{database}"
29
+
30
+ lv_exists = run_command "Checking logical volume exists" do
31
+ File.exists?(lv_path)
32
+ end
33
+
34
+ if !lv_exists then
35
+ raise "Logical volume #{lv_path.colorize(:red)} does not exist"
36
+ end
37
+
38
+ # Flush
39
+ run_command "Flush tables with read lock" do
40
+ mysql_client.flush_tables
41
+ end
42
+
43
+ # Stop MySQL
44
+ run_command "Stop MySQL server" do
45
+ Snapback::MySQL::ServiceControl.stop
46
+ end
47
+
48
+ revert do
49
+ run_command "Start MySQL server" do
50
+ Snapback::MySQL::ServiceControl.start
51
+ end
52
+ end
53
+
54
+ directory_exists = run_command "Checking if mount directory exists" do
55
+ File.directory? mount_database_directory
56
+ end
57
+
58
+ # Check mount directory exists
59
+ if !directory_exists then
60
+ run_command "Creating mount directory",
61
+ "mkdir #{mount_database_directory}"
62
+
63
+ revert do
64
+ run_command "Removing mount directory",
65
+ "rmdir #{$mount_database_directory}"
66
+ end
67
+
68
+ run_command "Changing permissions of mount directory",
69
+ "chmod 0777 #{mount_database_directory}"
70
+ end
71
+
72
+ run_command "Mounting directory",
73
+ "mount #{lv_path} #{mount_database_directory}"
74
+
75
+ run_command "Linking mount directory",
76
+ "ln -s #{mount_database_directory} #{mysql_database_directory}"
77
+
78
+ run_command "Changing ownership of: #{mount_database_directory}",
79
+ "chown -R mysql:mysql #{mount_database_directory}"
80
+
81
+ run_command "Changing ownership of: #{mysql_database_directory}",
82
+ "chown -R mysql:mysql #{mysql_database_directory}"
83
+
84
+ # Start MySQL
85
+ run_command "Start MySQL server" do
86
+ Snapback::MySQL::ServiceControl.start
87
+ end
88
+
89
+ revert do
90
+ run_command "Stop MySQL server" do
91
+ Snapback::MySQL::ServiceControl.stop
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,161 @@
1
+ desc 'Rollback the working copy to the snapshot'
2
+ arg_name 'database [, ...]'
3
+ command :rollback do |c|
4
+ c.action do |global_options,options,args|
5
+ help_now!('database(s) required') if args.empty?
6
+
7
+ # Load the configuration
8
+ config = Snapback::ConfigurationLoader.factory global_options[:config]
9
+
10
+ # Connect to MySQL
11
+ mysql_client = config.mysql_client
12
+
13
+ args.each do |database|
14
+
15
+ # Start the transaction
16
+ Snapback::Transaction.new do
17
+
18
+ run_command "Selecting database: #{database}" do
19
+ mysql_client.database_select(database)
20
+ end
21
+
22
+ vg_name = config.lvm_volume_group
23
+ lv_name = "#{config.lvm_database_prefix}-#{database}"
24
+ lv_path = "/dev/#{vg_name}/#{lv_name}"
25
+
26
+ mount_database_directory = config.filesystem_mount_directory(database)
27
+ mysql_database_directory = "#{mysql_client.get_data_directory}/#{database}"
28
+
29
+ # Drop tablespaces
30
+ tables = run_command "Getting list of tables in database" do
31
+ mysql_client.database_tables
32
+ end
33
+
34
+ tables.each do |table|
35
+ table = table.to_s
36
+ run_command "Changing table engine to MyISAM: #{table}" do
37
+ mysql_client.table_set_engine(table, "MyISAM")
38
+ end
39
+
40
+ run_command "Dropping table: #{table}" do
41
+ mysql_client.table_drop(table)
42
+ end
43
+ end
44
+
45
+ # Flush
46
+ run_command "Flush tables with read lock" do
47
+ mysql_client.flush_tables
48
+ end
49
+
50
+ # Stop MySQL
51
+ run_command "Stop MySQL server" do
52
+ Snapback::MySQL::ServiceControl.stop
53
+ end
54
+
55
+ revert do
56
+ run_command "Start MySQL server" do
57
+ Snapback::MySQL::ServiceControl.start
58
+ end
59
+ end
60
+
61
+ # Unlink
62
+ run_command "Unlinking mysql data directory",
63
+ "unlink #{mysql_database_directory}"
64
+
65
+ revert do
66
+ run_command "Linking mysql data directory",
67
+ "ln -s #{mount_database_directory} #{mysql_database_directory}"
68
+ end
69
+
70
+ # Unmount
71
+ run_command "Unmounting logical volume",
72
+ "umount #{mount_database_directory}"
73
+
74
+ revert do
75
+ run_command "Mounting logical volume",
76
+ "mount #{lv_path} #{mount_database_directory}"
77
+ end
78
+
79
+ # Deactivate
80
+ run_command "De-activating logical volume",
81
+ "lvchange -an #{lv_path}"
82
+
83
+ revert do
84
+ run_command "Re-activating logical volume",
85
+ "lvchange -ay #{lv_path}"
86
+ end
87
+
88
+ # Merge the old logical volume into the new one
89
+ # lvconvert --merge /dev/{vgName}/backup-{dbName}
90
+ run_command "Rolling back to the snapshot",
91
+ "lvconvert --merge /dev/#{vg_name}/#{config.lvm_snapshot_prefix}-#{database}"
92
+
93
+ # Active the master drive
94
+ run_command "Activating logical volume",
95
+ "lvchange -ay #{lv_path}"
96
+
97
+ revert do
98
+ run_command "Deactivating logical volume",
99
+ "lvchange -an #{lv_path}"
100
+ end
101
+
102
+ # Mount the master drive
103
+ run_command "Mounting logical volume",
104
+ "mount #{lv_path} #{mount_database_directory}"
105
+
106
+ revert do
107
+ run_command "Unmounting logical volume",
108
+ "umount #{mount_database_directory}"
109
+ end
110
+
111
+ # Symbolic-link the MySQL data directory to the new logical volume
112
+ run_command "Linking mysql data directory",
113
+ "ln -s #{mount_database_directory} #{mysql_database_directory}"
114
+
115
+ revert do
116
+ run_command "Unlinking mysql data directory",
117
+ "unlink #{mysql_database_directory}"
118
+ end
119
+
120
+ # Change the permissions & ownership to MySQL
121
+ run_command "Changing owner to mysql: #{mysql_database_directory}",
122
+ "chown -R mysql:mysql #{mysql_database_directory}"
123
+
124
+ run_command "Changing owner to mysql: #{mount_database_directory}",
125
+ "chown -R mysql:mysql #{mount_database_directory}"
126
+
127
+ # Start MySQL
128
+ run_command "Starting MySQL server" do
129
+ Snapback::MySQL::ServiceControl.start
130
+ end
131
+
132
+ revert do
133
+ run_command "Stopping MySQL server" do
134
+ Snapback::MySQL::ServiceControl.stop
135
+ end
136
+ end
137
+
138
+ # Reconnect
139
+ run_command "Re-connecting to MySQL" do
140
+ mysql_client.connect
141
+ end
142
+
143
+ run_command "Re-selecting database: #{database}" do
144
+ mysql_client.database_select(database)
145
+ end
146
+
147
+ # Import tablespaces and optimize table
148
+ tables = run_command "Getting list of tables in database" do
149
+ mysql_client.database_tables
150
+ end
151
+
152
+ tables.each do |table|
153
+ table = table.to_s
154
+ run_command "Optimizing table: #{table}" do
155
+ mysql_client.table_optimize(table)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end