mysql-slaver 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -14,7 +14,7 @@ ASSUMPTIONS/PRE-REQUISITES
14
14
 
15
15
  * localhost is configured as a mysql replication slave
16
16
  * the current localhost user can ssh to the db master
17
- * any ssh config settings required to access the master from localhost are set in a ~/.ssh/config file
17
+ * any ssh config settings, other than a port number, required to access the master from localhost are set in a ~/.ssh/config file
18
18
  * ssh is on the current user's path
19
19
  * your mysql administrator user is called 'root', locally and on the db master
20
20
  * mysql is on the local user's path
@@ -30,11 +30,10 @@ CAVEATS
30
30
 
31
31
  TODO
32
32
 
33
- * add a "no copying" mode that only updates master log file and position
33
+ * output better help (include optional params, format better (shorter lines))
34
34
  * add a "dry-run" mode
35
- * check ssh connection and permissions
35
+ * check ssh connection
36
36
  * check replication permissions
37
37
  * check slave is setup as a replication slave (i.e. it has a mysql server id)
38
38
  * allow a mysql admin username other than 'root'
39
39
  * allow different root user passwords on slave and master
40
- * allow ssh options
@@ -1,21 +1,24 @@
1
1
  module MysqlSlaver
2
2
  class CLI < ::Thor
3
+ desc "enslave", "Start MySQL replication to this host from a master"
4
+
3
5
  option :master_host, :required => true, :desc => "The server which will be the replication master, for this slave"
4
6
  option :database, :required => true, :desc => "The database to copy from the master"
5
7
  option :replication_user, :required => true, :desc => "DB user (on the master host), with replication permissions"
6
8
  option :replication_password, :required => true, :desc => "DB password for the replication user"
7
-
8
9
  option :root_password, :desc => "Password for the mysql root user (on both master and slave)"
9
10
  option :port, :desc => "Mysql port (if not 3306)"
11
+ option :ssh_port, :desc => "SSH port (if not 22)"
10
12
  option :sock, :desc => "Mysql socket file (if any)"
11
-
12
- desc "enslave", "start mysql replication to this host from a master"
13
+ option :no_copy, :type => :boolean, :desc => "Do not copy data - just change master status"
13
14
 
14
15
  def enslave
15
16
  MysqlSlaver::Slaver.new(
16
17
  :master_host => options[:master_host],
17
18
  :port => options[:port],
19
+ :ssh_port => options[:ssh_port],
18
20
  :socket_file => options[:sock],
21
+ :no_copy => options[:no_copy],
19
22
  :mysql_root_password => options[:root_password],
20
23
  :database => options[:database],
21
24
  :replication_user => options[:replication_user],
@@ -10,7 +10,7 @@ module MysqlSlaver
10
10
  @database = params.fetch(:database)
11
11
  @port = params.fetch(:port, nil)
12
12
  @socket_file = params.fetch(:socket_file, nil)
13
- @executor = params.fetch(:executor) { Executor.new }
13
+ @executor = params.fetch(:executor) { Executor.new(:ssh_port => params[:ssh_port]) }
14
14
  end
15
15
 
16
16
  def copy!
@@ -1,9 +1,19 @@
1
1
  module MysqlSlaver
2
2
  class Executor
3
+ attr_reader :ssh_port
4
+
3
5
  include Logger
4
6
 
7
+ def initialize(params = {})
8
+ @ssh_port = params[:ssh_port]
9
+ end
10
+
5
11
  def ssh_command(cmd, host)
6
- "ssh #{host} '#{cmd}'"
12
+ if ssh_port
13
+ "ssh -p #{ssh_port} #{host} '#{cmd}'"
14
+ else
15
+ "ssh #{host} '#{cmd}'"
16
+ end
7
17
  end
8
18
 
9
19
  def execute(cmd)
@@ -6,18 +6,21 @@
6
6
  # connection)
7
7
  module MysqlSlaver
8
8
  class Slaver
9
- attr_reader :status_fetcher, :data_copier, :master_changer
9
+ attr_reader :status_fetcher, :data_copier, :master_changer, :no_copy
10
10
 
11
11
  def initialize(params)
12
12
  mysql_root_password = params.fetch(:mysql_root_password, '')
13
13
  port = params.fetch(:port, 3306)
14
+ ssh_port = params.fetch(:ssh_port, 22)
14
15
  socket_file = params.fetch(:socket_file, nil)
16
+ @no_copy = params.fetch(:no_copy, false)
15
17
 
16
18
  @status_fetcher = params.fetch(:status_fetcher) {
17
19
  StatusFetcher.new(
18
20
  :master_host => params.fetch(:master_host),
19
21
  :mysql_root_password => mysql_root_password,
20
- :socket_file => socket_file
22
+ :socket_file => socket_file,
23
+ :ssh_port => ssh_port
21
24
  )
22
25
  }
23
26
 
@@ -27,7 +30,8 @@ module MysqlSlaver
27
30
  :mysql_root_password => mysql_root_password,
28
31
  :database => params.fetch(:database),
29
32
  :port => port,
30
- :socket_file => socket_file
33
+ :socket_file => socket_file,
34
+ :ssh_port => ssh_port
31
35
  )
