knife-mysql 0.1.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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +39 -0
- data/Rakefile +1 -0
- data/knife-mysql.gemspec +24 -0
- data/lib/chef/knife/mysql_scp.rb +182 -0
- data/lib/knife-mysql/version.rb +5 -0
- metadata +93 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 8d0fd4b00f5a88f5f7e90d28913295b5444c2f30
|
|
4
|
+
data.tar.gz: 8221333cd8c91b41284735c3f16393a501a814d0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b2ed1854d37e405da44073d38343341dfe0545d07bf7467068ac4d780add123d14f27bb2a72c6c30a02f4c7a8ce0f1a3fff37a8f15498ab79a61c95b896f84e1
|
|
7
|
+
data.tar.gz: d8a08ba68afc29b699120dede4213fe5a72c17dd561e7b27d4b7609258e9b3dcb49bdac06541c1ba721740ca4231d4b790994bf2f9b6cd3cc9e2727be1f8633d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# knife-mysql
|
|
2
|
+
|
|
3
|
+
`knife-mysql` is a [knife](http://docs.getchef.com/knife.html) plugin for working with MySQL databases on servers managed by [Chef](http://getchef.com/).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`gem install knife-mysql`
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
### scp
|
|
12
|
+
|
|
13
|
+
knife mysql scp SOURCE DESTINATION (options)
|
|
14
|
+
|
|
15
|
+
The `knife mysql scp` subcommand makes it easy to copy databases between nodes.
|
|
16
|
+
|
|
17
|
+
This task will `ssh` to each node matching the [source query](http://docs.getchef.com/essentials_search.html) and `mysqldump` the requested databases to a SQL file,
|
|
18
|
+
then download the resulting file to your local machine, and then upload it to each node matching the destination query, finally importing the data to `mysql` and
|
|
19
|
+
cleaning up all the files.
|
|
20
|
+
|
|
21
|
+
#### Examples
|
|
22
|
+
|
|
23
|
+
Copying a single database from one node to another.
|
|
24
|
+
|
|
25
|
+
$ knife mysql scp name:db1.example.com name:db2.example.com --databases db_example
|
|
26
|
+
|
|
27
|
+
Copying everything from your `production` database servers into a `staging` environment.
|
|
28
|
+
|
|
29
|
+
$ knife mysql scp "role:database AND chef_environment:production" "role:database AND chef_environment:staging"
|
|
30
|
+
|
|
31
|
+
See `knife mysql scp --help` for the full list of options.
|
|
32
|
+
|
|
33
|
+
## Contributing
|
|
34
|
+
|
|
35
|
+
Please do! Open a pull request with your changes and I'll be happy to review it.
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
Copyright (c) 2014 Logan Koester. Released under the MIT license. See LICENSE-MIT for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/knife-mysql.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "knife-mysql/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'knife-mysql'
|
|
7
|
+
s.version = Knife::Mysql::VERSION
|
|
8
|
+
s.authors = ['Logan Koester']
|
|
9
|
+
s.email = ['logan@logankoester.com']
|
|
10
|
+
s.homepage = 'http://github.com/logankoester/knife-mysql'
|
|
11
|
+
s.summary = %q{Knife plugin to interact with MySQL on your nodes}
|
|
12
|
+
s.description = %q{`knife-mysql` contains a utilities working with your database nodes, such as copying databases from one node or environment to another.}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = 'knife-mysql'
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
s.add_runtime_dependency 'chef'
|
|
22
|
+
s.add_runtime_dependency 'net-scp'
|
|
23
|
+
s.add_runtime_dependency 'ruby-progressbar'
|
|
24
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
require 'chef/knife'
|
|
2
|
+
|
|
3
|
+
module Knife
|
|
4
|
+
class MysqlScp < Chef::Knife
|
|
5
|
+
|
|
6
|
+
deps do
|
|
7
|
+
require 'etc'
|
|
8
|
+
require 'net/ssh'
|
|
9
|
+
require 'net/scp'
|
|
10
|
+
require 'ruby-progressbar'
|
|
11
|
+
require 'securerandom'
|
|
12
|
+
require 'fileutils'
|
|
13
|
+
require 'chef/search/query'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
banner 'knife mysql scp SOURCE DESTINATION (options)'
|
|
17
|
+
|
|
18
|
+
option :databases,
|
|
19
|
+
:short => "-B database_1,database_2",
|
|
20
|
+
:long => "--databases database_1,database_2",
|
|
21
|
+
:description => "SCP several databases",
|
|
22
|
+
:proc => Proc.new { |names| names.split(',') },
|
|
23
|
+
:default => false
|
|
24
|
+
|
|
25
|
+
option :all_databases,
|
|
26
|
+
:short => '-A',
|
|
27
|
+
:long => '--all-databases',
|
|
28
|
+
:description => 'SCP all databases',
|
|
29
|
+
:boolean => true,
|
|
30
|
+
:default => true
|
|
31
|
+
|
|
32
|
+
option :ssh_user,
|
|
33
|
+
:short => '-x USERNAME',
|
|
34
|
+
:long => '--ssh-user USERNAME',
|
|
35
|
+
:description => 'The ssh username',
|
|
36
|
+
:default => Etc.getlogin
|
|
37
|
+
|
|
38
|
+
option :user,
|
|
39
|
+
:short => '-u USERNAME',
|
|
40
|
+
:long => '--user USERNAME',
|
|
41
|
+
:description => 'The MySQL username',
|
|
42
|
+
:default => 'root'
|
|
43
|
+
|
|
44
|
+
def run
|
|
45
|
+
ensure_required_args
|
|
46
|
+
source_query = Chef::Search::Query.new
|
|
47
|
+
source_query.search 'node', name_args[0] do |source_node|
|
|
48
|
+
dumpfile = mysqldump source_node, config
|
|
49
|
+
download source_node, dumpfile
|
|
50
|
+
|
|
51
|
+
destination_query = Chef::Search::Query.new
|
|
52
|
+
destination_query.search 'node', name_args[1] do |destination_node|
|
|
53
|
+
puts destination_node
|
|
54
|
+
upload destination_node, dumpfile
|
|
55
|
+
mysqlrestore destination_node, dumpfile, config
|
|
56
|
+
delete_remote destination_node, dumpfile
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
delete dumpfile
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
def ensure_required_args
|
|
65
|
+
unless name_args.size == 2
|
|
66
|
+
puts 'Both a source query and a destination query are required.'
|
|
67
|
+
show_usage
|
|
68
|
+
exit 1
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
def mysqldump(node, config)
|
|
74
|
+
Net::SSH.start node.fqdn, config[:ssh_user] do |ssh|
|
|
75
|
+
source_password = ui.ask_question "[#{node.name}] MySQL password (#{config[:user]}): "
|
|
76
|
+
dumpfile = "knife-mysql-scp-#{SecureRandom.uuid}.sql"
|
|
77
|
+
command = "mysqldump --single-transaction -u #{config[:user]} -p#{source_password} #{databases_to_arg(config)} > #{dumpfile}"
|
|
78
|
+
ssh.open_channel do |channel|
|
|
79
|
+
ui.info "[#{node.name}] Running #{command}"
|
|
80
|
+
channel.exec command do |ch, success|
|
|
81
|
+
unless success
|
|
82
|
+
ui.error "[#{node.name}] [mysqldump] An error occurred."
|
|
83
|
+
abort
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
channel.on_request 'exit-status' do |ch, data|
|
|
87
|
+
ui.info "[#{node.name}] [mysqldump] Finished!"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
ssh.loop
|
|
92
|
+
return dumpfile
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
def mysqlrestore(node, dumpfile, config)
|
|
98
|
+
Net::SSH.start node.fqdn, config[:ssh_user] do |ssh|
|
|
99
|
+
source_password = ui.ask_question "MySQL password (#{config[:user]})"
|
|
100
|
+
command = "mysql -u #{config[:user]} -p#{source_password} < #{dumpfile}"
|
|
101
|
+
ssh.open_channel do |channel|
|
|
102
|
+
ui.info "[#{node.name}] Running #{command}"
|
|
103
|
+
channel.exec command do |ch, success|
|
|
104
|
+
unless success
|
|
105
|
+
ui.error "[#{node.name}] [mysql] An error occurred."
|
|
106
|
+
abort
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
channel.on_request 'exit-status' do |ch, data|
|
|
110
|
+
ui.info "[#{node.name}] [mysql] Finished!"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
ssh.loop
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
def download(node, filename)
|
|
120
|
+
Net::SCP.start node.fqdn, config[:ssh_user] do |scp|
|
|
121
|
+
ui.info "[#{node.name}] [scp] Downloading #{filename}..."
|
|
122
|
+
progress = ProgressBar.create :title => filename, :format => '%a %B %p%% %t'
|
|
123
|
+
scp.download! filename, filename do |ch, name, sent, total|
|
|
124
|
+
progress.total = total
|
|
125
|
+
progress.progress = sent
|
|
126
|
+
end
|
|
127
|
+
progress.finish
|
|
128
|
+
ui.info "[#{node.name}] [scp] Finished!"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def upload(node, filename)
|
|
133
|
+
Net::SCP.start node.fqdn, config[:ssh_user] do |scp|
|
|
134
|
+
ui.info "[#{node.name}] [scp] Uploading #{filename}..."
|
|
135
|
+
progress = ProgressBar.create :title => filename, :format => '%a %B %p%% %t'
|
|
136
|
+
scp.upload! filename, filename do |ch, name, sent, total|
|
|
137
|
+
progress.total = total
|
|
138
|
+
progress.progress = sent
|
|
139
|
+
end
|
|
140
|
+
progress.finish
|
|
141
|
+
ui.info "[#{node.name}] [scp] Finished!"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def delete(filename)
|
|
146
|
+
ui.info "Deleting #{filename}..."
|
|
147
|
+
FileUtils.rm(filename)
|
|
148
|
+
ui.info "Finished!"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def delete_remote(node, filename)
|
|
152
|
+
Net::SSH.start node.fqdn, config[:ssh_user] do |ssh|
|
|
153
|
+
ui.info "[#{node.name}] Deleting #{filename}..."
|
|
154
|
+
command = "rm #{filename}"
|
|
155
|
+
ssh.open_channel do |channel|
|
|
156
|
+
channel.exec command do |ch, success|
|
|
157
|
+
unless success
|
|
158
|
+
ui.info "[#{node.name}] Failed to delete #{filename}!"
|
|
159
|
+
abort
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
channel.on_request 'exit-status' do |ch, data|
|
|
163
|
+
ui.info "[#{node.name}] Finished!"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
ssh.loop
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
private
|
|
172
|
+
def databases_to_arg(config)
|
|
173
|
+
databases = config[:databases] || []
|
|
174
|
+
if config[:all_databases]
|
|
175
|
+
'--all-databases'
|
|
176
|
+
else
|
|
177
|
+
"--databases #{databases.join(' ')}"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
end
|
|
182
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: knife-mysql
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Logan Koester
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-07-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: chef
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: net-scp
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: ruby-progressbar
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
description: "`knife-mysql` contains a utilities working with your database nodes,
|
|
56
|
+
such as copying databases from one node or environment to another."
|
|
57
|
+
email:
|
|
58
|
+
- logan@logankoester.com
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- ".gitignore"
|
|
64
|
+
- Gemfile
|
|
65
|
+
- README.md
|
|
66
|
+
- Rakefile
|
|
67
|
+
- knife-mysql.gemspec
|
|
68
|
+
- lib/chef/knife/mysql_scp.rb
|
|
69
|
+
- lib/knife-mysql/version.rb
|
|
70
|
+
homepage: http://github.com/logankoester/knife-mysql
|
|
71
|
+
licenses: []
|
|
72
|
+
metadata: {}
|
|
73
|
+
post_install_message:
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - ">="
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '0'
|
|
87
|
+
requirements: []
|
|
88
|
+
rubyforge_project: knife-mysql
|
|
89
|
+
rubygems_version: 2.2.2
|
|
90
|
+
signing_key:
|
|
91
|
+
specification_version: 4
|
|
92
|
+
summary: Knife plugin to interact with MySQL on your nodes
|
|
93
|
+
test_files: []
|