Class: Chef::Knife::Ssh
Instance Attribute Summary collapse
Attributes inherited from Chef::Knife
#name_args
Instance Method Summary
collapse
Methods inherited from Chef::Knife
#ask_question, build_sub_class, #bulk_delete, #configure_chef, #confirm, #create_object, #delete_object, #edit_data, #edit_object, #file_exists_and_is_readable?, find_command, #format_for_display, #format_list_for_display, list_commands, load_commands, #load_from_file, #output, #pretty_print, #rest, #stdin, #stdout
#convert_to_class_name, #convert_to_snake_case, #filename_to_qualified_string, #snake_case_basename
Instance Attribute Details
#password=(value) ⇒ Object
Sets the attribute password
26
27
28
|
# File 'lib/chef/knife/ssh.rb', line 26
def password=(value)
@password = value
end
|
Instance Method Details
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/chef/knife/ssh.rb', line 67
def configure_session
list = case config[:manual]
when true
@name_args[0].split(" ")
when false
r = Array.new
q = Chef::Search::Query.new
q.search(:node, @name_args[0]) do |item|
r << format_for_display(item)[config[:attribute]]
end
r
end
session_from_list(list)
end
|
#fixup_sudo(command) ⇒ Object
96
97
98
|
# File 'lib/chef/knife/ssh.rb', line 96
def fixup_sudo(command)
command.sub(/^sudo/, 'sudo -p \'knife sudo password: \'')
end
|
#get_password ⇒ Object
129
130
131
|
# File 'lib/chef/knife/ssh.rb', line 129
def get_password
@password ||= h.ask("Enter your password: ") { |q| q.echo = false }
end
|
63
64
65
|
# File 'lib/chef/knife/ssh.rb', line 63
def h
@highline ||= HighLine.new
end
|
#interactive ⇒ Object
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
# File 'lib/chef/knife/ssh.rb', line 158
def interactive
puts "Connected to #{h.list(session.servers_for.collect { |s| h.color(s.host, :cyan) }, :inline, " and ")}"
puts
puts "To run a command on a list of servers, do:"
puts " on SERVER1 SERVER2 SERVER3; COMMAND"
puts " Example: on latte foamy; echo foobar"
puts
puts "To exit interactive mode, use 'quit!'"
puts
while 1
command = read_line
case command
when 'quit!'
puts 'Bye!'
break
when /^on (.+?); (.+)$/
raw_list = $1.split(" ")
server_list = Array.new
session.servers.each do |session_server|
server_list << session_server if raw_list.include?(session_server.host)
end
command = $2
ssh_command(command, session.on(*server_list))
else
ssh_command(command)
end
end
end
|
#print_data(host, data) ⇒ Object
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/chef/knife/ssh.rb', line 100
def print_data(host, data)
if data =~ /\n/
data.split(/\n/).each { |d| print_data(host, d) }
else
padding = @longest - host.length
print h.color(host, :cyan)
padding.downto(0) { print " " }
puts data
end
end
|
#read_line ⇒ Object
Present the prompt and read a single line from the console. It also detects ^D and returns “exit” in that case. Adds the input to the history, unless the input is empty. Loops repeatedly until a non-empty line is input.
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# File 'lib/chef/knife/ssh.rb', line 137
def read_line
loop do
command = reader.readline("#{h.color('knife-ssh>', :bold)} ", true)
if command.nil?
command = "exit"
puts(command)
else
command.strip!
end
unless command.empty?
return command
end
end
end
|
154
155
156
|
# File 'lib/chef/knife/ssh.rb', line 154
def reader
Readline
end
|
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
# File 'lib/chef/knife/ssh.rb', line 201
def run
@longest = 0
require 'net/ssh/multi'
require 'readline'
require 'highline'
configure_session
case @name_args[1]
when "interactive"
interactive
when "screen"
screen
else
ssh_command(@name_args[1..-1].join(" "))
end
session.close
end
|
187
188
189
190
191
192
193
194
195
196
197
198
199
|
# File 'lib/chef/knife/ssh.rb', line 187
def screen
tf = Tempfile.new("knife-ssh-screen")
tf.puts("caption always '%w'")
tf.puts("hardstatus alwayslastline 'knife ssh #{@name_args[0]}'")
window = 0
session.servers_for.each do |server|
tf.print("screen -t \"#{server.host}\" #{window} ssh ")
server.user ? tf.puts("#{server.user}@#{server.host}") : tf.puts(server.host)
window += 1
end
tf.close
exec("screen -c #{tf.path}")
end
|
59
60
61
|
# File 'lib/chef/knife/ssh.rb', line 59
def session
@session ||= Net::SSH::Multi.start(:concurrent_connections => config[:concurrency])
end
|
#session_from_list(list) ⇒ Object
82
83
84
85
86
87
88
89
90
91
92
93
94
|
# File 'lib/chef/knife/ssh.rb', line 82
def session_from_list(list)
list.each do |item|
Chef::Log.debug("Adding #{item}")
if config[:password]
session.use config[:ssh_user] ? "#{config[:ssh_user]}@#{item}" : item, :password => config[:password]
else
session.use config[:ssh_user] ? "#{config[:ssh_user]}@#{item}" : item
end
@longest = item.length if item.length > @longest
end
session
end
|
#ssh_command(command, subsession = nil) ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# File 'lib/chef/knife/ssh.rb', line 111
def ssh_command(command, subsession=nil)
subsession ||= session
command = fixup_sudo(command)
subsession.open_channel do |ch|
ch.request_pty
ch.exec command do |ch, success|
raise ArgumentError, "Cannot execute #{command}" unless success
ch.on_data do |ichannel, data|
print_data(ichannel[:host], data)
if data =~ /^knife sudo password: /
ichannel.send_data("#{get_password}\n")
end
end
end
end
session.loop
end
|