mysql-slaver 0.1.0

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