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.
checksums.yaml CHANGED
@@ -1,7 +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
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 143e6d3560aafaca95946154237916b3b02dca1c
4
+ data.tar.gz: 41ffc96d8acc093da21be2818ac50a824f84f1ff
5
+ SHA512:
6
+ metadata.gz: 80faaf5da96a475a10dc9922798e39576138848cfbcabb704ad8a6039db35d2d27cb6d9c20d0b3aa6be2602f3436c42175a3303948190c834668a1a8b3bb5f8e
7
+ data.tar.gz: 671d610a7cd87dcaf4df7dd7700b261e71dd6c39e0b9ab3d611f52cfca9497b360eabe802dbcbed5e64fe0d73b57fe03b5ab9a5c3b4dd1d73502f31e8e836156
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Snapback
2
2
 
3
- Version 0.1 Alpha
3
+ Version 0.0.3
4
4
 
5
- Create MySQL snapshots for easy development rollback.
5
+ Create MySQL snapshots for easy development rollback. Only recommended for use on virtual machines, not recommended for production environments.
6
6
 
7
7
  ## Project Details
8
8
 
@@ -53,8 +53,8 @@ The gem should also automatically install the following gems:
53
53
  You must then enable multiple tablespaces.
54
54
  Add a line to the [mysqld] section of your MySQL my.cnf:
55
55
 
56
- [mysqld]
57
- innodb_file_per_table=ON
56
+ [mysqld]
57
+ innodb_file_per_table
58
58
 
59
59
  ### Configuration
60
60
 
@@ -72,11 +72,6 @@ Restart AppArmor and MySQL
72
72
  service apparmor restart
73
73
  service mysql restart
74
74
 
75
- ### Usage
76
-
77
- Only recommended for use on virtual machines.
78
- Not recommended for production environments.
79
-
80
75
  ## Setup
81
76
 
82
77
  To start using this application, you must run this once:
@@ -144,7 +139,7 @@ E.g.: Stop using the database "camera"
144
139
 
145
140
  If you're getting an error message similar to following:
146
141
 
147
- File descriptor ? (/home/?/.snapback.yml) leaked on lvcreate invocation.
142
+ File descriptor ? (~/.snapback.yml) leaked on lvcreate invocation.
148
143
 
149
144
  You can circumvent this error by adding the following environmental variable before your command:
150
145
 
@@ -152,7 +147,7 @@ You can circumvent this error by adding the following environmental variable bef
152
147
 
153
148
  For example:
154
149
 
155
- sudo LVM_SUPPRESS_FD_WARNINGS=1 sudo snapback snapshot camera --size 100M
150
+ sudo LVM_SUPPRESS_FD_WARNINGS=1 snapback create camera --size 100M
156
151
 
157
152
  ## Licence
158
153
 
@@ -1,82 +1,66 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'colorize'
4
+ require 'snapback'
2
5
 
3
- require 'rubygems'
4
- require 'yaml'
5
- require 'optparse'
6
- require 'pp'
6
+ include GLI::App
7
7
 
8
- require 'snapback/options'
9
- require 'snapback/transaction'
10
- require 'snapback/database'
11
- require 'snapback/dsl'
8
+ require 'snapback/cli/install'
9
+ require 'snapback/cli/create'
10
+ require 'snapback/cli/drop'
11
+ require 'snapback/cli/snapshot'
12
+ require 'snapback/cli/commit'
13
+ require 'snapback/cli/rollback'
14
+ require 'snapback/cli/mount'
15
+ require 'snapback/cli/unmount'
12
16
 
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
17
+ program_desc 'Create database snapshots using logical volume management (LVM)'
22
18
 
23
- begin
24
- $options = Snapback::Options.parse(ARGV)
19
+ version Snapback::VERSION
25
20
 
26
- case $options[:command]
27
- when "install"
28
- require "snapback/app/install"
29
- Snapback::App::Install.instance.go
21
+ desc 'Show debugging messages'
22
+ switch [:q,:quiet]
30
23
 
31
- puts ""
32
- exit
33
- end
24
+ desc 'Location of the snapback configuration file'
25
+ flag :config, :default_value => '~/.snapback.yml'
26
+
27
+ pre do |global,command,options,args|
28
+ # Pre logic here
29
+ # Return true to proceed; false to abort and not call the
30
+ # chosen command
31
+ # Use skips_pre before a command to skip this block
32
+ # on that command only
34
33
 
35
- begin
36
- # Read confirmation options
37
- $config = YAML.load_file($options[:config])
38
- rescue
39
- raise "Could not load configuration file: #{$options[:config]}"
34
+ # Check the user is running as root
35
+ if Process.uid != 0 then
36
+ raise "You must run snapback as #{"root".colorize(:red)}"
40
37
  end
41
38
 
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
39
+ # Normalise the configuration filename
40
+ global[:config] = File.expand_path(global[:config])
48
41
 
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
42
+ if global[:quiet] then
43
+ Snapback.set_quiet
44
+ else
45
+ Snapback.set_verbose
71
46
  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
47
 
