mysql-slaver 0.1.0

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.
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "thor"
4
+
5
+ group :development, :test do
6
+ gem "rdoc"
7
+ gem "rdoc-data"
8
+ gem "rake"
9
+ gem "gem-this"
10
+ gem "gemcutter"
11
+ gem "rspec"
12
+ gem "ruby-debug"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ columnize (0.3.6)
5
+ diff-lcs (1.2.5)
6
+ gem-this (0.3.7)
7
+ gemcutter (0.7.1)
8
+ json (1.8.1)
9
+ linecache (0.46)
10
+ rbx-require-relative (> 0.0.4)
11
+ rake (10.3.0)
12
+ rbx-require-relative (0.0.9)
13
+ rdoc (4.1.1)
14
+ json (~> 1.4)
15
+ rdoc-data (4.0.1)
16
+ rdoc (~> 4.0)
17
+ rspec (2.14.1)
18
+ rspec-core (~> 2.14.0)
19
+ rspec-expectations (~> 2.14.0)
20
+ rspec-mocks (~> 2.14.0)
21
+ rspec-core (2.14.8)
22
+ rspec-expectations (2.14.5)
23
+ diff-lcs (>= 1.1.3, < 2.0)
24
+ rspec-mocks (2.14.6)
25
+ ruby-debug (0.10.4)
26
+ columnize (>= 0.1)
27
+ ruby-debug-base (~> 0.10.4.0)
28
+ ruby-debug-base (0.10.4)
29
+ linecache (>= 0.3)
30
+ thor (0.19.1)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ gem-this
37
+ gemcutter
38
+ rake
39
+ rdoc
40
+ rdoc-data
41
+ rspec
42
+ ruby-debug
43
+ thor
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ Tool to setup a mysql replication slave by copying data and master status from a remote mysql master over ssh.
2
+
3
+ USAGE
4
+
5
+ mysql_slaver help enslave
6
+
7
+ mysql_slaver enslave --database=DATABASE --master-host=MASTER_HOST --replication-password=REPLICATION_PASSWORD --replication-user=REPLICATION_USER
8
+
9
+ BLOGPOST
10
+
11
+ http://digitalronin.github.io/2014/04/16/mysql-slaver-gem-setup-mysql-replication/
12
+
13
+ ASSUMPTIONS/PRE-REQUISITES
14
+
15
+ * localhost is configured as a mysql replication slave
16
+ * the current localhost user can ssh to the db master
17
+ * your mysql administrator user is called 'root', locally and on the db master
18
+ * root user has the same password on this host and the master server
19
+ * mysql is on the local user''s path
20
+ * mysql and mysqldump are on the remote ssh user''s path
21
+ * replication permissions from the local host to the db master are already setup
22
+ * mysql is running on the default port (3306)
23
+ * ssh is on the current user''s path
24
+ * db character set is UTF-8
25
+ * any ssh config settings for the host are set in a ~/.ssh/config file
26
+
27
+ CAVEATS
28
+
29
+ * destructively replaces the target database on localhost with no backup
30
+
31
+ TODO
32
+
33
+ * accept (and insist on) command-line parameters
34
+ * add a "no copying" mode that only updates master log file and position
35
+ * add a "dry-run" mode
36
+ * package as a gem
37
+ * check ssh connection and permissions
38
+ * check replication permissions
39
+ * check slave is setup as a replication slave (i.e. it has a mysql server id)
40
+ * allow overriding the mysql port
41
+ * allow overriding the mysql root user
42
+ * allow different root user passwords on slave and master
43
+ * allow ssh options
data/Rakefile ADDED
@@ -0,0 +1,80 @@
1
+ require "rubygems"
2
+ require "rubygems/package_task"
3
+ require "rdoc/task"
4
+
5
+ require "rspec"
6
+ require "rspec/core/rake_task"
7
+ RSpec::Core::RakeTask.new do |t|
8
+ t.rspec_opts = %w(--format documentation --colour)
9
+ end
10
+
11
+
12
+ task :default => ["spec"]
13
+
14
+ # This builds the actual gem. For details of what all these options
15
+ # mean, and other ones you can add, check the documentation here:
16
+ #
17
+ # http://rubygems.org/read/chapter/20
18
+ #
19
+ spec = Gem::Specification.new do |s|
20
+
21
+ # Change these as appropriate
22
+ s.name = "mysql-slaver"
23
+ s.version = "0.1.0"
24
+ s.summary = "What this thing does"
25
+ s.author = "David Salgado"
26
+ s.email = "david@digitalronin.com"
27
+ s.homepage = "http://yoursite.example.com"
28
+
29
+ s.has_rdoc = true
30
+ s.extra_rdoc_files = %w(README.md)
31
+ s.rdoc_options = %w(--main README.md)
32
+
33
+ # Add any extra files to include in the gem
34
+ s.files = %w(Gemfile Gemfile.lock Rakefile README.md) + Dir.glob("{bin,spec,lib}/**/*")
35
+ s.executables = FileList["bin/**"].map { |f| File.basename(f) }
36
+ s.require_paths = ["lib"]
37
+
38
+ # If you want to depend on other gems, add them here, along with any
39
+ # relevant versions
40
+ # s.add_dependency("some_other_gem", "~> 0.1.0")
41
+
42
+ # If your tests use any gems, include them here
43
+ s.add_development_dependency("rspec")
44
+ end
45
+
46
+ # This task actually builds the gem. We also regenerate a static
47
+ # .gemspec file, which is useful if something (i.e. GitHub) will
48
+ # be automatically building a gem for this project. If you're not
49
+ # using GitHub, edit as appropriate.
50
+ #
51
+ # To publish your gem online, install the 'gemcutter' gem; Read more
52
+ # about that here: http://gemcutter.org/pages/gem_docs
53
+ Gem::PackageTask.new(spec) do |pkg|
54
+ pkg.gem_spec = spec
55
+ end
56
+
57
+ desc "Build the gemspec file #{spec.name}.gemspec"
58
+ task :gemspec do
59
+ file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
60
+ File.open(file, "w") {|f| f << spec.to_ruby }
61
+ end
62
+
63
+ # If you don't want to generate the .gemspec file, just remove this line. Reasons
64
+ # why you might want to generate a gemspec:
65
+ # - using bundler with a git source
66
+ # - building the gem without rake (i.e. gem build blah.gemspec)
67
+ # - maybe others?
68
+ task :package => :gemspec
69
+
70
+ # Generate documentation
71
+ RDoc::Task.new do |rd|
72
+ rd.main = "README.md"
73
+ rd.rdoc_files.include("README.md", "lib/**/*.rb")
74
+ rd.rdoc_dir = "rdoc"
75
+ end
76
+
77
+ desc 'Clear out RDoc and generated packages'
78
+ task :clean => [:clobber_rdoc, :clobber_package] do
79
+ rm "#{spec.name}.gemspec"
80
+ end
data/bin/mysql_slaver ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'thor'
5
+ require 'lib/mysql_slaver'
6
+
7
+ module MysqlSlaver
8
+ class CLI < Thor
9
+ option :master_host, :required => true, :desc => "The server which will be the replication master, for this slave"
10
+ option :database, :required => true, :desc => "The database to copy from the master"
11
+ option :replication_user, :required => true, :desc => "DB user (on the master host), with replication permissions"
12
+ option :replication_password, :required => true, :desc => "DB password for the replication user"
13
+ option :root_password, :desc => "Password for the mysql root user (on both master and slave)"
14
+ desc "enslave", "start mysql replication to this host from a master"
15
+ long_desc <<-LONGDESC
16
+ LONGDESC
17
+ def enslave
18
+ MysqlSlaver::Slaver.new(
19
+ :master_host => options[:master_host],
20
+ :mysql_root_password => options[:root_password],
21
+ :database => options[:database],
22
+ :replication_user => options[:replication_user],
23
+ :replication_password => options[:replication_password]
24
+ ).enslave!
25
+ end
26
+ end
27
+ end
28
+
29
+ MysqlSlaver::CLI.start(ARGV)
@@ -0,0 +1,23 @@
1
+ module MysqlSlaver
2
+ class DbCopier
3
+ include MysqlCommand
4
+
5
+ attr_accessor :master_host, :mysql_root_password, :database, :executor
6
+
7
+ def initialize(params)
8
+ @master_host = params.fetch(:master_host)
9
+ @mysql_root_password = params.fetch(:mysql_root_password, '')
10
+ @database = params.fetch(:database)
11
+ @executor = params.fetch(:executor) { Executor.new }
12
+ end
13
+
14
+ def copy!
15
+ executor.execute mysql_command("stop slave", mysql_root_password)
16
+ cmd = mysqldump(master_host, database, mysql_root_password)
17
+ dump_cmd = executor.ssh_command(cmd, master_host)
18
+ load_cmd = ['mysql', mysql_credentials('root', mysql_root_password), database].join(' ')
19
+ command = [dump_cmd, load_cmd].join(' | ')
20
+ executor.execute command
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module MysqlSlaver
2
+ class Executor
3
+ include Logger
4
+
5
+ def ssh_command(cmd, host)
6
+ "ssh #{host} '#{cmd}'"
7
+ end
8
+
9
+ def execute(cmd)
10
+ string = cmd.is_a?(Array) ? cmd.join('; ') : cmd
11
+ log "CMD: #{string}"
12
+ `#{string}`
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module MysqlSlaver
2
+ module Logger
3
+ def log(msg)
4
+ puts [Time.now.strftime("%Y-%m-%d %H:%M:%S"), msg].join(' ')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ module MysqlSlaver
2
+ class MasterChanger
3
+ include MysqlCommand
4
+
5
+ attr_accessor :master_host, :mysql_root_password, :replication_user, :replication_password, :executor
6
+
7
+ def initialize(params)
8
+ @master_host = params.fetch(:master_host)
9
+ @mysql_root_password = params.fetch(:mysql_root_password, '')
10
+ @replication_user = params.fetch(:replication_user)
11
+ @replication_password = params.fetch(:replication_password)
12
+ @executor = params.fetch(:executor) { Executor.new }
13
+ end
14
+
15
+ def change!(status)
16
+ cmds = [
17
+ 'stop slave',
18
+ change_master(status),
19
+ 'start slave'
20
+ ]
21
+ cmd = mysql_command(cmds.join('; '), mysql_root_password)
22
+ executor.execute cmd
23
+ end
24
+
25
+ private
26
+
27
+ def change_master(status)
28
+ %[CHANGE MASTER TO MASTER_LOG_FILE='#{status[:file]}', MASTER_LOG_POS=#{status[:position]}, MASTER_HOST='#{master_host}', MASTER_USER='#{replication_user}', MASTER_PASSWORD='#{replication_password}']
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module MysqlSlaver
2
+ module MysqlCommand
3
+ def mysql_credentials(user, password)
4
+ rtn = "-u #{user} "
5
+ rtn << "-p #{password} " unless password.to_s == ""
6
+ rtn
7
+ end
8
+
9
+ def mysql_command(cmd, password)
10
+ creds = mysql_credentials('root', password)
11
+ %[mysql #{creds} -e "#{cmd}"]
12
+ end
13
+
14
+ def mysqldump(host, database, password)
15
+ creds = mysql_credentials('root', password)
16
+ %[mysqldump -h #{host} #{creds} --master-data --single-transaction --quick --skip-add-locks --skip-lock-tables --default-character-set=utf8 --compress #{database}]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ # Setup the current server as a replication slave of a master mysql server,
2
+ # by dumping and loading a database, and issuing the appropriate change master
3
+ # command to mysql.
4
+ # This assumes that the current user can issue ssh commands to the master
5
+ # server (to get its master status, and to dump and load data over the ssh
6
+ # connection)
7
+ module MysqlSlaver
8
+ class Slaver
9
+ attr_reader :status_fetcher, :data_copier, :master_changer
10
+
11
+ def initialize(params)
12
+ mysql_root_password = params.fetch(:mysql_root_password, '')
13
+
14
+ @status_fetcher = params.fetch(:status_fetcher) {
15
+ StatusFetcher.new(
16
+ :master_host => params.fetch(:master_host),
17
+ :mysql_root_password => mysql_root_password
18
+ )
19
+ }
20
+
21
+ @data_copier = params.fetch(:data_copier) {
22
+ DbCopier.new(
23
+ :master_host => params.fetch(:master_host),
24
+ :mysql_root_password => mysql_root_password,
25
+ :database => params.fetch(:database)
26
+ )
27
+ }
28
+
29
+ @master_changer = params.fetch(:master_changer) {
30
+ MasterChanger.new(
31
+ :master_host => params.fetch(:master_host),
32
+ :mysql_root_password => mysql_root_password,
33
+ :replication_user => params.fetch(:replication_user),
34
+ :replication_password => params.fetch(:replication_password)
35
+ )
36
+ }
37
+ end
38
+
39
+ def enslave!
40
+ master_status = status_fetcher.status
41
+ data_copier.copy!
42
+ master_changer.change!(master_status)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ module MysqlSlaver
2
+ class StatusFetcher
3
+ include Logger
4
+ include MysqlCommand
5
+
6
+ attr_accessor :master_host, :mysql_root_password, :executor
7
+
8
+ def initialize(params)
9
+ @master_host = params.fetch(:master_host)
10
+ @mysql_root_password = params.fetch(:mysql_root_password, '')
11
+ @executor = params.fetch(:executor) { Executor.new }
12
+ end
13
+
14
+ def status
15
+ cmd = mysql_command("show master status\\G", mysql_root_password)
16
+ data = executor.execute executor.ssh_command(cmd, master_host)
17
+ rtn = parse data
18
+ log "MASTER STATUS - file: #{rtn[:file]}, position: #{rtn[:position]}"
19
+ rtn
20
+ end
21
+
22
+ private
23
+
24
+ def parse(text)
25
+ file = nil
26
+ position = nil
27
+ text.split("\n").each do |line|
28
+ case line
29
+ when /File: (mysql-bin\.\d+)/
30
+ file = $1
31
+ when /Position: (\d+)/
32
+ position = $1
33
+ end
34
+ end
35
+ {:file => file, :position => position}
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ require 'lib/mysql_slaver/logger'
2
+ require 'lib/mysql_slaver/executor'
3
+ require 'lib/mysql_slaver/mysql_command'
4
+ require 'lib/mysql_slaver/slaver'
5
+ require 'lib/mysql_slaver/status_fetcher'
6
+ require 'lib/mysql_slaver/db_copier'
7
+ require 'lib/mysql_slaver/master_changer'
@@ -0,0 +1,39 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module MysqlSlaver
4
+ describe DbCopier do
5
+ let(:executor) { double(Executor, :execute => true, :ssh_command => "dummy-ssh-command") }
6
+
7
+ let(:params) {
8
+ {
9
+ :master_host => 'my.db.host',
10
+ :mysql_root_password => 'supersekrit',
11
+ :database => 'myappdb',
12
+ :executor => executor
13
+ }
14
+ }
15
+ subject(:copier) { described_class.new(params) }
16
+
17
+ describe "#copy!" do
18
+ it "stops slave" do
19
+ copier.copy!
20
+ stop = %[mysql -u root -p supersekrit -e "stop slave"]
21
+ expect(executor).to have_received(:execute).with(stop)
22
+ end
23
+
24
+ it "loads data" do
25
+ dump_and_load = "dummy-ssh-command | mysql -u root -p supersekrit myappdb"
26
+ expect(executor).to receive(:execute).once.ordered.with(dump_and_load)
27
+ copier.copy!
28
+ end
29
+
30
+ context "dumping" do
31
+ it "issues mysqldump over ssh" do
32
+ dump = "mysqldump -h my.db.host -u root -p supersekrit --master-data --single-transaction --quick --skip-add-locks --skip-lock-tables --default-character-set=utf8 --compress myappdb"
33
+ expect(executor).to receive(:ssh_command).with(dump, 'my.db.host')
34
+ copier.copy!
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module MysqlSlaver
4
+ describe Executor do
5
+ subject(:executor) { described_class.new }
6
+
7
+ describe "#ssh_command" do
8
+ it "formats command" do
9
+ expect(executor.ssh_command("foo", "myhost")).to eq("ssh myhost 'foo'")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module MysqlSlaver
4
+ describe MasterChanger do
5
+ let(:executor) { double(Executor, :execute => true) }
6
+
7
+ let(:status) { {:file => 'mysql-bin.001555', :position => 18426246} }
8
+ let(:params) {
9
+ {
10
+ :master_host => 'my.db.host',
11
+ :mysql_root_password => 'supersekrit',
12
+ :replication_user => 'repluser',
13
+ :replication_password => 'replpassword',
14
+ :executor => executor
15
+ }
16
+ }
17
+ subject(:changer) { described_class.new(params) }
18
+
19
+ describe "#change!" do
20
+ it "executes multi-part mysql command" do
21
+ change_cmd = %[mysql -u root -p supersekrit -e "stop slave; CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.001555', MASTER_LOG_POS=18426246, MASTER_HOST='my.db.host', MASTER_USER='repluser', MASTER_PASSWORD='replpassword'; start slave"]
22
+ changer.change!(status)
23
+ expect(executor).to have_received(:execute).with(change_cmd)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module MysqlSlaver
4
+ describe Slaver do
5
+ subject(:slaver) { described_class.new(params) }
6
+
7
+ describe "#enslave!" do
8
+ let(:status_fetcher) { double(StatusFetcher, :status => ()) }
9
+ let(:data_copier) { double(DbCopier, :copy! => true) }
10
+ let(:master_changer) { double(MasterChanger, :change! => true) }
11
+
12
+ let(:params) {
13
+ {
14
+ :status_fetcher => status_fetcher,
15
+ :data_copier => data_copier,
16
+ :master_changer => master_changer
17
+ }
18
+ }
19
+
20
+ it "fetches master status" do
21
+ slaver.enslave!
22
+ expect(status_fetcher).to have_received(:status)
23
+ end
24
+
25
+ it "copies data" do
26
+ slaver.enslave!
27
+ expect(data_copier).to have_received(:copy!)
28
+ end
29
+
30
+ it "changes master status" do
31
+ slaver.enslave!
32
+ expect(master_changer).to have_received(:change!)
33
+ end
34
+
35
+ end
36
+
37
+ context "instantiating collaborators" do
38
+ let(:params) {
39
+ {
40
+ :master_host => 'my.db.host',
41
+ :mysql_root_password => 'supersekrit',
42
+ :database => 'myappdb',
43
+ :replication_user => 'repluser',
44
+ :replication_password => 'replpassword'
45
+ }
46
+ }
47
+
48
+ it "instantiates a status fetcher" do
49
+ fetcher = slaver.status_fetcher
50
+ expect(fetcher.master_host).to eq('my.db.host')
51
+ expect(fetcher.mysql_root_password).to eq('supersekrit')
52
+ end
53
+
54
+ it "instantiates a data copier" do
55
+ copier = slaver.data_copier
56
+ expect(copier.master_host).to eq('my.db.host')
57
+ expect(copier.mysql_root_password).to eq('supersekrit')
58
+ expect(copier.database).to eq('myappdb')
59
+ end
60
+
61
+ it "instantiates a master changer" do
62
+ changer = slaver.master_changer
63
+ expect(changer.master_host).to eq('my.db.host')
64
+ expect(changer.mysql_root_password).to eq('supersekrit')
65
+ expect(changer.replication_user).to eq('repluser')
66
+ expect(changer.replication_password).to eq('replpassword')
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec/spec_helper'
2
+
3
+ module MysqlSlaver
4
+ describe StatusFetcher do
5
+ let(:executor) { double(Executor, :execute => "", :ssh_command => "dummy-ssh-command") }
6
+
7
+ let(:params) {
8
+ {
9
+ :master_host => 'my.db.host',
10
+ :mysql_root_password => 'supersekrit',
11
+ :executor => executor
12
+ }
13
+ }
14
+ subject(:fetcher) { described_class.new(params) }
15
+
16
+ before do
17
+ fetcher.stub(:log)
18
+ end
19
+
20
+ describe "#status" do
21
+ let(:output) { <<EOF
22
+ *************************** 1. row ***************************
23
+ File: mysql-bin.003219
24
+ Position: 37065270
25
+ Binlog_Do_DB:
26
+ Binlog_Ignore_DB:
27
+ EOF
28
+ }
29
+
30
+ before do
31
+ executor.stub(:execute => output)
32
+ end
33
+
34
+ it "executes show master command over ssh" do
35
+ show_master = %[mysql -u root -p supersekrit -e "show master status\\G"]
36
+ fetcher.status
37
+ expect(executor).to have_received(:ssh_command).with(show_master, 'my.db.host')
38
+ end
39
+
40
+ it "parses show master output" do
41
+ expect(fetcher.status).to eq({:file => 'mysql-bin.003219', :position => '37065270'})
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,4 @@
1
+ require 'ruby-debug'
2
+ Debugger.start
3
+
4
+ require 'lib/mysql_slaver'
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mysql-slaver
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - David Salgado
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2014-04-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :development
33
+ version_requirements: *id001
34
+ description:
35
+ email: david@digitalronin.com
36
+ executables:
37
+ - mysql_slaver
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.md
42
+ files:
43
+ - Gemfile
44
+ - Gemfile.lock
45
+ - Rakefile
46
+ - README.md
47
+ - bin/mysql_slaver
48
+ - spec/mysql_slaver/db_copier_spec.rb
49
+ - spec/mysql_slaver/executor_spec.rb
50
+ - spec/mysql_slaver/master_changer_spec.rb
51
+ - spec/mysql_slaver/slaver_spec.rb
52
+ - spec/mysql_slaver/status_fetcher_spec.rb
53
+ - spec/spec_helper.rb
54
+ - lib/mysql_slaver/db_copier.rb
55
+ - lib/mysql_slaver/executor.rb
56
+ - lib/mysql_slaver/logger.rb
57
+ - lib/mysql_slaver/master_changer.rb
58
+ - lib/mysql_slaver/mysql_command.rb
59
+ - lib/mysql_slaver/slaver.rb
60
+ - lib/mysql_slaver/status_fetcher.rb
61
+ - lib/mysql_slaver.rb
62
+ homepage: https://github.com/digitalronin/mysql-slaver
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --main
68
+ - README.md
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.8.25
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Setup mysql replication on a slave (localhost), from a remote master, over SSH
96
+ test_files: []
97
+