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.
@@ -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
@@ -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.
@@ -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
@@ -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
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ require 'mysqlknife/config'
4
+ require 'mysqlknife/connection'
5
+ require 'mysqlknife/kill'
6
+ require 'mysqlknife/sql'
7
+ require 'mysqlknife/swap'
8
+ require 'mysqlknife/version'
9
+
10
+ module Mysqlknife
11
+ # Your code goes here...
12
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module Mysqlknife
4
+ VERSION = '1.0.0'
5
+ 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: []