79
- Snapback::Transaction.instance.do_rollback
48
+ # Annouce the function
49
+ puts "Snapback is about to #{command.name.to_s.colorize(:green)}" if Snapback.verbose?
50
+
51
+ true
52
+ end
53
+
54
+ post do |global,command,options,args|
55
+ # Post logic here
56
+ # Use skips_post before a command to skip this
57
+ # block on that command only
58
+ end
59
+
60
+ on_error do |exception|
61
+ # Error logic here
62
+ # return false to skip default error handling
63
+ true
80
64
  end
81
65
 
82
- puts ""
66
+ exit run(ARGV)
@@ -0,0 +1,130 @@
1
+ require 'colorize'
2
+ require 'open4'
3
+
4
+ require 'snapback/transaction'
5
+ require 'snapback/filesystem'
6
+
7
+ # Command
8
+
9
+ module Snapback
10
+ @@verbose = false
11
+
12
+ def self.set_quiet
13
+ @@verbose = true
14
+ end
15
+
16
+ def self.set_verbose
17
+ @@verbose = false
18
+ end
19
+
20
+ def self.quiet?
21
+ @@verbose == true
22
+ end
23
+
24
+ def self.verbose?
25
+ @@verbose == false
26
+ end
27
+ end
28
+
29
+ def run_command description, command = "", &block
30
+ if Snapback.verbose?
31
+ print "#{description}".to_s.ljust(72)
32
+ STDOUT.flush
33
+ end
34
+
35
+ begin
36
+ if block_given? then
37
+ result = block.call
38
+
39
+ if result then
40
+ return_ok
41
+ else
42
+ return_no
43
+ end
44
+ else
45
+ err = ""
46
+ status = Open4::popen4(command) do |pid, stdin, stdout, stderr|
47
+ err = stderr.read
48
+ end
49
+
50
+ if status != 0 then
51
+ raise err
52
+ end
53
+
54
+ return_ok
55
+ end
56
+ rescue Exception => e
57
+ return_failed
58
+ raise $! # rethrow
59
+ end
60
+
61
+ return result
62
+ end
63
+
64
+ # Output status
65
+
66
+ def return_ok
67
+ return nil if Snapback.quiet?
68
+ puts "[#{" OK ".colorize(:green)}]"
69
+ end
70
+
71
+ def return_no
72
+ return nil if Snapback.quiet?
73
+ puts "[#{" NO ".colorize(:red)}]"
74
+ end
75
+
76
+ def return_failed
77
+ return nil if Snapback.quiet?
78
+ puts "[#{"FAILED".colorize(:red)}]"
79
+ end
80
+
81
+ # Ask
82
+
83
+ def ask_int question, max
84
+ number = nil
85
+
86
+ while true
87
+ print "#{question}: "
88
+
89
+ number = $stdin.gets.chomp
90
+
91
+ if !Integer(number) then
92
+ puts "The value you entered is not a number."
93
+ puts ""
94
+ next
95
+ end
96
+
97
+ number = number.to_i
98
+
99
+ if number < 1 || number > max then
100
+ puts "Please enter a number between 1 and #{max}."
101
+ puts ""
102
+ next
103
+ end
104
+
105
+ break
106
+ end
107
+
108
+ number
109
+ end
110
+
111
+ def ask_string question
112
+ print "#{question}: "
113
+ $stdin.gets.chomp
114
+ end
115
+
116
+ def ask_confirm question
117
+ while true
118
+ print "#{question} [Y/N]: "
119
+
120
+ confirmed = $stdin.gets.chomp.upcase
121
+
122
+ if confirmed.eql? 'Y' then
123
+ return true
124
+ elsif confirmed.eql? 'N' then
125
+ return false
126
+ else
127
+ puts "Please enter either Y or N."
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,72 @@
1
+ require 'snapback/configuration_loader'
2
+ require 'snapback/mysql/service_control'
3
+
4
+ desc 'Commit the working copy of the database'
5
+ arg_name 'database [, ...]'
6
+ command :commit do |c|
7
+ c.action do |global_options,options,args|
8
+ # Ensure all flags and switches are present
9
+ help_now!('database(s) required') if args.empty?
10
+
11
+ # Load the configuration
12
+ config = Snapback::ConfigurationLoader.factory global_options[:config]
13
+
14
+ # Connect to MySQL
15
+ mysql_client = config.mysql_client
16
+
17
+ # For each database
18
+ args.each do |database|
19
+
20
+ # Start the transaction
21
+ Snapback::Transaction.new do
22
+ run_command "Selecting database: #{database}" do
23
+ mysql_client.database_select(database)
24
+ end
25
+
26
+ vg_name = config.lvm_volume_group
27
+ lv_name = "#{config.lvm_database_prefix}-#{database}"
28
+ lv_path = "/dev/#{vg_name}/#{lv_name}"
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
+ # Commit LVM
55
+ run_command "Commit logical volume" do
56
+ exec "lvremove -f #{lv_path}"
57
+ end
58
+
59
+ # Start MySQL
60
+ run_command "Start MySQL server" do
61
+ Snapback::MySQL::ServiceControl.start
62
+ end
63
+
64
+ revert do
65
+ run_command "Stop MySQL server" do
66
+ Snapback::MySQL::ServiceControl.stop
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,157 @@
1
+ desc 'Create a new snapback compliant database'
2
+ arg_name 'database [, ...]'
3
+ command :create do |c|
4
+
5
+ c.desc 'Disk size of database to create'
6
+ c.flag [:s, :size]
7
+
8
+ c.action do |global_options,options,args|
9
+ help_now!('parameter -s for size is required') if options[:s].nil?
10
+ help_now!('database(s) required') if args.empty?
11
+
12
+ # Load the configuration
13
+ config = Snapback::ConfigurationLoader.factory global_options[:config]
14
+
15
+ # Connect to MySQL
16
+ mysql_client = config.mysql_client
17
+
18
+ args.each do |database|
19
+
20
+ # Start the transaction
21
+ Snapback::Transaction.new do
22
+
23
+ vg_name = config.lvm_volume_group
24
+ lv_name = "#{config.lvm_database_prefix}-#{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
+ database_exists = run_command "Checking database exists: #{database}" do
31
+ mysql_client.database_exists?(database)
32
+ end
33
+
34
+ if !database_exists then
35
+ run_command "Creating database: #{database}" do
36
+ mysql_client.database_create(database)
37
+ end
38
+
39
+ revert do
40
+ run_command "Dropping database: #{database}" do
41
+ mysql_client.db_drop(database)
42
+ end
43
+ end
44
+ end
45
+
46
+ lv_available = run_command "Checking logical volume name is available" do
47
+ !File.exists?(lv_path)
48
+ end
49
+
50
+ if !lv_available then
51
+ raise "Logical volume #{lv_path.colorize(:red)} already exist"
52
+ end
53
+
54
+ # Flush
55
+ run_command "Flush tables with read lock" do
56
+ mysql_client.flush_tables
57
+ end
58
+
59
+ # Stop MySQL
60
+ run_command "Stop MySQL server" do
61
+ Snapback::MySQL::ServiceControl.stop
62
+ end
63
+
64
+ revert do
65
+ run_command "Start MySQL server" do
66
+ Snapback::MySQL::ServiceControl.start
67
+ end
68
+ end
69
+
70
+ # Logical volume management
71
+ run_command "Create logical volume",
72
+ "lvcreate -L #{options[:s]} -n #{lv_name} #{vg_name}"
73
+
74
+ revert do
75
+ run_command "Removing logical volume",
76
+ "lvremove -f #{vg_name}/#{lv_name}"
77
+ end
78
+
79
+ run_command "Format logical volume filesystem",
80
+ "mkfs.ext4 #{lv_path}"
81
+
82
+ # Create a new directory for where the MySQL database can be mounted
83
+ # mkdir /mnt/mysql/{dbName};
84
+
85
+ mount_diectory_exists = run_command "Checking mount directory: #{mount_database_directory}" do
86
+ File.directory? mount_database_directory
87
+ end
88
+
89
+ if !mount_diectory_exists then
90
+ run_command "Make mount directory",
91
+ "mkdir #{mount_database_directory}"
92
+
93
+ revert do
94
+ run_command "Removing mount directory",
95
+ "rm -rf #{$mount_database_directory}"
96
+ end
97
+ end
98
+
99
+ run_command "Changing permissions of mount directory",
100
+ "chmod 0777 #{mount_database_directory}"
101
+
102
+ # Mount the new logical volume
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
+ # Move the contents of the database to the new logical volume
112
+ Snapback::Filesystem.move_mysql_files(mysql_database_directory, mount_database_directory)
113
+
114
+ revert do
115
+ Snapback::Filesystem.move_mysql_files(mount_database_directory, mysql_database_directory)
116
+ end
117
+
118
+ # Remove the folder in the MySQL data directory
119
+
120
+ run_command "Remove mysql database directory",
121
+ "rm -rf #{mysql_database_directory}"
122
+
123
+ revert do
124
+ run_command "Re-creating MySQL database directory",
125
+ "mkdir #{mysql_database_directory}"
126
+ end
127
+
128
+ # Symbolic-link the MySQL data directory to the new logical volume
129
+ run_command "Linking mysql data directory",
130
+ "ln -s #{mount_database_directory} #{mysql_database_directory}"
131
+
132
+ revert do
133
+ run_command "Unlinking mysql data directory",
134
+ "unlink #{mysql_database_directory}"
135
+ end
136
+
137
+ # Change the permissions & ownership to MySQL
138
+ run_command "Changing owner to mysql: #{mysql_database_directory}",
139
+ "chown -R mysql:mysql #{mysql_database_directory}"
140
+
141
+ run_command "Changing owner to mysql: #{mount_database_directory}",
142
+ "chown -R mysql:mysql #{mount_database_directory}"
143
+
144
+ # Start MySQL
145
+ run_command "Starting MySQL server" do
146
+ Snapback::MySQL::ServiceControl.start
147
+ end
148
+
149
+ revert do
150
+ run_command "Stopping MySQL server" do
151
+ Snapback::MySQL::ServiceControl.stop
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end