repctl 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/bin/repctl CHANGED
@@ -203,10 +203,19 @@ class RepctlCmds < Thor
203
203
  # Setting Up Replication with Existing Data using the 'mysqldump' utility. The
204
204
  # master has existing data.
205
205
  #
206
- desc "add_slave MASTER SLAVE", "Master has some data that is used to initialize the slave."
206
+ desc "add_slave MASTER SLAVE", "Establish a new master/slave relationship."
207
+ method_option :sync, :type => :boolean, :aliases => "-s",
208
+ :default => false, :desc => "Initialize slave via dump/restore from master"
209
+ method_option :dumpfile, :type => :string, :aliases => "-d",
210
+ :default => DEFAULT_DUMPFILE, :desc => "Name of the dumpfile"
211
+ long_desc <<-EOS
212
+ Add a new slave to an existing server which may already be the
213
+ master for some other slaves. The 'sync' option is destroys any
214
+ data that may already be on the slave. Before replicaton is started
215
+ the slave is initialized via dump/restore from the master.
216
+ EOS
207
217
  def add_slave(master, slave)
208
- dumpfile = DEFAULT_DUMPFILE
209
- do_add_slave(master, slave, dumpfile)
218
+ do_add_slave(master, slave, options)
210
219
  end
211
220
 
212
221
  desc "remove_slave SLAVE", "Remove a slave from the replica set."
@@ -3,6 +3,7 @@ module Repctl
3
3
 
4
4
  include Commands
5
5
  include Servers
6
+ include Config
6
7
 
7
8
  def do_stop(instance)
8
9
  do_admin(instance, "shutdown")
@@ -24,7 +25,7 @@ module Repctl
24
25
  end
25
26
 
26
27
  def do_restart(instance)
27
- do_admin(instance, "shutown")
28
+ do_admin(instance, "shutdown")
28
29
  do_start(instance)
29
30
  end
30
31
 
@@ -96,10 +97,16 @@ module Repctl
96
97
  output
97
98
  end
98
99
 
99
- def do_add_slave(master, slave, dumpfile)
100
- do_reset(slave)
101
- coordinates = do_dump(master, dumpfile)
102
- do_restore(slave, dumpfile)
100
+ def do_add_slave(master, slave, options = {})
101
+ puts options.to_yaml
102
+ sync = options.has_key?(:sync) ? options[:sync] : false
103
+ dumpfile = options.has_key?(:dumpfile) ? options[:dumpfile] : DEFAULT_DUMPFILE
104
+ if sync
105
+ do_reset(slave)
106
+ coordinates = do_dump(master, dumpfile)
107
+ do_restore(slave, dumpfile)
108
+ end
109
+ coordinates = get_coordinates(master)
103
110
  do_change_master(master, slave, coordinates)
104
111
  do_start_slave(slave)
105
112
  do_cluster_user(slave)
@@ -119,7 +126,8 @@ module Repctl
119
126
  end
120
127
 
121
128
  def do_repl_trio(master, slave1, slave2, options = {})
122
- if options[:reset]
129
+ reset = options.has_key?(:reset) ? options[:reset] : true
130
+ if reset
123
131
  do_reset(master)
124
132
  do_reset(slave1)
125
133
  do_reset(slave2)
@@ -113,6 +113,27 @@ module Repctl
113
113
  if pid
114
114
  puts "Instance #{instance} with PID #{pid} is already running."
115
115
  else
116
+ server = server_for_instance(instance)
117
+ puts "Starting instance #{instance} with PID #{Process.pid}."
118
+ pid = spawn(["#{MYSQL_HOME}/bin/mysqld", "mysqld"],
119
+ "--defaults-file=#{server['defaults-file']}",
120
+ "--datadir=#{server['datadir']}",
121
+ "--port=#{server['port']}",
122
+ "--server-id=#{server['server-id']}",
123
+ "--innodb_data_home_dir=#{server['innodb_data_home_dir']}",
124
+ "--innodb_log_group_home_dir=#{server['innodb_log_group_home_dir']}",
125
+ "--relay-log=#{Socket.gethostname}-relay-bin",
126
+ "--socket=#{server['socket']}",
127
+ "--user=#{server['user']}")
128
+ Process.detach(pid)
129
+ unless live?(instance)
130
+ puts "Waiting for server..."
131
+ sleep(1)
132
+ end
133
+ end
134
+ end
135
+
136
+ =begin
116
137
  pid = fork
117
138
  unless pid
118
139
  # We're in the child.
