repctl 0.0.4 → 0.0.5
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/.gitignore +1 -0
- data/bin/repctl +13 -121
- data/config/servers.yml +4 -0
- data/lib/repctl/color.rb +61 -0
- data/lib/repctl/helpers.rb +146 -0
- data/lib/repctl/mysql_admin.rb +8 -33
- data/lib/repctl/servers.rb +13 -3
- data/lib/repctl/version.rb +1 -1
- data/lib/repctl.rb +5 -3
- data/repctl.gemspec +5 -0
- data/webserver/public/images/wait30.gif +0 -0
- data/webserver/sass/config.rb +24 -0
- data/webserver/sass/sass/ie.scss +5 -0
- data/webserver/sass/sass/print.scss +3 -0
- data/webserver/sass/sass/screen.scss +6 -0
- data/webserver/sass/stylesheets/ie.css +5 -0
- data/webserver/sass/stylesheets/print.css +3 -0
- data/webserver/sass/stylesheets/screen.css +68 -0
- data/webserver/views/layout.erb +80 -0
- data/webserver/views/main.erb +38 -0
- data/webserver/views/operation_complete.erb +5 -0
- data/webserver/views/status.erb +24 -0
- data/webserver/webserver.rb +108 -0
- metadata +67 -8
data/.gitignore
CHANGED
data/bin/repctl
CHANGED
@@ -5,34 +5,6 @@ require 'fileutils'
|
|
5
5
|
require 'repctl'
|
6
6
|
require 'thor'
|
7
7
|
|
8
|
-
module Repctl
|
9
|
-
module Helpers
|
10
|
-
def do_stop(instance)
|
11
|
-
do_admin(instance, "shutdown")
|
12
|
-
end
|
13
|
-
|
14
|
-
def do_reset(instance)
|
15
|
-
do_stop(instance)
|
16
|
-
do_config(instance)
|
17
|
-
do_start(instance)
|
18
|
-
do_secure_accounts(instance)
|
19
|
-
end
|
20
|
-
|
21
|
-
def do_start_slave(instance)
|
22
|
-
run_mysql_query(instance, "START SLAVE")
|
23
|
-
end
|
24
|
-
|
25
|
-
def do_stop_slave(instance)
|
26
|
-
run_mysql_query(instance, "STOP SLAVE")
|
27
|
-
end
|
28
|
-
|
29
|
-
def do_restart(instance)
|
30
|
-
do_admin(instance, "shutown")
|
31
|
-
do_start(instance)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
8
|
class RepctlCmds < Thor
|
37
9
|
|
38
10
|
include Thor::Actions
|
@@ -40,6 +12,7 @@ class RepctlCmds < Thor
|
|
40
12
|
include Repctl::Commands
|
41
13
|
include Repctl::Servers
|
42
14
|
include Repctl::Helpers
|
15
|
+
include Repctl::Color
|
43
16
|
|
44
17
|
desc "start [INSTANCES]", "Start one or more defined server instances."
|
45
18
|
method_option :all, :type => :boolean, :aliases => "-a",
|
@@ -200,49 +173,12 @@ class RepctlCmds < Thor
|
|
200
173
|
method_option :servers, :aliases => "-s", :type => :array,
|
201
174
|
:desc => "Only check the status of given servers."
|
202
175
|
def status
|
203
|
-
todos = options[:servers] || all_live_instances
|
204
|
-
unless todos.any?
|
205
|
-
say "No Running Servers. Are you running as the mysql user?", :blue
|
206
|
-
return
|
207
|
-
end
|
208
176
|
header = sprintf("%-5s%-27s%-27s%-27s%-8s\n",
|
209
177
|
"inst", "master", "received", "applied", "lag")
|
210
|
-
|
211
178
|
loop do
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
coordinates = get_coordinates(i)
|
216
|
-
master_file = coordinates[:file]
|
217
|
-
master_pos = coordinates[:position]
|
218
|
-
slave = is_slave?(i)
|
219
|
-
if slave
|
220
|
-
slave_status = get_slave_status(i)
|
221
|
-
recv_file = slave_status["Master_Log_File"]
|
222
|
-
recv_pos = slave_status["Read_Master_Log_Pos"]
|
223
|
-
apply_file = slave_status["Relay_Master_Log_File"]
|
224
|
-
apply_pos = slave_status["Exec_Master_Log_Pos"]
|
225
|
-
lag = slave_status["Seconds_Behind_Master"]
|
226
|
-
master_host = slave_status["Master_Host"]
|
227
|
-
master_port = slave_status["Master_Port"]
|
228
|
-
master_instance = instance_for(master_host, master_port)
|
229
|
-
end
|
230
|
-
|
231
|
-
if slave
|
232
|
-
if lag
|
233
|
-
lag = lag.to_s
|
234
|
-
else
|
235
|
-
lag = "-"
|
236
|
-
end
|
237
|
-
format = "%1d%-4s%16s:%-10d%16s:%-10d%16s:%-10d%-8s"
|
238
|
-
str = sprintf(format, i, "(#{master_instance.to_s})", master_file,
|
239
|
-
master_pos, recv_file, recv_pos, apply_file, apply_pos, lag)
|
240
|
-
else
|
241
|
-
format = "%-5d%16s:%-10d"
|
242
|
-
str = sprintf(format, i, master_file, master_pos)
|
243
|
-
end
|
244
|
-
|
245
|
-
say str + "\n", :yellow
|
179
|
+
output = formatted_status(options)
|
180
|
+
output.each do |line|
|
181
|
+
puts line
|
246
182
|
end
|
247
183
|
break unless options[:continuous]
|
248
184
|
sleep options[:continuous]
|
@@ -255,8 +191,7 @@ class RepctlCmds < Thor
|
|
255
191
|
coordinates = do_dump(instance, dumpfile)
|
256
192
|
file = coordinates[:file]
|
257
193
|
position = coordinates[:position]
|
258
|
-
|
259
|
-
[file, String(position)]
|
194
|
+
say "Dumped at coordinates (#{file}, #{position})", :green
|
260
195
|
end
|
261
196
|
|
262
197
|
desc "restore INSTANCE [DUMPFILE]", "Restore INSTANCE from a \'mysqldump\' file DUMPFILE."
|
@@ -269,25 +204,14 @@ class RepctlCmds < Thor
|
|
269
204
|
# master has existing data.
|
270
205
|
#
|
271
206
|
desc "add_slave MASTER SLAVE", "Master has some data that is used to initialize the slave."
|
272
|
-
method_option :populate, :type => :boolean, :default => false
|
273
207
|
def add_slave(master, slave)
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
invoke "utils:bench", [master, "/opt/MySQL/b2.properties"]
|
278
|
-
end
|
279
|
-
file, position = invoke "dump", [master]
|
280
|
-
|
281
|
-
# Slave is running, but it is not yet configured as a slave.
|
282
|
-
# Load slave from the dump file...
|
283
|
-
invoke "restore", [slave]
|
284
|
-
|
285
|
-
do_change_master(master, slave, :file => file, :position => position)
|
286
|
-
do_start_slave(slave)
|
287
|
-
|
288
|
-
do_cluster_user(slave)
|
289
|
-
do_repl_user(slave)
|
208
|
+
dumpfile = DEFAULT_DUMPFILE
|
209
|
+
do_add_slave(master, slave, dumpfile)
|
210
|
+
end
|
290
211
|
|
212
|
+
desc "remove_slave SLAVE", "Remove a slave from the replica set."
|
213
|
+
def remove_slave(slave)
|
214
|
+
do_remove_slave(slave)
|
291
215
|
end
|
292
216
|
|
293
217
|
DEFAULT_MASTER = 1
|
@@ -385,16 +309,7 @@ class RepctlCmds < Thor
|
|
385
309
|
"Set up a single master/slave replication pair from the very beginning."
|
386
310
|
def repl_pair(master, slave)
|
387
311
|
say "master is #{master}, slave is #{slave}", :green
|
388
|
-
|
389
|
-
do_reset(slave)
|
390
|
-
do_cluster_user(master)
|
391
|
-
do_repl_user(master)
|
392
|
-
coordinates = get_coordinates(master)
|
393
|
-
file = coordinates[:file]
|
394
|
-
position = coordinates[:position]
|
395
|
-
say "File is #{file}, Position is #{position}", :green
|
396
|
-
do_change_master(master, slave, :file => file, :position => position)
|
397
|
-
do_start_slave(slave)
|
312
|
+
do_repl_pair(master, slave)
|
398
313
|
end
|
399
314
|
|
400
315
|
desc "repl_trio MASTER SLAVE1 SLAVE2",
|
@@ -402,30 +317,7 @@ class RepctlCmds < Thor
|
|
402
317
|
method_option :reset, :type => :boolean, :default => true
|
403
318
|
def repl_trio(master, slave1, slave2)
|
404
319
|
say "master is #{master}, slaves are #{slave1} and #{slave2}", :green
|
405
|
-
|
406
|
-
do_reset(master)
|
407
|
-
do_reset(slave1)
|
408
|
-
do_reset(slave2)
|
409
|
-
else
|
410
|
-
do_restart(master)
|
411
|
-
do_restart(slave1)
|
412
|
-
do_restart(slave2)
|
413
|
-
end
|
414
|
-
# Set up the replication accounts for all servers, in case we
|
415
|
-
# decide to switch masters later.
|
416
|
-
[master, slave1, slave2].each do |s|
|
417
|
-
do_cluster_user(s)
|
418
|
-
do_repl_user(s)
|
419
|
-
end
|
420
|
-
|
421
|
-
coordinates = get_coordinates(master)
|
422
|
-
file = coordinates[:file]
|
423
|
-
position = coordinates[:position]
|
424
|
-
say "File is #{file}, Position is #{position}", :green
|
425
|
-
do_change_master(master, slave1, :file => file, :position => position)
|
426
|
-
do_start_slave(slave1)
|
427
|
-
do_change_master(master, slave2, :file => file, :position => position)
|
428
|
-
do_start_slave(slave2)
|
320
|
+
do_repl_trio(master, slave1, slave2, options)
|
429
321
|
end
|
430
322
|
|
431
323
|
desc "install_sample_configs DIRECTORY", "After initial install, use these "
|
data/config/servers.yml
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
innodb_data_home_dir: /opt/MySQL/instances/data1
|
10
10
|
innodb_log_group_home_dir: /opt/MySQL/instances/data1
|
11
11
|
pid-file: /opt/MySQL/instances/data1/deimos.pid
|
12
|
+
user: _mysql
|
12
13
|
|
13
14
|
- instance: 2
|
14
15
|
defaults-file: "/opt/projects/repctl/config/mysql.cnf"
|
@@ -20,6 +21,7 @@
|
|
20
21
|
innodb_data_home_dir: /opt/MySQL/instances/data2
|
21
22
|
innodb_log_group_home_dir: /opt/MySQL/instances/data2
|
22
23
|
pid-file: /opt/MySQL/instances/data2/deimos.pid
|
24
|
+
user: _mysql
|
23
25
|
|
24
26
|
- instance: 3
|
25
27
|
defaults-file: "/opt/projects/repctl/config/mysql.cnf"
|
@@ -31,6 +33,7 @@
|
|
31
33
|
innodb_data_home_dir: /opt/MySQL/instances/data3
|
32
34
|
innodb_log_group_home_dir: /opt/MySQL/instances/data3
|
33
35
|
pid-file: /opt/MySQL/instances/data3/deimos.pid
|
36
|
+
user: _mysql
|
34
37
|
|
35
38
|
- instance: 4
|
36
39
|
defaults-file: "/opt/projects/repctl/config/mysql.cnf"
|
@@ -42,4 +45,5 @@
|
|
42
45
|
innodb_data_home_dir: /opt/MySQL/instances/data4
|
43
46
|
innodb_log_group_home_dir: /opt/MySQL/instances/data4
|
44
47
|
pid-file: /opt/MySQL/instances/data4/deimos.pid
|
48
|
+
user: _mysql
|
45
49
|
|
data/lib/repctl/color.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Repctl
|
2
|
+
module Color
|
3
|
+
module Constants
|
4
|
+
|
5
|
+
# Embed in a String to clear all previous ANSI sequences.
|
6
|
+
CLEAR = "\e[0m"
|
7
|
+
# The start of an ANSI bold sequence.
|
8
|
+
BOLD = "\e[1m"
|
9
|
+
|
10
|
+
# Set the terminal's foreground ANSI color to black.
|
11
|
+
BLACK = "\e[30m"
|
12
|
+
# Set the terminal's foreground ANSI color to red.
|
13
|
+
RED = "\e[31m"
|
14
|
+
# Set the terminal's foreground ANSI color to green.
|
15
|
+
GREEN = "\e[32m"
|
16
|
+
# Set the terminal's foreground ANSI color to yellow.
|
17
|
+
YELLOW = "\e[33m"
|
18
|
+
# Set the terminal's foreground ANSI color to blue.
|
19
|
+
BLUE = "\e[34m"
|
20
|
+
# Set the terminal's foreground ANSI color to magenta.
|
21
|
+
MAGENTA = "\e[35m"
|
22
|
+
# Set the terminal's foreground ANSI color to cyan.
|
23
|
+
CYAN = "\e[36m"
|
24
|
+
# Set the terminal's foreground ANSI color to white.
|
25
|
+
WHITE = "\e[37m"
|
26
|
+
|
27
|
+
# Set the terminal's background ANSI color to black.
|
28
|
+
ON_BLACK = "\e[40m"
|
29
|
+
# Set the terminal's background ANSI color to red.
|
30
|
+
ON_RED = "\e[41m"
|
31
|
+
# Set the terminal's background ANSI color to green.
|
32
|
+
ON_GREEN = "\e[42m"
|
33
|
+
# Set the terminal's background ANSI color to yellow.
|
34
|
+
ON_YELLOW = "\e[43m"
|
35
|
+
# Set the terminal's background ANSI color to blue.
|
36
|
+
ON_BLUE = "\e[44m"
|
37
|
+
# Set the terminal's background ANSI color to magenta.
|
38
|
+
ON_MAGENTA = "\e[45m"
|
39
|
+
# Set the terminal's background ANSI color to cyan.
|
40
|
+
ON_CYAN = "\e[46m"
|
41
|
+
# Set the terminal's background ANSI color to white.
|
42
|
+
ON_WHITE = "\e[47m"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set color by using a string or one of the defined constants. If a third
|
46
|
+
# option is set to true, it also adds bold to the string. This is based
|
47
|
+
# on Highline implementation and it automatically appends CLEAR to the end
|
48
|
+
# of the returned String.
|
49
|
+
#
|
50
|
+
def colorize(color, bold = false)
|
51
|
+
color = Constants.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
52
|
+
bold = bold ? Constants::BOLD : ""
|
53
|
+
"#{bold}#{color}#{self.to_s}#{Constants::CLEAR}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
String.class_eval do
|
59
|
+
include Repctl::Color
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module Repctl
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
include Commands
|
5
|
+
include Servers
|
6
|
+
|
7
|
+
def do_stop(instance)
|
8
|
+
do_admin(instance, "shutdown")
|
9
|
+
end
|
10
|
+
|
11
|
+
def do_reset(instance)
|
12
|
+
do_stop(instance)
|
13
|
+
do_config(instance)
|
14
|
+
do_start(instance)
|
15
|
+
do_secure_accounts(instance)
|
16
|
+
end
|
17
|
+
|
18
|
+
def do_start_slave(instance)
|
19
|
+
run_mysql_query(instance, "START SLAVE")
|
20
|
+
end
|
21
|
+
|
22
|
+
def do_stop_slave(instance)
|
23
|
+
run_mysql_query(instance, "STOP SLAVE")
|
24
|
+
end
|
25
|
+
|
26
|
+
def do_restart(instance)
|
27
|
+
do_admin(instance, "shutown")
|
28
|
+
do_start(instance)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Generate an array of hashes, one hash per fabric-wide instance.
|
32
|
+
def repl_status(options = {})
|
33
|
+
todos = options[:servers] || all_live_instances
|
34
|
+
return [] unless todos.any?
|
35
|
+
status_array = []
|
36
|
+
todos.each do |i|
|
37
|
+
coordinates = get_coordinates(i)
|
38
|
+
next unless coordinates
|
39
|
+
master_file = coordinates[:file]
|
40
|
+
master_pos = coordinates[:position]
|
41
|
+
|
42
|
+
fields = {}
|
43
|
+
fields[:instance] = i.to_s
|
44
|
+
fields[:server] = "#{server_for_instance(i)['hostname']}:#{i}"
|
45
|
+
fields[:generated_binlog] = "#{master_file}:#{master_pos}"
|
46
|
+
if is_slave?(i)
|
47
|
+
slave_status = get_slave_status(i)
|
48
|
+
recv_file = slave_status["Master_Log_File"]
|
49
|
+
recv_pos = slave_status["Read_Master_Log_Pos"]
|
50
|
+
apply_file = slave_status["Relay_Master_Log_File"]
|
51
|
+
apply_pos = slave_status["Exec_Master_Log_Pos"]
|
52
|
+
lag = slave_status["Seconds_Behind_Master"]
|
53
|
+
master_host = slave_status["Master_Host"]
|
54
|
+
master_port = slave_status["Master_Port"]
|
55
|
+
master_instance = instance_for(master_host, master_port)
|
56
|
+
|
57
|
+
fields[:applied_binlog] = "#{apply_file}:#{apply_pos}"
|
58
|
+
fields[:received_binlog] = "#{recv_file}:#{recv_pos}"
|
59
|
+
fields[:master] = "#{master_host}:#{master_instance}"
|
60
|
+
fields[:lag] = lag
|
61
|
+
end
|
62
|
+
status_array << fields
|
63
|
+
end
|
64
|
+
status_array
|
65
|
+
end
|
66
|
+
|
67
|
+
def formatted_status(options = {})
|
68
|
+
output = []
|
69
|
+
header = sprintf("%-5s%-27s%-27s%-27s%-8s",
|
70
|
+
"inst", "master", "received", "applied", "lag")
|
71
|
+
output << header.colorize(:green)
|
72
|
+
todos = repl_status(options)
|
73
|
+
todos.each do |server|
|
74
|
+
instance = server[:instance]
|
75
|
+
gen_binlog = server[:generated_binlog]
|
76
|
+
if server[:master]
|
77
|
+
server[:master].match(/.*:(\d*)$/)
|
78
|
+
master_instance = $1
|
79
|
+
recv_binlog = server[:received_binlog]
|
80
|
+
app_binlog = server[:applied_binlog]
|
81
|
+
lag = server[:lag]
|
82
|
+
if lag == nil
|
83
|
+
lag = "-"
|
84
|
+
else
|
85
|
+
lag = lag.to_s
|
86
|
+
end
|
87
|
+
format = "%1d%-4s%-27s%-27s%-27s%-8s"
|
88
|
+
str = sprintf(format, instance, "(#{master_instance})",
|
89
|
+
gen_binlog, recv_binlog, app_binlog, lag)
|
90
|
+
else
|
91
|
+
format = "%-5d%-26s"
|
92
|
+
str = sprintf(format, instance, gen_binlog)
|
93
|
+
end
|
94
|
+
output << str.colorize(:yellow)
|
95
|
+
end
|
96
|
+
output
|
97
|
+
end
|
98
|
+
|
99
|
+
def do_add_slave(master, slave, dumpfile)
|
100
|
+
do_reset(slave)
|
101
|
+
coordinates = do_dump(master, dumpfile)
|
102
|
+
do_restore(slave, dumpfile)
|
103
|
+
do_change_master(master, slave, coordinates)
|
104
|
+
do_start_slave(slave)
|
105
|
+
do_cluster_user(slave)
|
106
|
+
do_repl_user(slave)
|
107
|
+
end
|
108
|
+
|
109
|
+
def do_repl_pair(master, slave)
|
110
|
+
do_reset(master)
|
111
|
+
do_reset(slave)
|
112
|
+
do_cluster_user(master)
|
113
|
+
do_repl_user(master)
|
114
|
+
coordinates = get_coordinates(master)
|
115
|
+
file = coordinates[:file]
|
116
|
+
position = coordinates[:position]
|
117
|
+
do_change_master(master, slave, :file => file, :position => position)
|
118
|
+
do_start_slave(slave)
|
119
|
+
end
|
120
|
+
|
121
|
+
def do_repl_trio(master, slave1, slave2, options = {})
|
122
|
+
if options[:reset]
|
123
|
+
do_reset(master)
|
124
|
+
do_reset(slave1)
|
125
|
+
do_reset(slave2)
|
126
|
+
else
|
127
|
+
do_restart(master)
|
128
|
+
do_restart(slave1)
|
129
|
+
do_restart(slave2)
|
130
|
+
end
|
131
|
+
# Set up the replication accounts for all servers, in case we
|
132
|
+
# decide to switch masters later.
|
133
|
+
[master, slave1, slave2].each do |s|
|
134
|
+
do_cluster_user(s)
|
135
|
+
do_repl_user(s)
|
136
|
+
end
|
137
|
+
coordinates = get_coordinates(master)
|
138
|
+
file = coordinates[:file]
|
139
|
+
position = coordinates[:position]
|
140
|
+
do_change_master(master, slave1, :file => file, :position => position)
|
141
|
+
do_start_slave(slave1)
|
142
|
+
do_change_master(master, slave2, :file => file, :position => position)
|
143
|
+
do_start_slave(slave2)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/repctl/mysql_admin.rb
CHANGED
@@ -7,7 +7,6 @@ module Repctl
|
|
7
7
|
|
8
8
|
class Client < DelegateClass(Mysql2::Client)
|
9
9
|
include Servers
|
10
|
-
|
11
10
|
@@clients = {}
|
12
11
|
|
13
12
|
def initialize(instance, opts)
|
@@ -36,7 +35,6 @@ module Repctl
|
|
36
35
|
while timeout >= 0
|
37
36
|
begin
|
38
37
|
@@clients[instance] ||= Client.new(instance, opts)
|
39
|
-
# puts "Connected to instance #{instance}."
|
40
38
|
break
|
41
39
|
rescue Mysql2::Error => e
|
42
40
|
puts "#{e.message}, retrying connection to instance #{instance}..."
|
@@ -59,7 +57,6 @@ module Repctl
|
|
59
57
|
@@clients[@instance] = nil
|
60
58
|
Client.open(@instance)
|
61
59
|
end
|
62
|
-
|
63
60
|
end
|
64
61
|
|
65
62
|
module Commands
|
@@ -131,7 +128,7 @@ module Repctl
|
|
131
128
|
"--innodb_log_group_home_dir=#{server['innodb_log_group_home_dir']}",
|
132
129
|
"--relay-log=#{Socket.gethostname}-relay-bin",
|
133
130
|
"--socket=#{server['socket']}",
|
134
|
-
"--user
|
131
|
+
"--user=#{server['user']}")
|
135
132
|
end
|
136
133
|
end
|
137
134
|
end
|
@@ -415,14 +412,6 @@ EOT
|
|
415
412
|
client.close if client
|
416
413
|
end
|
417
414
|
|
418
|
-
# Return the process ID (pid) for an instance.
|
419
|
-
def get_mysqld_pid(instance)
|
420
|
-
server = server_for_instance(instance)
|
421
|
-
pidfile = server['pid-file']
|
422
|
-
return nil unless File.exist?(pidfile)
|
423
|
-
Integer(File.open(pidfile, &:readline).strip)
|
424
|
-
end
|
425
|
-
|
426
415
|
# 'master' is currently a slave that is to be the new master.
|
427
416
|
# 'slaves' contains the list of slaves, one of these may be the
|
428
417
|
# current master.
|
@@ -448,6 +437,13 @@ EOT
|
|
448
437
|
end
|
449
438
|
end
|
450
439
|
|
440
|
+
def do_remove_slave(instance)
|
441
|
+
stop_slave_io_thread(instance)
|
442
|
+
server = server_for_instance(instance)
|
443
|
+
datadir = server['datadir']
|
444
|
+
%x{ rm -f #{File.join(datadir, 'master.info')} }
|
445
|
+
end
|
446
|
+
|
451
447
|
private
|
452
448
|
|
453
449
|
# This is an example template to create commands to issue queries.
|
@@ -596,30 +592,9 @@ EOT
|
|
596
592
|
client.close
|
597
593
|
end
|
598
594
|
end
|
599
|
-
|
600
|
-
|
601
|
-
|
602
595
|
end
|
603
596
|
end
|
604
597
|
|
605
|
-
class RunExamples
|
606
|
-
include Repctl::Commands
|
607
|
-
|
608
|
-
def runtest
|
609
|
-
|
610
|
-
switch_master_to(3)
|
611
|
-
=begin
|
612
|
-
(1..4).each {|i| ensure_running(i)}
|
613
|
-
puts get_master_coordinates(1)
|
614
|
-
(2..4).each {|i| puts get_slave_coordinates(i)}
|
615
|
-
(1..4).each {|i| puts is_master?(i) }
|
616
|
-
puts "Master is #{find_master}"
|
617
|
-
drain_relay_log(2)
|
618
|
-
# sleep(10)
|
619
|
-
# (1..4).each {|i| crash(i)}
|
620
|
-
=end
|
621
|
-
end
|
622
|
-
end
|
623
598
|
|
624
599
|
|
625
600
|
|
data/lib/repctl/servers.rb
CHANGED
@@ -23,7 +23,13 @@ module Repctl
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def all_live_servers
|
26
|
-
all_servers.select
|
26
|
+
s = all_servers.select do |s|
|
27
|
+
if pid = get_mysqld_pid(s["instance"])
|
28
|
+
mysqld_running?(pid)
|
29
|
+
else
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
27
33
|
end
|
28
34
|
|
29
35
|
def all_live_instances
|
@@ -43,9 +49,13 @@ module Repctl
|
|
43
49
|
return nil
|
44
50
|
end
|
45
51
|
|
46
|
-
|
52
|
+
# See if a MySQL server with the given pid is running.
|
53
|
+
def mysqld_running?(pid)
|
54
|
+
pids = %x{ ps -e | grep mysqld}.split("\n").map { |row| row =~ /\s*(\d+)\s+/; $1.to_i}
|
55
|
+
pids.include?(pid)
|
56
|
+
end
|
47
57
|
|
48
|
-
# Return the process ID (pid) for an instance.
|
58
|
+
# Return the process ID (pid) for an instance. This only consults the PID file.
|
49
59
|
def get_mysqld_pid(instance)
|
50
60
|
server = server_for_instance(instance)
|
51
61
|
pidfile = server['pid-file']
|
data/lib/repctl/version.rb
CHANGED
data/lib/repctl.rb
CHANGED
@@ -4,9 +4,11 @@ config_dir = ENV["REPCTL_CONFIG_DIR"] ||
|
|
4
4
|
|
5
5
|
require File.join(config_dir, 'config')
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
7
|
+
require 'repctl/version'
|
8
|
+
require 'repctl/servers'
|
9
|
+
require 'repctl/mysql_admin'
|
10
|
+
require 'repctl/helpers'
|
11
|
+
require 'repctl/color'
|
10
12
|
|
11
13
|
module Repctl
|
12
14
|
# Your code goes here...
|
data/repctl.gemspec
CHANGED
@@ -20,6 +20,11 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
# specify any dependencies here; for example:
|
22
22
|
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "shotgun"
|
24
|
+
s.add_development_dependency "compass"
|
23
25
|
s.add_runtime_dependency "thor"
|
24
26
|
s.add_runtime_dependency "mysql2"
|
27
|
+
s.add_runtime_dependency "sinatra"
|
28
|
+
s.add_runtime_dependency "thin"
|
29
|
+
|
25
30
|
end
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Require any additional compass plugins here.
|
2
|
+
|
3
|
+
# Set this to the root of your project when deployed:
|
4
|
+
http_path = "/"
|
5
|
+
css_dir = "stylesheets"
|
6
|
+
sass_dir = "sass"
|
7
|
+
images_dir = "images"
|
8
|
+
javascripts_dir = "javascripts"
|
9
|
+
|
10
|
+
# You can select your preferred output style here (can be overridden via the command line):
|
11
|
+
# output_style = :expanded or :nested or :compact or :compressed
|
12
|
+
|
13
|
+
# To enable relative paths to assets via compass helper functions. Uncomment:
|
14
|
+
# relative_assets = true
|
15
|
+
|
16
|
+
# To disable debugging comments that display the original location of your selectors. Uncomment:
|
17
|
+
# line_comments = false
|
18
|
+
|
19
|
+
|
20
|
+
# If you prefer the indented syntax, you might want to regenerate this
|
21
|
+
# project again passing --syntax sass, or you can uncomment this:
|
22
|
+
# preferred_syntax = :sass
|
23
|
+
# and then run:
|
24
|
+
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
|
@@ -0,0 +1,5 @@
|
|
1
|
+
/* Welcome to Compass. Use this file to write IE specific override styles.
|
2
|
+
* Import this file using the following HTML or equivalent:
|
3
|
+
* <!--[if IE]>
|
4
|
+
* <link href="/stylesheets/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
|
5
|
+
* <![endif]--> */
|
@@ -0,0 +1,6 @@
|
|
1
|
+
/* Welcome to Compass.
|
2
|
+
* In this file you should write your main styles. (or centralize your imports)
|
3
|
+
* Import this file using the following HTML or equivalent:
|
4
|
+
* <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css" /> */
|
5
|
+
|
6
|
+
@import "compass/reset";
|
@@ -0,0 +1,5 @@
|
|
1
|
+
/* Welcome to Compass. Use this file to write IE specific override styles.
|
2
|
+
* Import this file using the following HTML or equivalent:
|
3
|
+
* <!--[if IE]>
|
4
|
+
* <link href="/stylesheets/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
|
5
|
+
* <![endif]--> */
|
@@ -0,0 +1,68 @@
|
|
1
|
+
/* Welcome to Compass.
|
2
|
+
* In this file you should write your main styles. (or centralize your imports)
|
3
|
+
* Import this file using the following HTML or equivalent:
|
4
|
+
* <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css" /> */
|
5
|
+
/* line 17, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
6
|
+
html, body, div, span, applet, object, iframe,
|
7
|
+
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
8
|
+
a, abbr, acronym, address, big, cite, code,
|
9
|
+
del, dfn, em, img, ins, kbd, q, s, samp,
|
10
|
+
small, strike, strong, sub, sup, tt, var,
|
11
|
+
b, u, i, center,
|
12
|
+
dl, dt, dd, ol, ul, li,
|
13
|
+
fieldset, form, label, legend,
|
14
|
+
table, caption, tbody, tfoot, thead, tr, th, td,
|
15
|
+
article, aside, canvas, details, embed,
|
16
|
+
figure, figcaption, footer, header, hgroup,
|
17
|
+
menu, nav, output, ruby, section, summary,
|
18
|
+
time, mark, audio, video {
|
19
|
+
margin: 0;
|
20
|
+
padding: 0;
|
21
|
+
border: 0;
|
22
|
+
font-size: 100%;
|
23
|
+
font: inherit;
|
24
|
+
vertical-align: baseline;
|
25
|
+
}
|
26
|
+
|
27
|
+
/* line 20, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
28
|
+
body {
|
29
|
+
line-height: 1;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* line 22, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
33
|
+
ol, ul {
|
34
|
+
list-style: none;
|
35
|
+
}
|
36
|
+
|
37
|
+
/* line 24, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
38
|
+
table {
|
39
|
+
border-collapse: collapse;
|
40
|
+
border-spacing: 0;
|
41
|
+
}
|
42
|
+
|
43
|
+
/* line 26, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
44
|
+
caption, th, td {
|
45
|
+
text-align: left;
|
46
|
+
font-weight: normal;
|
47
|
+
vertical-align: middle;
|
48
|
+
}
|
49
|
+
|
50
|
+
/* line 28, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
51
|
+
q, blockquote {
|
52
|
+
quotes: none;
|
53
|
+
}
|
54
|
+
/* line 101, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
55
|
+
q:before, q:after, blockquote:before, blockquote:after {
|
56
|
+
content: "";
|
57
|
+
content: none;
|
58
|
+
}
|
59
|
+
|
60
|
+
/* line 30, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
61
|
+
a img {
|
62
|
+
border: none;
|
63
|
+
}
|
64
|
+
|
65
|
+
/* line 114, ../../../../../../usr/local/rvm/gems/ruby-1.9.2-p290@rails-3.1/gems/compass-0.11.7/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
|
66
|
+
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary {
|
67
|
+
display: block;
|
68
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
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
|
+
|
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
|
+
});
|
26
|
+
|
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
|
+
});
|
37
|
+
</script>
|
38
|
+
|
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
|
+
</head>
|
76
|
+
|
77
|
+
<body>
|
78
|
+
<%= yield %>
|
79
|
+
</body>
|
80
|
+
</html>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<header id="banner">
|
2
|
+
<h1>MySQL Replication Manager</h1>
|
3
|
+
</header>
|
4
|
+
|
5
|
+
<section>
|
6
|
+
<header>
|
7
|
+
<h2>Status Summary</h2>
|
8
|
+
</header>
|
9
|
+
<div id="status-table">
|
10
|
+
</div>
|
11
|
+
</section>
|
12
|
+
|
13
|
+
<section>
|
14
|
+
<header><h2>Switch Master</h2></header>
|
15
|
+
<form id="switch-master" action="/switch_master" method="post">
|
16
|
+
<p>Master: <input type="text" name="switch[master]" size="20"/></p>
|
17
|
+
<p>Slaves: <input type="text" name="switch[slaves]" size="20"/></p>
|
18
|
+
<input type="submit" value="Switch Master">
|
19
|
+
</form>
|
20
|
+
<div>
|
21
|
+
<div style="float:left;" id="switch-master-result"></div>
|
22
|
+
<img style="float:left;" class='spinner' id="switch-master-spinner" src='images/wait30.gif' alt='spinner'></img>
|
23
|
+
</div>
|
24
|
+
</section>
|
25
|
+
|
26
|
+
<section>
|
27
|
+
<header><h2>Set up Replication Trio from Scratch</h2></header>
|
28
|
+
<form id="repl-trio" action="/repl_trio" method="post">
|
29
|
+
<p>Master: <input type="text" name="repl_trio[master]" size="20"/></p>
|
30
|
+
<p>Slaves: <input type="text" name="repl_trio[slaves]" size="20"/></p>
|
31
|
+
<input type="submit" value="Create Repliction Trio">
|
32
|
+
</form>
|
33
|
+
<div>
|
34
|
+
<div style="float:left;" id="repl-trio-result"></div>
|
35
|
+
<img style="float:left;" class="spinner" id='repl-trio-spinner' src='images/wait30.gif' alt='spinner'></img>
|
36
|
+
</div>
|
37
|
+
</section>
|
38
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<div>
|
2
|
+
Status as of <%= @timestamp %>
|
3
|
+
</div>
|
4
|
+
<table class="gridtable">
|
5
|
+
<tr>
|
6
|
+
<th>instance</th>
|
7
|
+
<th>master</th>
|
8
|
+
<th>generated binlog</th>
|
9
|
+
<th>received binlog</th>
|
10
|
+
<th>applied binlog</th>
|
11
|
+
<th>lag (secs)</th>
|
12
|
+
</tr>
|
13
|
+
<% @status_array.each do |s| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= s[:server] %></td>
|
16
|
+
<td><%= s[:master] %></td>
|
17
|
+
<td><%= s[:generated_binlog] %></td>
|
18
|
+
<td><%= s[:received_binlog] %></td>
|
19
|
+
<td><%= s[:applied_binlog] %></td>
|
20
|
+
<td><%= s[:lag] %></td>
|
21
|
+
</tr>
|
22
|
+
<% end %>
|
23
|
+
</table>
|
24
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'repctl'
|
3
|
+
|
4
|
+
include Repctl::Config
|
5
|
+
include Repctl::Commands
|
6
|
+
include Repctl::Servers
|
7
|
+
include Repctl::Utils
|
8
|
+
include Repctl::Color
|
9
|
+
|
10
|
+
def time
|
11
|
+
start = Time.now
|
12
|
+
yield
|
13
|
+
Time.now - start
|
14
|
+
end
|
15
|
+
|
16
|
+
helpers do
|
17
|
+
def img(name)
|
18
|
+
"<img src='images/#{ name}' alt='#{ name}' />"
|
19
|
+
end
|
20
|
+
|
21
|
+
def master_slave_params(params)
|
22
|
+
param_error = false
|
23
|
+
@error_message = nil
|
24
|
+
if params.nil? || params["master"] == "" || params["master"].nil? ||
|
25
|
+
params["slaves"] == nil || params["slaves"] == ""
|
26
|
+
@error_message = "parameters missing"
|
27
|
+
else
|
28
|
+
begin
|
29
|
+
master = params["master"].to_i
|
30
|
+
slaves = params["slaves"].split("\s").map(&:to_i)
|
31
|
+
rescue Exception => e
|
32
|
+
@error_message = "invalid format for parameters"
|
33
|
+
else
|
34
|
+
if master == 0 || slaves.include?(0)
|
35
|
+
@error_message = "0 can not be an instance"
|
36
|
+
elsif slaves.include?(master)
|
37
|
+
@error_message = "master can not also be a slave"
|
38
|
+
elsif slaves.empty?
|
39
|
+
@error_message = "no slaves are specified"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
[@error_message, master, slaves]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/' do
|
48
|
+
erb :main
|
49
|
+
end
|
50
|
+
|
51
|
+
# curl deimos:9393/switch_master --header "Accept: text/plain" \
|
52
|
+
# -d switch[slaves]="2 1 4" -d switch[master]=3
|
53
|
+
post '/switch_master' do
|
54
|
+
@message, master, slaves = master_slave_params(params["switch"])
|
55
|
+
if @message
|
56
|
+
@success = false
|
57
|
+
else
|
58
|
+
secs = time do
|
59
|
+
do_switch_master(master, slaves)
|
60
|
+
end
|
61
|
+
@message = "Switch master processed in #{secs} secs."
|
62
|
+
@success = true
|
63
|
+
end
|
64
|
+
if request.accept == ['text/plain']
|
65
|
+
if @success
|
66
|
+
"#{@message}\n".colorize(:green)
|
67
|
+
else
|
68
|
+
"#{@message}\n".colorize(:red)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
erb :operation_complete, :layout => !request.xhr?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
post '/repl_trio' do
|
76
|
+
@message, master, slaves = master_slave_params(params["repl_trio"])
|
77
|
+
if @message
|
78
|
+
@success = false
|
79
|
+
else
|
80
|
+
secs = time do
|
81
|
+
sleep 1
|
82
|
+
end
|
83
|
+
@message = "Create replication trio with master #{master} and slaves #{slaves} in #{secs} secs."
|
84
|
+
@success = true
|
85
|
+
end
|
86
|
+
if request.accept == ['text/plain']
|
87
|
+
if @success
|
88
|
+
"#{@message}\n".colorize(:green)
|
89
|
+
else
|
90
|
+
"#{@message}\n".colorize(:red)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
erb :operation_complete, :layout => !request.xhr?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# curl deimos:9393/status --header "Accept: text/plain"
|
98
|
+
get '/status' do
|
99
|
+
if request.accept == ['text/plain']
|
100
|
+
formatted_status.join("\n") + "\n"
|
101
|
+
else
|
102
|
+
@timestamp = Time.now.strftime("%I:%M:%S %p")
|
103
|
+
@status_array = repl_status
|
104
|
+
erb :status , :layout => !request.xhr?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
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.
|
4
|
+
version: 0.0.5
|
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-
|
12
|
+
date: 2012-03-08 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &121456320 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,32 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *121456320
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: shotgun
|
27
|
+
requirement: &121455900 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *121455900
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: compass
|
38
|
+
requirement: &121455480 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *121455480
|
25
47
|
- !ruby/object:Gem::Dependency
|
26
48
|
name: thor
|
27
|
-
requirement: &
|
49
|
+
requirement: &121455060 !ruby/object:Gem::Requirement
|
28
50
|
none: false
|
29
51
|
requirements:
|
30
52
|
- - ! '>='
|
@@ -32,10 +54,32 @@ dependencies:
|
|
32
54
|
version: '0'
|
33
55
|
type: :runtime
|
34
56
|
prerelease: false
|
35
|
-
version_requirements: *
|
57
|
+
version_requirements: *121455060
|
36
58
|
- !ruby/object:Gem::Dependency
|
37
59
|
name: mysql2
|
38
|
-
requirement: &
|
60
|
+
requirement: &121454640 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *121454640
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sinatra
|
71
|
+
requirement: &121454220 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *121454220
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: thin
|
82
|
+
requirement: &121453800 !ruby/object:Gem::Requirement
|
39
83
|
none: false
|
40
84
|
requirements:
|
41
85
|
- - ! '>='
|
@@ -43,7 +87,7 @@ dependencies:
|
|
43
87
|
version: '0'
|
44
88
|
type: :runtime
|
45
89
|
prerelease: false
|
46
|
-
version_requirements: *
|
90
|
+
version_requirements: *121453800
|
47
91
|
description: Ruby gem with Thor script to manage MySQL and PostgreSQL replication
|
48
92
|
email:
|
49
93
|
- lydianblues@gmail.com
|
@@ -63,10 +107,25 @@ files:
|
|
63
107
|
- config/mysql.cnf
|
64
108
|
- config/servers.yml
|
65
109
|
- lib/repctl.rb
|
110
|
+
- lib/repctl/color.rb
|
111
|
+
- lib/repctl/helpers.rb
|
66
112
|
- lib/repctl/mysql_admin.rb
|
67
113
|
- lib/repctl/servers.rb
|
68
114
|
- lib/repctl/version.rb
|
69
115
|
- repctl.gemspec
|
116
|
+
- webserver/public/images/wait30.gif
|
117
|
+
- webserver/sass/config.rb
|
118
|
+
- webserver/sass/sass/ie.scss
|
119
|
+
- webserver/sass/sass/print.scss
|
120
|
+
- webserver/sass/sass/screen.scss
|
121
|
+
- webserver/sass/stylesheets/ie.css
|
122
|
+
- webserver/sass/stylesheets/print.css
|
123
|
+
- webserver/sass/stylesheets/screen.css
|
124
|
+
- webserver/views/layout.erb
|
125
|
+
- webserver/views/main.erb
|
126
|
+
- webserver/views/operation_complete.erb
|
127
|
+
- webserver/views/status.erb
|
128
|
+
- webserver/webserver.rb
|
70
129
|
homepage: ''
|
71
130
|
licenses: []
|
72
131
|
post_install_message:
|