snapback 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ data.tar.gz: 1a664b28c0d9ab5bc744ee05541062e603d3e637
4
+ metadata.gz: de56065c29b02b45a8ab80b1f06922c2ad5349b3
5
+ SHA512:
6
+ data.tar.gz: d82b6e0c7f95d7f83251da16087b9ca15c8ba0deb3a9762eca97d85944802074b4f4e8a32cff1f7f9e6b246f137a41642dfd6a5cb4d91b94278278a0572006ab
7
+ metadata.gz: f264844f630a2f7973c99ec5dd7c912af64bae519523110f287888ca260b00407cb56021c7677527a88ade801b5751fc4d97f40a9cafa6821e833aa7e3a151fd
data/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # Snapback
2
+
3
+ Version 0.1 Alpha
4
+
5
+ Create MySQL snapshots for easy development rollback.
6
+
7
+ ## Project Details
8
+
9
+ ### Use case
10
+
11
+ Large databases can be cumbersome to reload particularly when testing database migrations.
12
+ This gem utilises logical volume management (LVM) to create database snapshots, allowing you to rollback to specified point in time.
13
+
14
+ ### Problem domain
15
+
16
+ This scripts automates the concepts that are discussed in the following articles:
17
+
18
+ * lullabot.com -- [MySQL Backups Using LVM Snapshots](http://www.lullabot.com/articles/mysql-backups-using-lvm-snapshots)
19
+ * tldp.org -- [Taking a Backup Using Snapshots](http://tldp.org/HOWTO/LVM-HOWTO/snapshots_backup.html)
20
+ * mysqlperformanceblog.com -- [Faster Point In Time Recovery with LVM2 Snaphots and Binary Logs](http://www.mysqlperformanceblog.com/2012/02/23/faster-point-in-time-recovery-with-lvm2-snaphots-and-binary-logs/)
21
+
22
+ If you'd like more information on how to setup LVM on a Linux installation, see:
23
+
24
+ * howtogeek.com -- [What is Logical Volume Management and How Do You Enable It in Ubuntu?](http://www.howtogeek.com/howto/36568/what-is-logical-volume-management-and-how-do-you-enable-it-in-ubuntu/)
25
+
26
+
27
+ ### Dependencies
28
+
29
+ * Linux (tested on Ubuntu 12.04.1 LTS)
30
+ * Sudo shell access
31
+ * Ruby (tested on version 1.8.7)
32
+ * Logical volume management (tested on version 2.02.66(2))
33
+ * MySQL (tested on version 5.5.29-0ubuntu0.12.04.1)
34
+
35
+ ### Installation
36
+
37
+ # If the MySQL client libraries aren't already installed, you may need to run this
38
+ sudo apt-get update
39
+ sudo apt-get install build-essential
40
+ sudo apt-get install libmysql-ruby
41
+ sudo apt-get install libmysqlclient-dev
42
+
43
+ # Install the gem
44
+ sudo gem install snapback
45
+
46
+ The gem should also automatically install the following gems:
47
+
48
+ * mysql
49
+ * colorize
50
+ * open4
51
+ * ruby-lvm
52
+
53
+ You must then enable multiple tablespaces.
54
+ Add a line to the [mysqld] section of your MySQL my.cnf:
55
+
56
+ [mysqld]
57
+ innodb_file_per_table=ON
58
+
59
+ ### Configuration
60
+
61
+ If you're on Ubuntu (or other Linux system that uses AppArmor), you may need to allow MySQL to use the mounted directories.
62
+
63
+ sudo nano /etc/apparmor.d/usr.sbin/mysqld
64
+
65
+ Add the following lines to the file:
66
+
67
+ /mnt/mysql/ rwk,
68
+ /mnt/mysql/** rwk,
69
+
70
+ Restart AppArmor and MySQL
71
+
72
+ service apparmor restart
73
+ service mysql restart
74
+
75
+ ### Usage
76
+
77
+ Only recommended for use on virtual machines.
78
+ Not recommended for production environments.
79
+
80
+ ## Setup
81
+
82
+ To start using this application, you must run this once:
83
+
84
+ sudo snapback install
85
+
86
+ This creates the appropriate directories and checks that you have the required programs installed.
87
+ It will also ask you questions about your environment and save your configuration in your home directory.
88
+
89
+ ## Creating a new database
90
+
91
+ To create a new database, you must specify the following values:
92
+
93
+ * The name of the new database
94
+ * The size you expect the database to be (+10% for good measure)
95
+
96
+ E.g.: Create a database called "camera" which should hold 1G
97
+
98
+ sudo snapback create camera --size 1G
99
+
100
+ ## Snapshot an existing database
101
+
102
+ To make a snapshot, you must specify the following values:
103
+
104
+ * The name of the database being snapshot
105
+ * The amount you expect the database to grow by (+10% for good measure). Remember that deleting items in the database will cause the database grow (as you're recording changes, not size of files).
106
+
107
+ E.g.: Snapshot a database called "camera", where the changes will amount to an extra 100MB.
108
+
109
+ sudo snapback snapshot camera --size 100M
110
+
111
+ ## Rollback a database to the snapshot
112
+
113
+ Once you've finished trying to make changes in your database, you can create a snapshot
114
+
115
+ E.g.: Rollback the database "camera" back to the date of the snapshot.
116
+
117
+ sudo snapback rollback camera
118
+
119
+ ## Drop a database
120
+
121
+ Once you've finished with the database, you can drop it from MySQL and remove the logical volumes.
122
+
123
+ E.g.: Drop the database "camera".
124
+
125
+ sudo snapback drop camera
126
+
127
+ ## Mount existing devices
128
+
129
+ If you want to mount a logical volume (e.g.: after a reboot), you can use the mount command.
130
+
131
+ E.g.: Continue using the database "camera"
132
+
133
+ sudo snapback mount camera
134
+
135
+ ## Unmount existing devices
136
+
137
+ If (for any reason) you want to unmount a logical volume (e.g.: disable a database temporarily), you can use the unmount command.
138
+
139
+ E.g.: Stop using the database "camera"
140
+
141
+ sudo snapback unmount camera
142
+
143
+ ## LVM Issues
144
+
145
+ If you're getting an error message similar to following:
146
+
147
+ File descriptor ? (/home/?/.snapback.yml) leaked on lvcreate invocation.
148
+
149
+ You can circumvent this error by adding the following environmental variable before your command:
150
+
151
+ LVM_SUPPRESS_FD_WARNINGS=1
152
+
153
+ For example:
154
+
155
+ sudo LVM_SUPPRESS_FD_WARNINGS=1 sudo snapback snapshot camera --size 100M
156
+
157
+ ## Licence
158
+
159
+ Copyright (C) 2013, [Bashkim Isai](http://www.bashkim.com.au)
160
+
161
+ This script is distributed under the MIT licence.
162
+
163
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
164
+
165
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
166
+
167
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
168
+
169
+ ## Contributors
170
+
171
+ * @bashaus -- [Bashkim Isai](http://www.bashkim.com.au/)
172
+
173
+ If you fork this project and create a pull request add your GitHub username, your full name and website to the end of list above.
data/bin/snapback ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'yaml'
5
+ require 'optparse'
6
+ require 'pp'
7
+
8
+ require 'snapback/options'
9
+ require 'snapback/transaction'
10
+ require 'snapback/database'
11
+ require 'snapback/dsl'
12
+
13
+ begin
14
+ # Ensure user is root
15
+ if Process.uid != 0 then
16
+ raise "Must run as root"
17
+ end
18
+ rescue
19
+ $stderr.puts "#{$!.to_s.red}"
20
+ exit
21
+ end
22
+
23
+ begin
24
+ $options = Snapback::Options.parse(ARGV)
25
+
26
+ case $options[:command]
27
+ when "install"
28
+ require "snapback/app/install"
29
+ Snapback::App::Install.instance.go
30
+
31
+ puts ""
32
+ exit
33
+ end
34
+
35
+ begin
36
+ # Read confirmation options
37
+ $config = YAML.load_file($options[:config])
38
+ rescue
39
+ raise "Could not load configuration file: #{$options[:config]}"
40
+ end
41
+
42
+ # Connect to MySQL
43
+ $database = Snapback::Database.instance
44
+ $database.hostname = $config['mysql']['hostname']
45
+ $database.username = $config['mysql']['username']
46
+ $database.password = $config['mysql']['password']
47
+ $database.connect
48
+
49
+ case $options[:command]
50
+ when "create"
51
+ require "snapback/app/create"
52
+ Snapback::App::Create.instance.go
53
+ when "snapshot"
54
+ require "snapback/app/snapshot"
55
+ Snapback::App::Snapshot.instance.go
56
+ when "commit"
57
+ require "snapback/app/commit"
58
+ Snapback::App::Commit.instance.go
59
+ when "rollback"
60
+ require "snapback/app/rollback"
61
+ Snapback::App::Rollback.instance.go
62
+ when "drop"
63
+ require "snapback/app/drop"
64
+ Snapback::App::Drop.instance.go
65
+ when "mount"
66
+ require "snapback/app/mount"
67
+ Snapback::App::Mount.instance.go
68
+ when "unmount"
69
+ require "snapback/app/unmount"
70
+ Snapback::App::Unmount.instance.go
71
+ end
72
+ rescue
73
+ puts ""
74
+ $stderr.puts "#{$!.to_s.red}"
75
+ puts "Use -v (--verbose) to view entire process".red if !$options[:verbose]
76
+ puts "Rolling back".red
77
+ puts ""
78
+
79
+ Snapback::Transaction.instance.do_rollback
80
+ end
81
+
82
+ puts ""
@@ -0,0 +1,35 @@
1
+ require "singleton"
2
+
3
+ module Snapback
4
+ module App
5
+ class Commit
6
+ include Singleton
7
+
8
+ def go
9
+ volume_group_name = "#{$config['lvm']['volume_group']}"
10
+ logical_volume_name = "#{$config['lvm']['prefix_backup']}-#{$options[:database]}"
11
+
12
+ # Flush
13
+ exec_flush
14
+
15
+ # Stop the MySQL Server
16
+ $database.server_stop
17
+
18
+ on_rollback lambda {
19
+ $database.server_start
20
+ }
21
+
22
+ # Remove logical volume
23
+ run "Committing logical volume",
24
+ "lvremove -f /dev/#{volume_group_name}/#{logical_volume_name}"
25
+
26
+ # Start the MySQL Server
27
+ $database.server_start
28
+
29
+ on_rollback lambda {
30
+ $database.server_stop
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,117 @@
1
+ require "singleton"
2
+
3
+ module Snapback
4
+ module App
5
+ class Create
6
+ include Singleton
7
+
8
+ def go
9
+ # Ensure we have a size parameter
10
+ if $options[:size].nil? then
11
+ raise "You must specify a size attribute. E.g.: -s 500M"
12
+ end
13
+
14
+ volume_group_name = "#{$config['lvm']['volume_group']}"
15
+ logical_volume_name = "#{$config['lvm']['prefix_database']}-#{$options[:database]}"
16
+ mount_dir = get_mount_dir $options[:database]
17
+ mysql_data_dir = $database.get_data_dir
18
+
19
+ if !check "Checking database exists #{$options[:database]}", lambda {
20
+ $database.db_exists?($options[:database])
21
+ } then
22
+ check "Creating database '#{$options[:database]}'", lambda {
23
+ $database.db_create($options[:database])
24
+ }
25
+
26
+ on_rollback lambda {
27
+ check "Database '#{$options[:database]}' is being dropped", lambda {
28
+ $database.db_drop($options[:database])
29
+ }
30
+ }
31
+ end
32
+
33
+ exec_flush
34
+
35
+ # Stop the MySQL Server
36
+ $database.server_stop
37
+
38
+ on_rollback lambda {
39
+ $database.server_start
40
+ }
41
+
42
+ # Create a new logical volume (500MB)
43
+ # lvcreate –L 500MB –n mysql-{dbName} {vgName};
44
+ run "Create logical volume",
45
+ "lvcreate -L #{$options[:size]} -n #{logical_volume_name} #{volume_group_name}"
46
+
47
+ on_rollback lambda {
48
+ run "Removing logical volume",
49
+ "lvremove -f /dev/#{volume_group_name}/#{logical_volume_name}"
50
+ }
51
+
52
+ # Format the logical volume in ext4 format
53
+ # mkfs.ext4 /dev/{vgName}/mysql-{dbName};
54
+ run "Format logical volume filesystem",
55
+ "mkfs.ext4 /dev/#{volume_group_name}/#{logical_volume_name}"
56
+
57
+ # Create a new directory for where the MySQL database can be mounted
58
+ # mkdir /mnt/mysql/{dbName};
59
+
60
+ if !File.directory? mount_dir then
61
+ run "Make mount directory",
62
+ "mkdir #{mount_dir}"
63
+
64
+ on_rollback lambda {
65
+ run "Removing mount directory",
66
+ "rmdir #{$mount_dir}"
67
+ }
68
+
69
+ run "Changing permissions of mount directory",
70
+ "chmod 0777 #{mount_dir}"
71
+ end
72
+
73
+ # # Mount the new logical volume
74
+ # mount /dev/{vgName}/mysql-{dbName} /mnt/mysql/{dbName};
75
+ exec_mount "/dev/#{volume_group_name}/#{logical_volume_name}", mount_dir
76
+
77
+ # # Move the contents of the database to the new logical volume
78
+ # mv {mysql-data-dir}/{dbName}/* /mnt/mysql/{dbName};
79
+
80
+ move_mysql_files "#{mysql_data_dir}/#{$options[:database]}", mount_dir
81
+
82
+ on_rollback lambda {
83
+ move_mysql_files mount_dir, "#{mysql_data_dir}/#{$options[:database]}"
84
+ }
85
+
86
+ # # Remove the folder in the MySQL data directory
87
+ # rmdir {mysql-data-dir}/{dbName}/
88
+ run "Remove mysql database directory",
89
+ "rm -rf #{mysql_data_dir}/#{$options[:database]}"
90
+
91
+ on_rollback lambda {
92
+ run "Re-creating MySQL database directory",
93
+ "mkdir #{mysql_data_dir}/#{$options[:database]}"
94
+
95
+ exec_chown "#{mysql_data_dir}/#{$options[:database]}"
96
+ }
97
+
98
+ # # Symbolic-link the MySQL data directory to the new logical volume
99
+ # ln -s /mnt/mysql/{dbName} {mysql-data-dir}/{dbName}/
100
+ exec_link "#{mysql_data_dir}/#{$options[:database]}", mount_dir
101
+
102
+ # # Change the permissions & ownership to MySQL
103
+ # chown -R mysql:mysql {mysql-data-dir}/{dbName}/
104
+ # chown -R mysql:mysql /mnt/mysql/{dbName}/
105
+ exec_chown "#{mysql_data_dir}/#{$options[:database]}"
106
+ exec_chown mount_dir
107
+
108
+ # Stop the MySQL Server
109
+ $database.server_start
110
+
111
+ on_rollback lambda {
112
+ $database.server_stop
113
+ }
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,51 @@
1
+ require "singleton"
2
+ require "src/app/commit"
3
+
4
+ module Snapback
5
+ module App
6
+ class Drop
7
+ include Singleton
8
+
9
+ def go
10
+ volume_group_name = "#{$config['lvm']['volume_group']}"
11
+ logical_volume_name = "#{$config['lvm']['prefix_database']}-#{$options[:database]}"
12
+ mount_dir = get_mount_dir $options[:database]
13
+ mysql_data_dir = $database.get_data_dir
14
+
15
+ # Remove the backup
16
+ Snapback::App::Commit.instance.go
17
+
18
+ if !$database.db_exists?($options[:database]) then
19
+ raise "Database '#{$options[:database]}' does not exist"
20
+ end
21
+
22
+ # Flush
23
+ exec_flush
24
+
25
+ # Stop the MySQL Server
26
+ $database.server_stop
27
+
28
+ on_rollback lambda {
29
+ $database.server_start
30
+ }
31
+
32
+ # Unlink
33
+ exec_unlink "#{mysql_data_dir}/#{$options[:database]}", mount_dir
34
+
35
+ # Unmount
36
+ exec_unmount "/dev/#{volume_group_name}/#{logical_volume_name}", mount_dir
37
+
38
+ # Remove logical volume
39
+ run "Remove logical volume",
40
+ "lvremove -f /dev/#{volume_group_name}/#{logical_volume_name}"
41
+
42
+ # Start the MySQL Server
43
+ $database.server_start
44
+
45
+ on_rollback lambda {
46
+ $database.server_stop
47
+ }
48
+ end
49
+ end
50
+ end
51
+ end