@@ -129,9 +150,10 @@ module Repctl
129
150
  "--relay-log=#{Socket.gethostname}-relay-bin",
130
151
  "--socket=#{server['socket']}",
131
152
  "--user=#{server['user']}")
153
+ Process.detach(pid)
132
154
  end
133
- end
134
155
  end
156
+ =end
135
157
 
136
158
  def do_admin(instance, operation)
137
159
  server = server_for_instance(instance)
@@ -379,12 +401,16 @@ EOT
379
401
 
380
402
  if client
381
403
  cmd = "CREATE USER \'cluster\'@\'localhost\' IDENTIFIED BY \'secret\'"
404
+ puts cmd
382
405
  client.query(cmd)
383
406
  cmd = "GRANT ALL PRIVILEGES ON *.* TO \'cluster\'@'\localhost\'"
407
+ puts cmd
384
408
  client.query(cmd)
385
409
  cmd = "CREATE USER \'cluster\'@\'%\' IDENTIFIED BY \'secret\'"
410
+ puts cmd
386
411
  client.query(cmd)
387
412
  cmd = "GRANT ALL PRIVILEGES ON *.* TO \'cluster\'@\'%\'"
413
+ puts cmd
388
414
  client.query(cmd)
389
415
  else
390
416
  puts "Could not open connection to MySQL instance #{instance}."
@@ -1,3 +1,3 @@
1
1
  module Repctl
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -0,0 +1,51 @@
1
+ /* Fix this. It should not be in the global namespace. */
2
+ function getUpdate() {
3
+ $('#status-table').load('/status');
4
+ setTimeout(getUpdate, 3000);
5
+ }
6
+
7
+ $(document).ready(function() {
8
+ getUpdate();
9
+
10
+ $('#switch-master').submit(function() {
11
+ $('#switch-master-result').html("")
12
+ $('.spinner').show();
13
+ $.post('/switch_master', $(this).serialize(), function(data) {
14
+ $('.spinner').hide();
15
+ $('#switch-master-result').html(data)
16
+ });
17
+ return false;
18
+ });
19
+
20
+ $('#repl-trio').submit(function() {
21
+ $('#repl-trio-result').html("")
22
+ $('#repl-trio-spinner').show();
23
+ $.post('/repl_trio', $(this).serialize(), function(data) {
24
+ $('#repl-trio-spinner').hide();
25
+ $('#repl-trio-result').html(data)
26
+ });
27
+ return false;
28
+ });
29
+
30
+ $('#add-slave').submit(function() {
31
+ $('#add-slave-result').html("")
32
+ $('#add-slave-spinner').show();
33
+ $.post('/add_slave', $(this).serialize(), function(data) {
34
+ $('#add-slave-spinner').hide();
35
+ $('#add-slave-result').html(data)
36
+ });
37
+ return false;
38
+ });
39
+
40
+ $('#remove-slave').submit(function() {
41
+ $('#remove-slave-result').html("")
42
+ $('#remove-slave-spinner').show();
43
+ $.post('/remove_slave', $(this).serialize(), function(data) {
44
+ $('#remove-slave-spinner').hide();
45
+ $('#remove-slave-result').html(data)
46
+ });
47
+ return false;
48
+ });
49
+
50
+ });
51
+
@@ -0,0 +1,35 @@
1
+ #banner {
2
+ text-align: center;
3
+ }
4
+ .spinner {
5
+ display:none;
6
+ }
7
+ .success {
8
+ color: green;
9
+ }
10
+ .failure {
11
+ color: red;
12
+ }
13
+ table.gridtable {
14
+ font-family: verdana,arial,sans-serif;
15
+ font-size:11px;
16
+ color:#333333;
17
+ border-width: 1px;
18
+ border-color: #666666;
19
+ border-collapse: collapse;
20
+ }
21
+ table.gridtable th {
22
+ border-width: 1px;
23
+ padding: 8px;
24
+ border-style: solid;
25
+ border-color: #666666;
26
+ background-color: #dedede;
27
+ }
28
+ table.gridtable td {
29
+ border-width: 1px;
30
+ padding: 8px;
31
+ border-style: solid;
32
+ border-color: #666666;
33
+ background-color: #ffffff;
34
+ }
35
+
@@ -3,75 +3,14 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <title>MySQL Replication Manager</title>
6
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
7
- </script>
8
-
9
- <script type="text/javascript">
10
- /* Fix this. It should not be in the global namespace. */
11
- function getUpdate() {
12
- $('#status-table').load('/status');
13
- setTimeout(getUpdate, 3000);
14
- }
15
- $(document).ready(function() {
16
- getUpdate();
17
6
 
18
- $('#switch-master').submit(function() {
19
- $('.spinner').show();
20
- $.post('/switch_master', $(this).serialize(), function(data) {
21
- $('.spinner').hide();
22
- $("#switch-master-result").html(data)
23
- });
24
- return false;
25
- });
7
+ <link rel="stylesheet" href="stylesheets/repctl.css" type="text/css">
26
8
 
27
- $('#repl-trio').submit(function() {
28
- $('#repl-trio-spinner').show();
29
- $.post('/repl_trio', $(this).serialize(), function(data) {
30
- $('#repl-trio-spinner').hide();
31
- $("#repl-trio-result").html(data)
32
- });
33
- return false;
34
- });
35
-
36
- });
9
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
10
+ </script>
11
+ <script type="text/javascript" src="javascripts/repctl.js">
37
12
  </script>
