repctl 0.0.5 → 0.0.6

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/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