mysqlknife 1.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 +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +53 -0
- data/bin/mysqlknife +83 -0
- data/lib/mysqlknife.rb +12 -0
- data/lib/mysqlknife/config.rb +39 -0
- data/lib/mysqlknife/connection.rb +41 -0
- data/lib/mysqlknife/kill.rb +38 -0
- data/lib/mysqlknife/sql.rb +84 -0
- data/lib/mysqlknife/swap.rb +63 -0
- data/lib/mysqlknife/version.rb +5 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2d375284a62187872eddd91fba09f0da91bcc450
|
4
|
+
data.tar.gz: d556e33bf773b026f4024441949f4fa837760bee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a47e344f675bf8ff135010b824c85dd020275f68a962d2863ca710a430863a8a1ac6ce52064747f7f715bc9efa08880b85a334dde026d33f5a688ce6513a999
|
7
|
+
data.tar.gz: 2fda7a0ba3ad1c17317de5fa03cb3a2836aa28dfe612dae97fb46b3c168b4b361c8209c70501d22df21eadc1c8a5ef6011573564ba3d90f8f3de2cf9dc311407
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nicola Strappazzon C.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Mysqlknife
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install this tool executing the following command:
|
8
|
+
|
9
|
+
```Shell
|
10
|
+
$ gem install mysqlkill
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
|
16
|
+
### Swap Databases
|
17
|
+
|
18
|
+
Swap tables and views between two databases.
|
19
|
+
|
20
|
+
You need to rename two databases, for example, foo and bar. You only need to run the
|
21
|
+
following command and save the STDOUT output to a file and then execute DML
|
22
|
+
statements.
|
23
|
+
|
24
|
+
```Shell
|
25
|
+
$ mysqlknife swap --host 127.0.0.1 --user root --password admin --databases from,to > swap.sql
|
26
|
+
$ mysql -h 127.0.0.1 -u root -padmin < swap.sql
|
27
|
+
```
|
28
|
+
|
29
|
+
### Kill process
|
30
|
+
|
31
|
+
Please, follow next instructions to kill process:
|
32
|
+
|
33
|
+
```Shell
|
34
|
+
$ mysqlknife kill --host 127.0.0.1 --user root --pass admin --where "time >= 200" --list
|
35
|
+
```
|
36
|
+
|
37
|
+
```Shell
|
38
|
+
$ mysqlknife kill --host 127.0.0.1 --user root --pass admin --where "time >= 200"
|
39
|
+
```
|
40
|
+
|
41
|
+
## Warning
|
42
|
+
|
43
|
+
1. Do not use this tool in production before testing it.
|
44
|
+
2. Please, use when do you need.
|
45
|
+
3. The author is NOT responsible for misuse use of this tool.
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
1. Fork it
|
50
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
51
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
52
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
53
|
+
5. Create new Pull Request
|
data/bin/mysqlknife
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
$LOAD_PATH << './lib'
|
5
|
+
|
6
|
+
require 'commander'
|
7
|
+
require 'commander/import'
|
8
|
+
require 'terminal-table'
|
9
|
+
require 'mysqlknife'
|
10
|
+
|
11
|
+
program :name, 'MySQL knife tools'
|
12
|
+
program :version, Mysqlknife::VERSION
|
13
|
+
program :description, 'MySQL knife tools'
|
14
|
+
program :help, 'Author', 'Nicola Strappazzon <nicola51980@gmail.com>'
|
15
|
+
|
16
|
+
global_option('-H', '--host STRING')
|
17
|
+
global_option('-u', '--user STRING')
|
18
|
+
global_option('-p', '--password [STRING]')
|
19
|
+
global_option('-P', '--port [STRING]')
|
20
|
+
|
21
|
+
command :swap do |c|
|
22
|
+
c.description = 'Swap two databases.'
|
23
|
+
c.syntax = %w(mysqlknife swap
|
24
|
+
--host 127.0.0.1
|
25
|
+
--user root
|
26
|
+
--password admin
|
27
|
+
--databases from,to).join(' ')
|
28
|
+
c.option '--databases STRING', String, 'Databases to swap.'
|
29
|
+
|
30
|
+
c.action do |args, options|
|
31
|
+
if options.host.nil? ||
|
32
|
+
options.user.nil? ||
|
33
|
+
options.databases.nil? ||
|
34
|
+
options.databases.split(',').count != 2
|
35
|
+
puts c.syntax
|
36
|
+
else
|
37
|
+
swap = Mysqlknife::Swap.new(options.__hash__).all
|
38
|
+
|
39
|
+
if swap
|
40
|
+
swap.each do |sql|
|
41
|
+
puts sql
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
command :kill do |c|
|
49
|
+
c.description = 'Kill all process.'
|
50
|
+
c.syntax = %w(mysqlknife kill
|
51
|
+
--host 127.0.0.1
|
52
|
+
--user root
|
53
|
+
--password admin
|
54
|
+
--where "time >= 28800").join(' ')
|
55
|
+
c.option '--where STRING', String, 'Conditions to filter.'
|
56
|
+
c.option '--list', 'List match process to kill.'
|
57
|
+
|
58
|
+
c.action do |args, options|
|
59
|
+
if options.host.nil? ||
|
60
|
+
options.user.nil? ||
|
61
|
+
options.where.nil?
|
62
|
+
puts c.syntax
|
63
|
+
else
|
64
|
+
kill = Mysqlknife::Kill.new(options.__hash__)
|
65
|
+
|
66
|
+
if options.list.nil?
|
67
|
+
kill.clear unless kill.list.first.nil?
|
68
|
+
else
|
69
|
+
unless kill.list.first.nil?
|
70
|
+
table = Terminal::Table.new do |t|
|
71
|
+
t.add_row(kill.list.first.keys)
|
72
|
+
t.add_separator
|
73
|
+
|
74
|
+
kill.list.each do |row|
|
75
|
+
t.add_row(row.values)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
puts table
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/mysqlknife.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Mysqlknife
|
6
|
+
class Config
|
7
|
+
@configs = nil
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
unless file.nil?
|
11
|
+
path = File.expand_path(File.join(Dir.pwd, file))
|
12
|
+
@configs = YAML.load_file(path) if File.exist?(path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def get
|
17
|
+
if !@configs.nil? && !ENV['ENV'].nil?
|
18
|
+
# Convert string keys to symbols in hash:
|
19
|
+
@configs = @configs[ENV['ENV']].reduce({}) do |config, (k, v)|
|
20
|
+
config[k.to_sym] = v
|
21
|
+
config
|
22
|
+
end
|
23
|
+
|
24
|
+
# Add defaults values:
|
25
|
+
defaults(@configs)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def defaults(options)
|
30
|
+
options.delete_if { |k, v| v.nil? }
|
31
|
+
|
32
|
+
{ host: 'localhost',
|
33
|
+
port: '3306',
|
34
|
+
user: 'root',
|
35
|
+
pass: '' }
|
36
|
+
.merge(options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mysql2'
|
5
|
+
|
6
|
+
module Mysqlknife
|
7
|
+
class Connection
|
8
|
+
def initialize(options = {}, database = nil)
|
9
|
+
options = options(options)
|
10
|
+
|
11
|
+
@host = options[:host]
|
12
|
+
@port = options[:port]
|
13
|
+
@username = options[:user]
|
14
|
+
@password = options[:password]
|
15
|
+
@database = database
|
16
|
+
end
|
17
|
+
|
18
|
+
def options(options)
|
19
|
+
options.delete_if { |k, v| v.nil? }
|
20
|
+
|
21
|
+
{ host: 'localhost',
|
22
|
+
port: '3306',
|
23
|
+
user: 'root',
|
24
|
+
password: '' }
|
25
|
+
.merge(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute(sql)
|
29
|
+
begin
|
30
|
+
conn = Mysql2::Client.new(host: @host,
|
31
|
+
port: @port,
|
32
|
+
username: @username,
|
33
|
+
password: @password,
|
34
|
+
database: @database)
|
35
|
+
return conn.query(sql)
|
36
|
+
rescue
|
37
|
+
exit(1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
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 check_privileges
|
12
|
+
sql_user = @sql.current_user
|
13
|
+
sql_grants = @sql.current_user_grants
|
14
|
+
if @conn.execute(sql_user).first['CURRENT_USER'] =~ /^root\@/
|
15
|
+
return true
|
16
|
+
else
|
17
|
+
|
18
|
+
return true if @conn.execute(sql_grants).first.values.to_s =~ /PROCESS/
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def list
|
23
|
+
@conn.execute(@sql.processlist(@where))
|
24
|
+
end
|
25
|
+
|
26
|
+
def clear
|
27
|
+
exist_procedure = @conn.execute(@sql.show_procedure('rds_kill'))
|
28
|
+
|
29
|
+
@conn.execute(@sql.processlist(@where)).each do |process|
|
30
|
+
if exist_procedure.first.nil?
|
31
|
+
@conn.execute(@sql.mysql_kill(process['id']))
|
32
|
+
else
|
33
|
+
@conn.execute(@sql.rds_kill(process['id']))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mysqlknife
|
4
|
+
class Sql
|
5
|
+
def initialize(database = nil)
|
6
|
+
@database = database
|
7
|
+
end
|
8
|
+
|
9
|
+
def use
|
10
|
+
"USE `#{@database}`;"
|
11
|
+
end
|
12
|
+
|
13
|
+
def drop_view(view)
|
14
|
+
"DROP VIEW IF EXISTS `#{@database}`.`#{view}`;"
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_view(view, select)
|
18
|
+
"CREATE OR REPLACE VIEW `#{@database}`.`#{view}` AS #{select};"
|
19
|
+
end
|
20
|
+
|
21
|
+
def swap_table(database, table)
|
22
|
+
%W(RENAME TABLE
|
23
|
+
`#{database}`.`#{table}` TO `#{@database}`.`_#{table}_tmp`,
|
24
|
+
`#{@database}`.`#{table}` TO `#{database}`.`#{table}`,
|
25
|
+
`#{@database}`.`_#{table}_tmp` TO `#{@database}`.`#{table}`;)
|
26
|
+
.join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
def rename_table(database, table_old, table_new = nil)
|
30
|
+
table_new = table_old unless table_old.nil?
|
31
|
+
|
32
|
+
%W(RENAME TABLE `#{@database}`.`#{table_old}`
|
33
|
+
TO `#{database}`.`#{table_new}`;).join(' ')
|
34
|
+
end
|
35
|
+
|
36
|
+
def tables
|
37
|
+
%W(SELECT table_name AS name
|
38
|
+
FROM information_schema.tables
|
39
|
+
WHERE table_schema = '#{@database}'
|
40
|
+
AND table_type = 'BASE TABLE'
|
41
|
+
ORDER BY table_name;).join(' ')
|
42
|
+
end
|
43
|
+
|
44
|
+
def views
|
45
|
+
%W(SELECT REPLACE(view_definition, '`#{@database}`.', '') AS code,
|
46
|
+
table_name AS name
|
47
|
+
FROM information_schema.views
|
48
|
+
WHERE table_schema = '#{@database}';).join(' ')
|
49
|
+
end
|
50
|
+
|
51
|
+
def processlist(where = nil)
|
52
|
+
sql = %w(SELECT id, user, host, db, command, time, state, info
|
53
|
+
FROM INFORMATION_SCHEMA.PROCESSLIST
|
54
|
+
WHERE state NOT REGEXP '(slave|relay|event)'
|
55
|
+
AND user NOT IN ('rdsadmin',
|
56
|
+
'rdsrepladmin',
|
57
|
+
'system user',
|
58
|
+
'event_scheduler')
|
59
|
+
AND id != CONNECTION_ID()
|
60
|
+
AND command != 'Binlog Dump').join(' ')
|
61
|
+
sql << " AND #{where}" unless where.nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
def show_procedure(name)
|
65
|
+
"SHOW PROCEDURE STATUS LIKE '#{name}';"
|
66
|
+
end
|
67
|
+
|
68
|
+
def mysql_kill(pid)
|
69
|
+
"kill #{pid};"
|
70
|
+
end
|
71
|
+
|
72
|
+
def rds_kill(pid)
|
73
|
+
"CALL mysql.rds_kill(#{pid});"
|
74
|
+
end
|
75
|
+
|
76
|
+
def current_user
|
77
|
+
'SELECT CURRENT_USER;'
|
78
|
+
end
|
79
|
+
|
80
|
+
def current_user_grants
|
81
|
+
'SHOW GRANTS FOR CURRENT_USER;'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mysqlknife
|
4
|
+
class Swap
|
5
|
+
def initialize(options = {})
|
6
|
+
databases = options[:databases].split(',')
|
7
|
+
@db_from = databases[0]
|
8
|
+
@db_to = databases[1]
|
9
|
+
@conn_from = Connection.new(options, @db_from)
|
10
|
+
@conn_to = Connection.new(options, @db_to)
|
11
|
+
@from = Sql.new(@db_from)
|
12
|
+
@to = Sql.new(@db_to)
|
13
|
+
end
|
14
|
+
|
15
|
+
def all
|
16
|
+
sql = []
|
17
|
+
|
18
|
+
# Swap tables.
|
19
|
+
tables_from = @conn_from.execute(@from.tables)
|
20
|
+
tables_from = tables_from.map { |f| f['name'] } if tables_from
|
21
|
+
tables_to = @conn_to.execute(@to.tables)
|
22
|
+
tables_to = tables_to.map { |t| t['name'] } if tables_to
|
23
|
+
|
24
|
+
if tables_from && tables_to
|
25
|
+
swap = tables_from & tables_to
|
26
|
+
rename = (tables_from - tables_to) + (tables_to - tables_from)
|
27
|
+
|
28
|
+
unless swap.empty?
|
29
|
+
swap.map do | table |
|
30
|
+
sql << @to.swap_table(@db_from, table)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
unless rename.empty?
|
35
|
+
rename.map do | table |
|
36
|
+
if tables_from.include?(table)
|
37
|
+
sql << @from.rename_table(@db_to, table)
|
38
|
+
else
|
39
|
+
sql << @to.rename_table(@db_from, table)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Drop views and create new views in another DB.
|
46
|
+
sql.concat(swap_views(@conn_from, @from, @to))
|
47
|
+
sql.concat(swap_views(@conn_to, @to, @from))
|
48
|
+
end
|
49
|
+
|
50
|
+
def swap_views(conn, from, to)
|
51
|
+
sql = []
|
52
|
+
views = conn.execute(to.views)
|
53
|
+
if views
|
54
|
+
sql << to.use
|
55
|
+
views.each do | view |
|
56
|
+
sql << to.drop_view(view['name'])
|
57
|
+
sql << from.create_view(view['name'], view['code'])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
sql
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mysqlknife
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicola Strappazzon C.
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: MySQL knife tools
|
14
|
+
email: nicola51980@gmail.com
|
15
|
+
executables:
|
16
|
+
- mysqlknife
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/mysqlknife
|
21
|
+
- lib/mysqlknife/config.rb
|
22
|
+
- lib/mysqlknife/connection.rb
|
23
|
+
- lib/mysqlknife/kill.rb
|
24
|
+
- lib/mysqlknife/sql.rb
|
25
|
+
- lib/mysqlknife/swap.rb
|
26
|
+
- lib/mysqlknife/version.rb
|
27
|
+
- lib/mysqlknife.rb
|
28
|
+
- LICENSE.txt
|
29
|
+
- README.md
|
30
|
+
homepage: https://github.com/nicola51980/mysqlknife
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.1.11
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: ''
|
54
|
+
test_files: []
|