snapback 0.0.1 → 0.0.3

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.
@@ -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