38
13
 
39
- <style type="text/css">
40
- #banner {
41
- text-align: center;
42
- }
43
- .spinner {
44
- display:none;
45
- }
46
- .success {
47
- color: green;
48
- }
49
- .failure {
50
- color: red;
51
- }
52
- table.gridtable {
53
- font-family: verdana,arial,sans-serif;
54
- font-size:11px;
55
- color:#333333;
56
- border-width: 1px;
57
- border-color: #666666;
58
- border-collapse: collapse;
59
- }
60
- table.gridtable th {
61
- border-width: 1px;
62
- padding: 8px;
63
- border-style: solid;
64
- border-color: #666666;
65
- background-color: #dedede;
66
- }
67
- table.gridtable td {
68
- border-width: 1px;
69
- padding: 8px;
70
- border-style: solid;
71
- border-color: #666666;
72
- background-color: #ffffff;
73
- }
74
- </style>
75
14
  </head>
76
15
 
77
16
  <body>
@@ -28,7 +28,7 @@
28
28
  <form id="repl-trio" action="/repl_trio" method="post">
29
29
  <p>Master: <input type="text" name="repl_trio[master]" size="20"/></p>
30
30
  <p>Slaves: <input type="text" name="repl_trio[slaves]" size="20"/></p>
31
- <input type="submit" value="Create Repliction Trio">
31
+ <input type="submit" value="Create Replication Trio">
32
32
  </form>
33
33
  <div>
34
34
  <div style="float:left;" id="repl-trio-result"></div>
@@ -36,3 +36,30 @@
36
36
  </div>
37
37
  </section>
38
38
 
39
+ <section>
40
+ <header><h2>Add a New Slave to Replica Set</h2></header>
41
+ <form id="add-slave" action="/add_slave" method="post">
42
+ <p>Master: <input type="text" name="add_slave[master]" size="20"/></p>
43
+ <p>Slave: <input type="text" name="add_slave[slaves]" size="20"/></p>
44
+ <label for="add_slave[sync]">Synchronize slave to master before starting replication</label>
45
+ <input name="add_slave[sync]" value="sync" type="checkbox"/><br>
46
+ <input type="submit" value="Add Slave to Master">
47
+ </form>
48
+ <div>
49
+ <div style="float:left;" id="add-slave-result"></div>
50
+ <img style="float:left;" class="spinner" id='add-slave-spinner' src='images/wait30.gif' alt='spinner'></img>
51
+ </div>
52
+ </section>
53
+
54
+ <section>
55
+ <header><h2>Remove Slave from Replica Set</h2></header>
56
+ <form id="remove-slave" action="/remove_slave" method="post">
57
+ <p>Slave: <input type="text" name="remove_slave[slave]" size="20"/></p>
58
+ <input type="submit" value="Remove Slave from Replica Set">
59
+ </form>
60
+ <div>
61
+ <div style="float:left;" id="remove-slave-result"></div>
62
+ <img style="float:left;" class="spinner" id='remove-slave-spinner' src='images/wait30.gif' alt='spinner'></img>
63
+ </div>
64
+ </section>
65
+
@@ -4,7 +4,7 @@ require 'repctl'
4
4
  include Repctl::Config
5
5
  include Repctl::Commands
6
6
  include Repctl::Servers
7
- include Repctl::Utils
7
+ include Repctl::Helpers
8
8
  include Repctl::Color
9
9
 
10
10
  def time
@@ -72,15 +72,70 @@ post '/switch_master' do
72
72
  end
73
73
  end
74
74
 
