snapback 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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