32
36
  }
33
37
 
@@ -45,7 +49,7 @@ module MysqlSlaver
45
49
 
46
50
  def enslave!
47
51
  master_status = status_fetcher.status
48
- data_copier.copy!
52
+ data_copier.copy! unless no_copy
49
53
  master_changer.change!(master_status)
50
54
  end
51
55
  end
@@ -9,7 +9,7 @@ module MysqlSlaver
9
9
  @master_host = params.fetch(:master_host)
10
10
  @socket_file = params.fetch(:socket_file, nil)
11
11
  @mysql_root_password = params.fetch(:mysql_root_password, '')
12
- @executor = params.fetch(:executor) { Executor.new }
12
+ @executor = params.fetch(:executor) { Executor.new(:ssh_port => params[:ssh_port]) }
13
13
  end
14
14
 
15
15
  def status
@@ -2,12 +2,23 @@ require 'spec/spec_helper'
2
2
 
3
3
  module MysqlSlaver
4
4
  describe Executor do
5
- subject(:executor) { described_class.new }
5
+ let(:ssh_port) { nil }
6
+ let(:params) { {:ssh_port => ssh_port} }
7
+
8
+ subject(:executor) { described_class.new(params) }
6
9
 
7
10
  describe "#ssh_command" do
8
11
  it "formats command" do
9
12
  expect(executor.ssh_command("foo", "myhost")).to eq("ssh myhost 'foo'")
10
13
  end
14
+
15
+ context "with non-standard ssh port" do
16
+ let(:ssh_port) { 64389 }
17
+
18
+ it "formats command" do
19
+ expect(executor.ssh_command("foo", "myhost")).to eq("ssh -p 64389 myhost 'foo'")
20
+ end
21
+ end
11
22
  end
12
23
  end
13
24
  end
@@ -32,6 +32,24 @@ module MysqlSlaver
32
32
  expect(master_changer).to have_received(:change!)
33
33
  end
34
34
 
35
+ context "no-copy" do
36
+ let(:params) { super().merge(:no_copy => true) }
37
+
38
+ it "fetches master status" do
39
+ slaver.enslave!
40
+ expect(status_fetcher).to have_received(:status)
41
+ end
42
+
43
+ it "doesn't copy data" do
44
+ slaver.enslave!
45
+ expect(data_copier).to_not have_received(:copy!)
46
+ end
47
+
48
+ it "changes master status" do
49
+ slaver.enslave!
50
+ expect(master_changer).to have_received(:change!)
51
+ end
52
+ end
35
53
  end
36
54
 
37
55
  context "instantiating collaborators" do
@@ -76,6 +94,20 @@ module MysqlSlaver
76
94
  end
77
95
  end
78
96
 
97
+ context "with non-standard ssh port" do
98
+ let(:params) { super().merge(:ssh_port => 64389) }
99
+
100
+ it "instantiates a status fetcher" do
101
+ fetcher = slaver.status_fetcher
102
+ expect(fetcher.executor.ssh_port).to eq(64389)
103
+ end
104
+
105
+ it "instantiates a data copier" do
106
+ copier = slaver.data_copier
107
+ expect(copier.executor.ssh_port).to eq(64389)
108
+ end
109
+ end
110
+
79
111
  context "with mysql socket" do
80
112
  let(:params) { super().merge(:socket_file => "/tmp/mysql.sock") }
81
113
 
@@ -93,7 +125,6 @@ module MysqlSlaver
93
125
  copier = slaver.data_copier
94
126
  expect(copier.socket_file).to eq("/tmp/mysql.sock")
95
127
  end
96
-
97
128
  end
98
129
  end
99
130
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql-slaver
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 9
10
- version: 0.1.9
9
+ - 10
10
+ version: 0.1.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - David Salgado
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2014-04-18 00:00:00 Z
18
+ date: 2014-04-20 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rspec