75
+ # curl deimos:9393/add_slave --header "Accept: text/plain" \
76
+ # -d add_slave[master]=1 -d add_slave[slaves]=3 -d add_slave[sync]=sync
77
+ post '/add_slave' do
78
+ @message, master, slaves = master_slave_params(params["add_slave"])
79
+ options = {}
80
+ if params["add_slave"] && params["add_slave"]["sync"] == "sync"
81
+ options[:sync] = true
82
+ end
83
+ unless slaves && slaves[0]
84
+ @message = "You need to specify a slave"
85
+ end
86
+ if @message
87
+ @success = false
88
+ else
89
+ slave = slaves[0]
90
+ secs = time do
91
+ do_add_slave(master, slave, options)
92
+ end
93
+ @message = "Added slave #{slave} to master #{master} in #{secs} secs."
94
+ @success = true
95
+ end
96
+ if request.accept == ['text/plain']
97
+ if @success
98
+ "#{@message}\n".colorize(:green)
99
+ else
100
+ "#{@message}\n".colorize(:red)
101
+ end
102
+ else
103
+ erb :operation_complete, :layout => !request.xhr?
104
+ end
105
+ end
106
+
107
+ # curl deimos:9393/remove_slave --header "Accept: text/plain" \
108
+ # -d remove_slave[slave]=3
109
+ post '/remove_slave' do
110
+ slave = params["remove_slave"]["slave"]
111
+ secs = time do
112
+ do_remove_slave(slave)
113
+ end
114
+ @message = "Removed slave #{slave} in #{secs} secs."
115
+ @success = true
116
+ if request.accept == ['text/plain']
117
+ if @success
118
+ "#{@message}\n".colorize(:green)
119
+ else
120
+ "#{@message}\n".colorize(:red)
121
+ end
122
+ else
123
+ erb :operation_complete, :layout => !request.xhr?
124
+ end
125
+ end
126
+
127
+ # curl deimos:9393/repl_trio --header "Accept: text/plain" \
128
+ # -d repl_trio[master]=1 -d repl_trio[slaves]="2 3"
75
129
  post '/repl_trio' do
76
130
  @message, master, slaves = master_slave_params(params["repl_trio"])
77
131
  if @message
78
132
  @success = false
79
133
  else
80
134
  secs = time do
81
- sleep 1
135
+ do_repl_trio(master, slaves[0], slaves[1])
82
136
  end
83
- @message = "Create replication trio with master #{master} and slaves #{slaves} in #{secs} secs."
137
+ @message = "Create replication trio with master #{master} and " +
138
+ "slaves #{slaves[0] and slaves[1]} in #{secs} secs."
84
139
  @success = true
85
140
  end
86
141
  if request.accept == ['text/plain']
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repctl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-08 00:00:00.000000000Z
12
+ date: 2012-03-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &121456320 !ruby/object:Gem::Requirement
16
+ requirement: &195841920 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *121456320
24
+ version_requirements: *195841920
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: shotgun
27
- requirement: &121455900 !ruby/object:Gem::Requirement
27
+ requirement: &195841500 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *121455900
35
+ version_requirements: *195841500
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: compass
38
- requirement: &121455480 !ruby/object:Gem::Requirement
38
+ requirement: &195841080 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *121455480
46
+ version_requirements: *195841080
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: thor
49
- requirement: &121455060 !ruby/object:Gem::Requirement
49
+ requirement: &195840660 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *121455060
57
+ version_requirements: *195840660
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: mysql2
60
- requirement: &121454640 !ruby/object:Gem::Requirement
60
+ requirement: &195840240 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *121454640
68
+ version_requirements: *195840240
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sinatra
71
- requirement: &121454220 !ruby/object:Gem::Requirement
71
+ requirement: &195839820 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *121454220
79
+ version_requirements: *195839820
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: thin
82
- requirement: &121453800 !ruby/object:Gem::Requirement
82
+ requirement: &195839400 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,7 +87,7 @@ dependencies:
87
87
  version: '0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *121453800
90
+ version_requirements: *195839400
91
91
  description: Ruby gem with Thor script to manage MySQL and PostgreSQL replication
92
92
  email:
93
93
  - lydianblues@gmail.com
@@ -114,6 +114,8 @@ files:
114
114
  - lib/repctl/version.rb
115
115
  - repctl.gemspec
116
116
  - webserver/public/images/wait30.gif
117
+ - webserver/public/javascripts/repctl.js
118
+ - webserver/public/stylesheets/repctl.css
117
119
  - webserver/sass/config.rb
118
120
  - webserver/sass/sass/ie.scss
119
121
  - webserver/sass/sass/print.scss