mysqlknife 1.4.0 → 2.0.0
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.
- checksums.yaml +4 -4
- data/README.md +45 -62
- data/lib/mysqlknife.rb +5 -2
- data/lib/mysqlknife/cli.rb +120 -101
- data/lib/mysqlknife/command.rb +26 -0
- data/lib/mysqlknife/configs.rb +123 -0
- data/lib/mysqlknife/iterm.rb +29 -0
- data/lib/mysqlknife/log.rb +34 -0
- data/lib/mysqlknife/mysql.rb +24 -0
- data/lib/mysqlknife/mysql/command.rb +63 -0
- data/lib/mysqlknife/mysql/kill.rb +73 -0
- data/lib/mysqlknife/mysql/replica.rb +41 -0
- data/lib/mysqlknife/mysql/sql.rb +58 -0
- data/lib/mysqlknife/parameters.rb +84 -0
- data/lib/mysqlknife/ssh.rb +18 -0
- data/lib/mysqlknife/version.rb +1 -1
- metadata +13 -9
- data/lib/mysqlknife/checksum.rb +0 -26
- data/lib/mysqlknife/config.rb +0 -60
- data/lib/mysqlknife/connection.rb +0 -30
- data/lib/mysqlknife/kill.rb +0 -72
- data/lib/mysqlknife/replica.rb +0 -51
- data/lib/mysqlknife/sql.rb +0 -114
- data/lib/mysqlknife/swap.rb +0 -67
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mysqlknife
|
4
|
+
class Parameters
|
5
|
+
attr_writer :connection, :host, :tool
|
6
|
+
attr_reader :host, :tool
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@cnf = Configs.instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def connections
|
13
|
+
if @connection.nil?
|
14
|
+
puts @cnf.connections
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def connection_details
|
19
|
+
unless @connection.nil?
|
20
|
+
puts @cnf.show(@connection)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def hosts
|
25
|
+
if @connection.nil? == false &&
|
26
|
+
@host.nil? == true
|
27
|
+
puts @cnf.hosts(@connection)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def slaves
|
32
|
+
if @connection.nil? == false &&
|
33
|
+
@host.nil? == true
|
34
|
+
puts @cnf.slaves(@connection)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def tools
|
39
|
+
if @connection.nil? == false &&
|
40
|
+
@host.nil? == false &&
|
41
|
+
@tool.nil? == true
|
42
|
+
puts @cnf.tools(@connection)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def host_selected
|
47
|
+
if @connection.nil? == false &&
|
48
|
+
@host.nil? == false
|
49
|
+
@cnf.hosts(@connection).each do |host|
|
50
|
+
return @host = host if host.include?(@host)
|
51
|
+
end
|
52
|
+
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def slave_selected
|
58
|
+
if @connection.nil? == false &&
|
59
|
+
@host.nil? == false
|
60
|
+
@cnf.slaves(@connection).each do |host|
|
61
|
+
return @host = host if host.include?(@host)
|
62
|
+
end
|
63
|
+
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def tool_selected
|
69
|
+
if @connection.nil? == false &&
|
70
|
+
@host.nil? == false &&
|
71
|
+
@tool.nil? == false &&
|
72
|
+
@cnf.tools(@connection).include?(@tool)
|
73
|
+
@cnf.hosts(@connection).each do |host|
|
74
|
+
if host.include?(@host)
|
75
|
+
@host = host
|
76
|
+
@tool = @cnf.tool(@connection, @tool)
|
77
|
+
|
78
|
+
return @tool
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mysqlknife
|
4
|
+
class SSH
|
5
|
+
def initialize
|
6
|
+
@cnf = Configs.instance
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute(command)
|
10
|
+
%W[ssh
|
11
|
+
-t
|
12
|
+
-l #{@cnf.ssh_user}
|
13
|
+
-i #{@cnf.ssh_key}
|
14
|
+
#{@cnf.ssh_host}
|
15
|
+
"#{command}"].join(' ')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/mysqlknife/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mysqlknife
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicola Strappazzon C.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mysql2
|
@@ -81,14 +81,18 @@ files:
|
|
81
81
|
- README.md
|
82
82
|
- bin/mysqlknife
|
83
83
|
- lib/mysqlknife.rb
|
84
|
-
- lib/mysqlknife/checksum.rb
|
85
84
|
- lib/mysqlknife/cli.rb
|
86
|
-
- lib/mysqlknife/
|
87
|
-
- lib/mysqlknife/
|
88
|
-
- lib/mysqlknife/
|
89
|
-
- lib/mysqlknife/
|
90
|
-
- lib/mysqlknife/
|
91
|
-
- lib/mysqlknife/
|
85
|
+
- lib/mysqlknife/command.rb
|
86
|
+
- lib/mysqlknife/configs.rb
|
87
|
+
- lib/mysqlknife/iterm.rb
|
88
|
+
- lib/mysqlknife/log.rb
|
89
|
+
- lib/mysqlknife/mysql.rb
|
90
|
+
- lib/mysqlknife/mysql/command.rb
|
91
|
+
- lib/mysqlknife/mysql/kill.rb
|
92
|
+
- lib/mysqlknife/mysql/replica.rb
|
93
|
+
- lib/mysqlknife/mysql/sql.rb
|
94
|
+
- lib/mysqlknife/parameters.rb
|
95
|
+
- lib/mysqlknife/ssh.rb
|
92
96
|
- lib/mysqlknife/version.rb
|
93
97
|
homepage: https://github.com/nicola51980/mysqlknife
|
94
98
|
licenses:
|
data/lib/mysqlknife/checksum.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mysqlknife
|
4
|
-
class Checksum
|
5
|
-
def initialize(options = {})
|
6
|
-
dsn_from = Config.new.dsn(options[:from])
|
7
|
-
dsn_to = Config.new.dsn(options[:to])
|
8
|
-
|
9
|
-
@sum_from = sum(dsn_from, options[:table])
|
10
|
-
@sum_to = sum(dsn_to, options[:table])
|
11
|
-
end
|
12
|
-
|
13
|
-
def sum(dsn, table)
|
14
|
-
conn = Connection.new(dsn)
|
15
|
-
sql = Sql.new(dsn[:database], table)
|
16
|
-
columns = conn.execute(sql.columns)
|
17
|
-
sql = sql.checksum(columns)
|
18
|
-
columns = conn.execute(sql)
|
19
|
-
columns.first['sum']
|
20
|
-
end
|
21
|
-
|
22
|
-
def equal?
|
23
|
-
(@sum_from == @sum_to)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/mysqlknife/config.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mysqlknife
|
4
|
-
class Config
|
5
|
-
@configs = nil
|
6
|
-
|
7
|
-
def initialize(file = nil)
|
8
|
-
unless file.nil?
|
9
|
-
path = File.expand_path(File.join(Dir.pwd, file))
|
10
|
-
@configs = YAML.load_file(path) if File.exist?(path)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def get
|
15
|
-
if !@configs.nil? && !ENV['ENV'].nil?
|
16
|
-
# Convert string keys to symbols in hash:
|
17
|
-
@configs = @configs[ENV['ENV']].reduce({}) do |config, (k, v)|
|
18
|
-
config[k.to_sym] = v
|
19
|
-
config
|
20
|
-
end
|
21
|
-
|
22
|
-
# Add defaults values:
|
23
|
-
defaults(@configs)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def symbolize_keys(options)
|
28
|
-
options.inject({}){|hash,(k,v)| hash[k.to_sym] = v; hash}
|
29
|
-
end
|
30
|
-
|
31
|
-
def defaults(options)
|
32
|
-
{ host: 'localhost',
|
33
|
-
port: '3306',
|
34
|
-
user: 'root',
|
35
|
-
password: '' }
|
36
|
-
.merge(options)
|
37
|
-
end
|
38
|
-
|
39
|
-
def dsn(options)
|
40
|
-
options.split(',')
|
41
|
-
.map { |c| c.split('=', 2) }
|
42
|
-
.reduce({}) do |m, (key, value)|
|
43
|
-
case key.to_sym
|
44
|
-
when :h
|
45
|
-
key = :host
|
46
|
-
when :u
|
47
|
-
key = :user
|
48
|
-
when :p
|
49
|
-
key = :password
|
50
|
-
when :P
|
51
|
-
key = :port
|
52
|
-
when :d
|
53
|
-
key = :database
|
54
|
-
end
|
55
|
-
m[key] = value
|
56
|
-
m
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mysqlknife
|
4
|
-
class Connection
|
5
|
-
def initialize(options = {}, database = nil)
|
6
|
-
config = Config.new
|
7
|
-
options = config.symbolize_keys(options)
|
8
|
-
options = config.defaults(options)
|
9
|
-
|
10
|
-
@host = options[:host]
|
11
|
-
@port = options[:port]
|
12
|
-
@username = options[:user]
|
13
|
-
@password = options[:password]
|
14
|
-
@database = options[:database] unless database
|
15
|
-
end
|
16
|
-
|
17
|
-
def execute(sql)
|
18
|
-
conn = Mysql2::Client.new(host: @host,
|
19
|
-
port: @port,
|
20
|
-
username: @username,
|
21
|
-
password: @password,
|
22
|
-
database: @database)
|
23
|
-
return conn.query(sql)
|
24
|
-
rescue => e
|
25
|
-
puts sql
|
26
|
-
puts e
|
27
|
-
exit(1)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/mysqlknife/kill.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mysqlknife
|
4
|
-
class Kill
|
5
|
-
def initialize(options = {})
|
6
|
-
@conn = Connection.new(options)
|
7
|
-
@sql = Sql.new
|
8
|
-
@where = options[:where]
|
9
|
-
end
|
10
|
-
|
11
|
-
def clear
|
12
|
-
list.each do |process|
|
13
|
-
log(process)
|
14
|
-
kill(process['id'])
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def check_user
|
19
|
-
sql = @sql.current_user
|
20
|
-
result = @conn.execute(sql).first['CURRENT_USER'] =~ /^root\@/
|
21
|
-
|
22
|
-
return true if result
|
23
|
-
end
|
24
|
-
|
25
|
-
def check_grants
|
26
|
-
sql = @sql.current_user_grants
|
27
|
-
result = @conn.execute(sql).first.values.to_s =~ /PROCESS/
|
28
|
-
|
29
|
-
return true if result
|
30
|
-
end
|
31
|
-
|
32
|
-
def check_privileges
|
33
|
-
check_user || check_grants
|
34
|
-
end
|
35
|
-
|
36
|
-
def list
|
37
|
-
@conn.execute(@sql.processlist(@where))
|
38
|
-
end
|
39
|
-
|
40
|
-
def show
|
41
|
-
unless list.first.nil?
|
42
|
-
table = Terminal::Table.new do |t|
|
43
|
-
t.add_row(list.first.keys)
|
44
|
-
t.add_separator
|
45
|
-
list.each do |row|
|
46
|
-
t.add_row(row.values)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
table
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def log(process)
|
54
|
-
puts %W(#{Time.now.getutc}
|
55
|
-
: MySQL Kill Process -
|
56
|
-
#{process.map { |k, v| "#{k}: #{v}" }.join(', ')}
|
57
|
-
).join(' ')
|
58
|
-
end
|
59
|
-
|
60
|
-
def rds?
|
61
|
-
! @conn.execute(@sql.show_procedure('rds_kill')).first
|
62
|
-
end
|
63
|
-
|
64
|
-
def kill(id)
|
65
|
-
if rds?
|
66
|
-
@conn.execute(@sql.mysql_kill(id))
|
67
|
-
else
|
68
|
-
@conn.execute(@sql.rds_kill(id))
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
data/lib/mysqlknife/replica.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mysqlknife
|
4
|
-
class Replica
|
5
|
-
def initialize(options = {})
|
6
|
-
@conn = Connection.new(options)
|
7
|
-
@sql = Sql.new
|
8
|
-
@behind = options[:behind]
|
9
|
-
end
|
10
|
-
|
11
|
-
def check_status_negative(behind)
|
12
|
-
@behind < 0 && behind < 0 && behind <= @behind && behind != 0
|
13
|
-
end
|
14
|
-
|
15
|
-
def check_status_positive(behind)
|
16
|
-
@behind > 0 && behind > 0 && @behind <= behind && behind != 0
|
17
|
-
end
|
18
|
-
|
19
|
-
def skip
|
20
|
-
procedure_name = @sql.show_procedure('rds_skip_repl_error')
|
21
|
-
exist_procedure = @conn.execute(procedure_name).first
|
22
|
-
slave_status = @conn.execute(@sql.slave_status).first
|
23
|
-
|
24
|
-
return nil if slave_status.nil?
|
25
|
-
return nil unless slave_status.include? 'Seconds_Behind_Master'
|
26
|
-
|
27
|
-
if check_status_negative(slave_status['Seconds_Behind_Master'])
|
28
|
-
puts %W(#{Time.now.getutc} : MySQL Skip error replica -
|
29
|
-
#{slave_status.map { |k, v| "#{k}: #{v}" }.join(', ')}
|
30
|
-
).join(' ')
|
31
|
-
if exist_procedure.nil?
|
32
|
-
@conn.execute(@sql.mysql_skip_repl_error)
|
33
|
-
while @conn.next_result
|
34
|
-
message = @conn.store_result
|
35
|
-
puts %W(#{Time.now.getutc} : MySQL Skip error replica -
|
36
|
-
Message: #{message}).join(' ')
|
37
|
-
sleep(1)
|
38
|
-
end
|
39
|
-
else
|
40
|
-
message = @conn.execute(@sql.rds_skip_repl_error).first['Message']
|
41
|
-
puts %W(#{Time.now.getutc} : MySQL Skip error replica -
|
42
|
-
Message: #{message}).join(' ')
|
43
|
-
end
|
44
|
-
# Resolv Positive Lag:
|
45
|
-
elsif check_status_positive(slave_status['Seconds_Behind_Master'])
|
46
|
-
puts %W(#{Time.now.getutc} : MySQL Skip error replica -
|
47
|
-
Not implemented.).join(' ')
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
data/lib/mysqlknife/sql.rb
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mysqlknife
|
4
|
-
class Sql
|
5
|
-
def initialize(database = nil, table = nil)
|
6
|
-
@database = database
|
7
|
-
@table = table
|
8
|
-
end
|
9
|
-
|
10
|
-
def use
|
11
|
-
"USE `#{@database}`;"
|
12
|
-
end
|
13
|
-
|
14
|
-
def drop_view(view)
|
15
|
-
"DROP VIEW IF EXISTS `#{@database}`.`#{view}`;"
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_view(view, select)
|
19
|
-
"CREATE OR REPLACE VIEW `#{@database}`.`#{view}` AS #{select};"
|
20
|
-
end
|
21
|
-
|
22
|
-
def swap_table(database, table)
|
23
|
-
%W(RENAME TABLE
|
24
|
-
`#{database}`.`#{table}` TO `#{@database}`.`_#{table}_tmp`,
|
25
|
-
`#{@database}`.`#{table}` TO `#{database}`.`#{table}`,
|
26
|
-
`#{@database}`.`_#{table}_tmp` TO `#{@database}`.`#{table}`;)
|
27
|
-
.join(' ')
|
28
|
-
end
|
29
|
-
|
30
|
-
def rename_table(database, table_old, table_new = nil)
|
31
|
-
table_new = table_old unless table_old.nil?
|
32
|
-
|
33
|
-
%W(RENAME TABLE `#{@database}`.`#{table_old}`
|
34
|
-
TO `#{database}`.`#{table_new}`;).join(' ')
|
35
|
-
end
|
36
|
-
|
37
|
-
def tables
|
38
|
-
%W(SELECT table_name AS name
|
39
|
-
FROM information_schema.tables
|
40
|
-
WHERE table_schema = '#{@database}'
|
41
|
-
AND table_type = 'BASE TABLE'
|
42
|
-
ORDER BY table_name;).join(' ')
|
43
|
-
end
|
44
|
-
|
45
|
-
def views
|
46
|
-
%W(SELECT REPLACE(view_definition, '`#{@database}`.', '') AS code,
|
47
|
-
table_name AS name
|
48
|
-
FROM information_schema.views
|
49
|
-
WHERE table_schema = '#{@database}';).join(' ')
|
50
|
-
end
|
51
|
-
|
52
|
-
def processlist(where = nil)
|
53
|
-
sql = %w(SELECT id, user, host, db, command, time, state, info
|
54
|
-
FROM INFORMATION_SCHEMA.PROCESSLIST
|
55
|
-
WHERE state NOT REGEXP '(slave|relay|event)'
|
56
|
-
AND user NOT IN ('rdsadmin',
|
57
|
-
'rdsrepladmin',
|
58
|
-
'system user',
|
59
|
-
'event_scheduler')
|
60
|
-
AND id != CONNECTION_ID()
|
61
|
-
AND command != 'Binlog Dump').join(' ')
|
62
|
-
sql << " AND #{where};" unless where.nil?
|
63
|
-
end
|
64
|
-
|
65
|
-
def show_procedure(name)
|
66
|
-
"SHOW PROCEDURE STATUS LIKE '#{name}';"
|
67
|
-
end
|
68
|
-
|
69
|
-
def mysql_kill(pid)
|
70
|
-
"kill #{pid};"
|
71
|
-
end
|
72
|
-
|
73
|
-
def rds_kill(pid)
|
74
|
-
"CALL mysql.rds_kill(#{pid});"
|
75
|
-
end
|
76
|
-
|
77
|
-
def current_user
|
78
|
-
'SELECT CURRENT_USER;'
|
79
|
-
end
|
80
|
-
|
81
|
-
def current_user_grants
|
82
|
-
'SHOW GRANTS FOR CURRENT_USER;'
|
83
|
-
end
|
84
|
-
|
85
|
-
def columns
|
86
|
-
%W(SELECT COLUMN_NAME
|
87
|
-
FROM information_schema.columns
|
88
|
-
WHERE table_schema = '#{@database}'
|
89
|
-
AND table_name = '#{@table}';).join(' ')
|
90
|
-
end
|
91
|
-
|
92
|
-
def checksum(columns)
|
93
|
-
md5 = columns.map do |column| %W(COALESCE(
|
94
|
-
#{column['COLUMN_NAME']},
|
95
|
-
'#{column['COLUMN_NAME']}')).join
|
96
|
-
end
|
97
|
-
"SELECT SUM(CRC32(CONCAT(#{md5.join(', ')}))) AS sum FROM #{@table};"
|
98
|
-
end
|
99
|
-
|
100
|
-
def slave_status
|
101
|
-
'SHOW SLAVE STATUS;'
|
102
|
-
end
|
103
|
-
|
104
|
-
def rds_skip_repl_error
|
105
|
-
'CALL mysql.rds_skip_repl_error;'
|
106
|
-
end
|
107
|
-
|
108
|
-
def mysql_skip_repl_error
|
109
|
-
%w(STOP SLAVE;
|
110
|
-
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
|
111
|
-
START SLAVE;).join(' ')
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|