knife-batch 1.0.0 → 1.0.2
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/lib/chef/knife/batch.rb +1 -14
- data/lib/knife-batch/version.rb +1 -1
- metadata +36 -30
- data/lib/chef/knife/knife-batch.rb +0 -213
data/lib/chef/knife/batch.rb
CHANGED
|
@@ -119,20 +119,7 @@ class Batch < Chef::Knife
|
|
|
119
119
|
end
|
|
120
120
|
(ui.fatal("No nodes returned from search!"); exit 10) if list.length == 0
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
child_ary = Array.new
|
|
124
|
-
iter = 0
|
|
125
|
-
list.each do |item|
|
|
126
|
-
if (iter +=1) <= config[:batch_size].to_i
|
|
127
|
-
child_ary << item
|
|
128
|
-
else
|
|
129
|
-
parent_ary << child_ary
|
|
130
|
-
child_ary = Array.new
|
|
131
|
-
iter = 0
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
parent_ary
|
|
122
|
+
list.each_slice(config[:batch_size].to_i).to_a
|
|
136
123
|
end
|
|
137
124
|
|
|
138
125
|
def print_data(host, data)
|
data/lib/knife-batch/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,65 +1,71 @@
|
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: knife-batch
|
|
3
|
-
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
5
4
|
prerelease:
|
|
5
|
+
version: 1.0.2
|
|
6
6
|
platform: ruby
|
|
7
|
-
authors:
|
|
7
|
+
authors:
|
|
8
8
|
- Ian Meyer
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
|
|
13
|
+
date: 2011-10-16 00:00:00 Z
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
15
16
|
name: chef
|
|
16
|
-
|
|
17
|
+
prerelease: false
|
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
17
19
|
none: false
|
|
18
|
-
requirements:
|
|
19
|
-
- -
|
|
20
|
-
- !ruby/object:Gem::Version
|
|
21
|
-
version:
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: "0"
|
|
22
24
|
type: :runtime
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
a la `knife ssh`, but doing it in groups of `n` with a sleep between execution iterations.'
|
|
27
|
-
email:
|
|
25
|
+
version_requirements: *id001
|
|
26
|
+
description: `knife batch` is a wonderful little plugin for executing commands a la `knife ssh`, but doing it in groups of `n` with a sleep between execution iterations.
|
|
27
|
+
email:
|
|
28
28
|
- ianmmeyer@gmail.com
|
|
29
29
|
executables: []
|
|
30
|
+
|
|
30
31
|
extensions: []
|
|
32
|
+
|
|
31
33
|
extra_rdoc_files: []
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
files:
|
|
33
36
|
- .gitignore
|
|
34
37
|
- Gemfile
|
|
35
38
|
- README.markdown
|
|
36
39
|
- Rakefile
|
|
37
40
|
- knife-batch.gemspec
|
|
38
41
|
- lib/chef/knife/batch.rb
|
|
39
|
-
- lib/chef/knife/knife-batch.rb
|
|
40
42
|
- lib/knife-batch/version.rb
|
|
41
43
|
homepage: http://github.com/imeyer/knife-batch
|
|
42
44
|
licenses: []
|
|
45
|
+
|
|
43
46
|
post_install_message:
|
|
44
47
|
rdoc_options: []
|
|
45
|
-
|
|
48
|
+
|
|
49
|
+
require_paths:
|
|
46
50
|
- lib
|
|
47
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
52
|
none: false
|
|
49
|
-
requirements:
|
|
50
|
-
- -
|
|
51
|
-
- !ruby/object:Gem::Version
|
|
52
|
-
version:
|
|
53
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: "0"
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
58
|
none: false
|
|
55
|
-
requirements:
|
|
56
|
-
- -
|
|
57
|
-
- !ruby/object:Gem::Version
|
|
58
|
-
version:
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: "0"
|
|
59
63
|
requirements: []
|
|
64
|
+
|
|
60
65
|
rubyforge_project: knife-batch
|
|
61
66
|
rubygems_version: 1.8.5
|
|
62
67
|
signing_key:
|
|
63
68
|
specification_version: 3
|
|
64
69
|
summary: Knife plugin to run ssh commands against batches of servers
|
|
65
70
|
test_files: []
|
|
71
|
+
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Author:: Ian Meyer <ianmmeyer@gmail.com>
|
|
3
|
-
# Plugin name:: batch
|
|
4
|
-
#
|
|
5
|
-
# Copyright 2011, Ian Meyer
|
|
6
|
-
#
|
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
-
# you may not use this file except in compliance with the License.
|
|
9
|
-
# You may obtain a copy of the License at
|
|
10
|
-
#
|
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
#
|
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
# See the License for the specific language governing permissions and
|
|
17
|
-
# limitations under the License.
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
class Batch < Chef::Knife
|
|
21
|
-
banner "knife batch [QUERY] [CMD]"
|
|
22
|
-
|
|
23
|
-
deps do
|
|
24
|
-
require 'net/ssh'
|
|
25
|
-
require 'net/ssh/multi'
|
|
26
|
-
require 'readline'
|
|
27
|
-
require 'chef/search/query'
|
|
28
|
-
require 'chef/mixin/command'
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
option :wait,
|
|
32
|
-
:short => "-W SECONDS",
|
|
33
|
-
:long => "--wait SECONDS",
|
|
34
|
-
:description => "The number of seconds between batches.",
|
|
35
|
-
:default => 0.5
|
|
36
|
-
|
|
37
|
-
option :batch_size,
|
|
38
|
-
:short => "-B NODES",
|
|
39
|
-
:long => "--batch-size NODES",
|
|
40
|
-
:description => "The number of nodes to run per batch.",
|
|
41
|
-
:default => 5
|
|
42
|
-
|
|
43
|
-
option :stop_on_failure,
|
|
44
|
-
:short => "-S",
|
|
45
|
-
:long => "--stop-on-failure",
|
|
46
|
-
:description => "Stop on first failure of remote command",
|
|
47
|
-
:default => false
|
|
48
|
-
|
|
49
|
-
option :manual,
|
|
50
|
-
:short => "-m",
|
|
51
|
-
:long => "--manual-list",
|
|
52
|
-
:boolean => true,
|
|
53
|
-
:description => "QUERY is a space separated list of servers",
|
|
54
|
-
:default => false
|
|
55
|
-
|
|
56
|
-
option :ssh_user,
|
|
57
|
-
:short => "-x USERNAME",
|
|
58
|
-
:long => "--ssh-user USERNAME",
|
|
59
|
-
:description => "The ssh username"
|
|
60
|
-
|
|
61
|
-
option :ssh_password,
|
|
62
|
-
:short => "-P PASSWORD",
|
|
63
|
-
:long => "--ssh-password PASSWORD",
|
|
64
|
-
:description => "The ssh password"
|
|
65
|
-
|
|
66
|
-
option :ssh_port,
|
|
67
|
-
:short => "-p PORT",
|
|
68
|
-
:long => "--ssh-port PORT",
|
|
69
|
-
:description => "The ssh port",
|
|
70
|
-
:default => "22",
|
|
71
|
-
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
|
|
72
|
-
|
|
73
|
-
option :identity_file,
|
|
74
|
-
:short => "-i IDENTITY_FILE",
|
|
75
|
-
:long => "--identity-file IDENTITY_FILE",
|
|
76
|
-
:description => "The SSH identity file used for authentication"
|
|
77
|
-
|
|
78
|
-
option :no_host_key_verify,
|
|
79
|
-
:long => "--no-host-key-verify",
|
|
80
|
-
:description => "Disable host key verification",
|
|
81
|
-
:boolean => true,
|
|
82
|
-
:default => false
|
|
83
|
-
|
|
84
|
-
option :attribute,
|
|
85
|
-
:short => "-a ATTR",
|
|
86
|
-
:long => "--attribute ATTR",
|
|
87
|
-
:description => "The attribute to use for opening the connection - default is fqdn",
|
|
88
|
-
:default => "fqdn"
|
|
89
|
-
|
|
90
|
-
def session(nodes)
|
|
91
|
-
ssh_error_handler = Proc.new do |server|
|
|
92
|
-
if config[:manual]
|
|
93
|
-
node_name = server.host
|
|
94
|
-
else
|
|
95
|
-
nodes.each do |n|
|
|
96
|
-
node_name = n if format_for_display(n)[config[:attribute]] == server.host
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
ui.warn "Failed to connect to #{node_name} -- #{$!.class.name}: #{$!.message}"
|
|
100
|
-
$!.backtrace.each { |l| Chef::Log.debug(l) }
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
@ssh_session ||= Net::SSH::Multi.start(:concurrent_connections => config[:concurrency], :on_error => ssh_error_handler)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def get_nodes
|
|
107
|
-
list = case config[:manual]
|
|
108
|
-
when true
|
|
109
|
-
@name_args[0].split(" ")
|
|
110
|
-
when false
|
|
111
|
-
r = Array.new
|
|
112
|
-
q = Chef::Search::Query.new
|
|
113
|
-
@action_nodes = q.search(:node, @name_args[0])[0]
|
|
114
|
-
@action_nodes.each do |item|
|
|
115
|
-
i = format_for_display(item)[config[:attribute]]
|
|
116
|
-
r.push(i) unless i.nil?
|
|
117
|
-
end
|
|
118
|
-
r
|
|
119
|
-
end
|
|
120
|
-
(ui.fatal("No nodes returned from search!"); exit 10) if list.length == 0
|
|
121
|
-
|
|
122
|
-
parent_ary = Array.new
|
|
123
|
-
child_ary = Array.new
|
|
124
|
-
iter = 0
|
|
125
|
-
list.each do |item|
|
|
126
|
-
if (iter +=1) <= config[:batch_size].to_i
|
|
127
|
-
child_ary << item
|
|
128
|
-
else
|
|
129
|
-
parent_ary << child_ary
|
|
130
|
-
child_ary = Array.new
|
|
131
|
-
iter = 0
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
parent_ary
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def print_data(host, data)
|
|
139
|
-
if data =~ /\n/
|
|
140
|
-
data.split(/\n/).each { |d| print_data(host, d) }
|
|
141
|
-
else
|
|
142
|
-
padding = @longest - host.length
|
|
143
|
-
print ui.color(host, :cyan)
|
|
144
|
-
padding.downto(0) { print " " }
|
|
145
|
-
puts data
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def session_from_list(nodes)
|
|
150
|
-
nodes.each do |item|
|
|
151
|
-
Chef::Log.debug("Adding #{item}")
|
|
152
|
-
|
|
153
|
-
hostspec = config[:ssh_user] ? "#{config[:ssh_user]}@#{item}" : item
|
|
154
|
-
session_opts = {}
|
|
155
|
-
session_opts[:keys] = File.expand_path(config[:identity_file]) if config[:identity_file]
|
|
156
|
-
session_opts[:password] = config[:ssh_password] if config[:ssh_password]
|
|
157
|
-
session_opts[:port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
|
|
158
|
-
session_opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
|
|
159
|
-
|
|
160
|
-
if config[:no_host_key_verify]
|
|
161
|
-
session_opts[:paranoid] = false
|
|
162
|
-
session_opts[:user_known_hosts_file] = "/dev/null"
|
|
163
|
-
end
|
|
164
|
-
session(nodes).use(hostspec, session_opts)
|
|
165
|
-
|
|
166
|
-
@longest = item.length if item.length > @longest
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
session(nodes)
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def ssh_command(command, subsession=nil, nodes)
|
|
173
|
-
subsession ||= session(nodes)
|
|
174
|
-
subsession.open_channel do |channel|
|
|
175
|
-
host = channel[:host]
|
|
176
|
-
channel.request_pty
|
|
177
|
-
channel.exec command do |ch, success|
|
|
178
|
-
exit_code = nil
|
|
179
|
-
raise ArgumentError, "Cannot execute #{command}" unless success
|
|
180
|
-
channel.on_data do |ch, data|
|
|
181
|
-
print_data(host, data)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
if config[:stop_on_failure]
|
|
185
|
-
channel.on_request("exit-status") do |ch, data|
|
|
186
|
-
exit_code = data.read_long
|
|
187
|
-
if not exit_code.nil?
|
|
188
|
-
exit 1 if exit_code.to_i > 0
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
@ssh_session.loop
|
|
195
|
-
@ssh_session = nil
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def run
|
|
199
|
-
extend Chef::Mixin::Command
|
|
200
|
-
|
|
201
|
-
@longest = 0
|
|
202
|
-
all_nodes = get_nodes
|
|
203
|
-
all_nodes.each do |nodes|
|
|
204
|
-
session_from_list(nodes)
|
|
205
|
-
|
|
206
|
-
ssh_command(@name_args[1..-1].join(" "), nodes)
|
|
207
|
-
puts "*" * 80
|
|
208
|
-
puts "Taking a nap for #{config[:wait]} seconds..."
|
|
209
|
-
puts "*" * 80
|
|
210
|
-
sleep config[:wait].to_f
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
end
|