ghaki-net-ssh 2011.11.30.1
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/LICENSE +19 -0
- data/README +23 -0
- data/VERSION +1 -0
- data/lib/ghaki/net_ssh/account.rb +38 -0
- data/lib/ghaki/net_ssh/errors.rb +3 -0
- data/lib/ghaki/net_ssh/ftp.rb +72 -0
- data/lib/ghaki/net_ssh/logger.rb +136 -0
- data/lib/ghaki/net_ssh/shell.rb +179 -0
- data/lib/ghaki/net_ssh/spec_helper.rb +65 -0
- data/lib/ghaki/net_ssh/telnet.rb +72 -0
- data/lib/ghaki/net_ssh.rb +12 -0
- data/spec/ghaki/net_ssh/account_spec.rb +42 -0
- data/spec/ghaki/net_ssh/common_helper.rb +22 -0
- data/spec/ghaki/net_ssh/ftp_spec.rb +75 -0
- data/spec/ghaki/net_ssh/logger_spec.rb +180 -0
- data/spec/ghaki/net_ssh/shell_spec.rb +138 -0
- data/spec/ghaki/net_ssh/telnet_spec.rb +67 -0
- data/spec/spec_helper.rb +7 -0
- metadata +202 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010 Gerald Kalafut
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
= Ghaki Net SSH - Secure Shell helpers
|
2
|
+
|
3
|
+
Ghaki Net SSH is a collection of extensions for the Net SSH gem library.
|
4
|
+
|
5
|
+
== Download
|
6
|
+
|
7
|
+
The latest version of Ghaki Net SSH can be found at
|
8
|
+
|
9
|
+
* git@github.com:ghaki/ghaki-net-ssh.git
|
10
|
+
|
11
|
+
== Installation
|
12
|
+
|
13
|
+
The preferred method of installing Ghaki Net SSH is through its GEM file.
|
14
|
+
|
15
|
+
% [sudo] gem install ghaki-net-ssh-1.0.0.gem
|
16
|
+
|
17
|
+
== License
|
18
|
+
|
19
|
+
Ghaki Net SSH is released under the MIT license.
|
20
|
+
|
21
|
+
== Support
|
22
|
+
|
23
|
+
Contact mailto:gerald@kalafut.org
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2011.11.30.1
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'ghaki/account/base'
|
2
|
+
require 'ghaki/net_ssh/shell'
|
3
|
+
|
4
|
+
module Ghaki #:nodoc:
|
5
|
+
module NetSSH #:nodoc:
|
6
|
+
|
7
|
+
class Account < Ghaki::Account::Base
|
8
|
+
attr_accessor :logger
|
9
|
+
|
10
|
+
def initialize opts={}; super opts
|
11
|
+
@logger = opts[:logger]
|
12
|
+
end
|
13
|
+
|
14
|
+
def start_shell opts={}, &block
|
15
|
+
Ghaki::NetSSH::Shell.start \
|
16
|
+
setup_shell_opts(opts), &block
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_ftp opts={}, &block
|
20
|
+
Ghaki::NetSSH::FTP.start \
|
21
|
+
setup_shell_opts(opts), &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_telnet opts={}, &block
|
25
|
+
Ghaki::NetSSH::Telnet.start \
|
26
|
+
setup_shell_opts(opts), &block
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def setup_shell_opts opts
|
32
|
+
opts[:account] = self
|
33
|
+
opts[:logger] ||= @logger unless @logger.nil?
|
34
|
+
opts
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'net/sftp'
|
5
|
+
require 'ghaki/core_ext/file/with_temp'
|
6
|
+
require 'ghaki/net_ssh/shell'
|
7
|
+
|
8
|
+
module Ghaki #:nodoc:
|
9
|
+
module NetSSH #:nodoc:
|
10
|
+
|
11
|
+
class FTP < DelegateClass(::Net::SFTP)
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
attr_accessor :raw_ftp, :shell
|
15
|
+
def_delegators :@shell,
|
16
|
+
:log_command_on, :log_output_on, :log_all_on,
|
17
|
+
:log_command_off, :log_output_off, :log_all_off,
|
18
|
+
:log_exec!, :log_command!
|
19
|
+
|
20
|
+
def self.start *args
|
21
|
+
ssh_gak = Ghaki::NetSSH::Shell.start( *args )
|
22
|
+
ftp_gak = Ghaki::NetSSH::FTP.new( ssh_gak )
|
23
|
+
if block_given?
|
24
|
+
begin
|
25
|
+
yield ftp_gak
|
26
|
+
ensure
|
27
|
+
ssh_gak.close
|
28
|
+
end
|
29
|
+
else
|
30
|
+
return ftp_gak
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def close
|
35
|
+
@shell.close
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize ssh
|
39
|
+
@shell = ssh
|
40
|
+
@raw_ftp = @shell.raw_ssh.sftp
|
41
|
+
super(@raw_ftp)
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove! fname
|
45
|
+
begin
|
46
|
+
log_command! 'SFTP', "remove #{fname}"
|
47
|
+
@raw_ftp.remove! fname
|
48
|
+
rescue ::Net::SFTP::StatusException
|
49
|
+
raise unless $!.message =~ %r{ \b no \s such \s file \b }oix
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def upload! loc_file, rem_file
|
54
|
+
tmp_file = ::File.join( ::File.dirname(rem_file),
|
55
|
+
'_tmp_' + $$.to_s + '.' + ::File.basename(rem_file) )
|
56
|
+
log_command! 'SFTP', "upload #{loc_file}, #{tmp_file}"
|
57
|
+
@raw_ftp.upload! loc_file, tmp_file
|
58
|
+
log_command! 'SFTP', "rename #{tmp_file}, #{rem_file}"
|
59
|
+
@raw_ftp.rename! tmp_file, rem_file
|
60
|
+
ensure
|
61
|
+
self.remove! tmp_file
|
62
|
+
end
|
63
|
+
|
64
|
+
def download! rem_file, loc_file
|
65
|
+
log_command! 'SFTP', "download #{rem_file}, #{loc_file}"
|
66
|
+
File.with_named_temp loc_file do |tmp_file|
|
67
|
+
@raw_ftp.download! rem_file, tmp_file
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'ghaki/logger/mixin'
|
2
|
+
|
3
|
+
module Ghaki #:nodoc:
|
4
|
+
module NetSSH #:nodoc:
|
5
|
+
|
6
|
+
module Logger
|
7
|
+
include Ghaki::Logger::Mixin
|
8
|
+
|
9
|
+
attr_accessor :should_log_command, :should_log_output
|
10
|
+
|
11
|
+
NO_OUTPUT = '** NO OUTPUT **'
|
12
|
+
|
13
|
+
def setup_logger opts
|
14
|
+
@logger = opts[:logger]
|
15
|
+
@should_log_command = opts[:log_ssh_command]
|
16
|
+
@should_log_command = true if @should_log_command.nil?
|
17
|
+
@should_log_output = opts[:log_ssh_output]
|
18
|
+
@should_log_output = true if @should_log_output.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
######################################################################
|
22
|
+
# TURN ON/OFF ALL LOGGING
|
23
|
+
######################################################################
|
24
|
+
|
25
|
+
def log_all_on &block
|
26
|
+
out = ''
|
27
|
+
old_out,old_cmd = @should_log_output,@should_log_command
|
28
|
+
@should_log_output = @should_log_command = true
|
29
|
+
if not block.nil?
|
30
|
+
begin
|
31
|
+
out = block.call
|
32
|
+
ensure
|
33
|
+
@should_log_output,@should_log_command = old_out,old_cmd
|
34
|
+
end
|
35
|
+
end
|
36
|
+
out
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_all_off &block
|
40
|
+
out = ''
|
41
|
+
old_out,old_cmd = @should_log_output,@should_log_command
|
42
|
+
@should_log_output = @should_log_command = false
|
43
|
+
if not block.nil?
|
44
|
+
begin
|
45
|
+
out = block.call
|
46
|
+
ensure
|
47
|
+
@should_log_output,@should_log_command = old_out,old_cmd
|
48
|
+
end
|
49
|
+
end
|
50
|
+
out
|
51
|
+
end
|
52
|
+
|
53
|
+
######################################################################
|
54
|
+
# TURN COMMAND LOGGIN ON/OFF
|
55
|
+
######################################################################
|
56
|
+
|
57
|
+
def log_command_on &block
|
58
|
+
out = ''
|
59
|
+
orig,@should_log_command = @should_log_command,true
|
60
|
+
if not block.nil?
|
61
|
+
begin
|
62
|
+
out = block.call
|
63
|
+
ensure
|
64
|
+
@should_log_command = orig
|
65
|
+
end
|
66
|
+
end
|
67
|
+
out
|
68
|
+
end
|
69
|
+
|
70
|
+
def log_command_off &block
|
71
|
+
out = ''
|
72
|
+
orig,@should_log_command = @should_log_command,false
|
73
|
+
if not block.nil?
|
74
|
+
begin
|
75
|
+
out = block.call
|
76
|
+
ensure
|
77
|
+
@should_log_command = orig
|
78
|
+
end
|
79
|
+
end
|
80
|
+
out
|
81
|
+
end
|
82
|
+
|
83
|
+
######################################################################
|
84
|
+
# TURN OUTPUT LOGGIN ON/OFF
|
85
|
+
######################################################################
|
86
|
+
|
87
|
+
def log_output_on &block
|
88
|
+
out = ''
|
89
|
+
orig,@should_log_output = @should_log_output,true
|
90
|
+
if not block.nil?
|
91
|
+
begin
|
92
|
+
out = block.call
|
93
|
+
ensure
|
94
|
+
@should_log_output = orig
|
95
|
+
end
|
96
|
+
end
|
97
|
+
out
|
98
|
+
end
|
99
|
+
|
100
|
+
def log_output_off &block
|
101
|
+
out = ''
|
102
|
+
orig,@should_log_output = @should_log_output,false
|
103
|
+
if not block.nil?
|
104
|
+
begin
|
105
|
+
out = block.call
|
106
|
+
ensure
|
107
|
+
@should_log_output = orig
|
108
|
+
end
|
109
|
+
end
|
110
|
+
out
|
111
|
+
end
|
112
|
+
|
113
|
+
######################################################################
|
114
|
+
# DO THE ACTUAL LOGGING WORK
|
115
|
+
######################################################################
|
116
|
+
|
117
|
+
def log_exec! title, cmd, &block
|
118
|
+
log_command! title, cmd
|
119
|
+
out = block.call || ''
|
120
|
+
return out unless @should_log_output
|
121
|
+
if out == ''
|
122
|
+
logger.puts( NO_OUTPUT )
|
123
|
+
else
|
124
|
+
logger.liner
|
125
|
+
logger.puts( out )
|
126
|
+
logger.liner
|
127
|
+
end
|
128
|
+
out
|
129
|
+
end
|
130
|
+
|
131
|
+
def log_command! title, cmd
|
132
|
+
logger.puts "#{title} #{@account.hostname} : #{cmd}" if @should_log_command
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'net/ssh/telnet'
|
3
|
+
require 'net/sftp'
|
4
|
+
|
5
|
+
require 'ghaki/account/base'
|
6
|
+
require 'ghaki/core_ext/file/with_temp'
|
7
|
+
|
8
|
+
require 'ghaki/net_ssh/errors'
|
9
|
+
require 'ghaki/net_ssh/ftp'
|
10
|
+
require 'ghaki/net_ssh/logger'
|
11
|
+
require 'ghaki/net_ssh/telnet'
|
12
|
+
|
13
|
+
module Ghaki #:nodoc:
|
14
|
+
module NetSSH #:nodoc:
|
15
|
+
|
16
|
+
class Shell < DelegateClass(::Net::SSH)
|
17
|
+
include Ghaki::NetSSH::Logger
|
18
|
+
|
19
|
+
DEF_TIMEOUT = 30
|
20
|
+
DEF_AUTH_METHODS = %w{
|
21
|
+
password
|
22
|
+
keyboard-interactive
|
23
|
+
publickey
|
24
|
+
hostbased
|
25
|
+
}
|
26
|
+
|
27
|
+
######################################################################
|
28
|
+
protected
|
29
|
+
######################################################################
|
30
|
+
|
31
|
+
def self.raw_opts_log cur_opts, raw_opts
|
32
|
+
if cur_opts.has_key?(:logger)
|
33
|
+
if cur_opts[:logger].nil?
|
34
|
+
# doesn't handle nil correctly
|
35
|
+
raw_opts.delete(:logger)
|
36
|
+
elsif cur_opts[:logger].level < ::Logger::WARN
|
37
|
+
# anything over WARN is insane
|
38
|
+
raw_opts[:logger] = cur_opts[:logger].dup
|
39
|
+
raw_opts[:logger].level = ::Logger::WARN
|
40
|
+
end
|
41
|
+
end
|
42
|
+
raw_opts
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.raw_opts_setup cur_opts
|
46
|
+
raw_opts = raw_opts_log( cur_opts, cur_opts.dup )
|
47
|
+
raw_opts[:timeout] ||= DEF_TIMEOUT
|
48
|
+
raw_opts[:auth_methods] ||= DEF_AUTH_METHODS
|
49
|
+
raw_opts.delete(:log_ssh_output)
|
50
|
+
raw_opts.delete(:log_ssh_command)
|
51
|
+
raw_opts.delete(:account)
|
52
|
+
unless cur_opts[:account].password.nil?
|
53
|
+
raw_opts[:password] = cur_opts[:account].password
|
54
|
+
end
|
55
|
+
raw_opts
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.args_to_opts args
|
59
|
+
case args.length
|
60
|
+
when 2
|
61
|
+
return Hash.new
|
62
|
+
when 1, 3
|
63
|
+
return args.pop
|
64
|
+
else
|
65
|
+
raise ArgumentError, "Invalid Arguments Passed: (1..3) != #{args.length}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.args_to_account args, cur_opts
|
70
|
+
if args.length == 0
|
71
|
+
acc = Ghaki::Account::Base.from_opts cur_opts
|
72
|
+
else
|
73
|
+
acc = Ghaki::Account::Base.new \
|
74
|
+
:hostname => args.shift,
|
75
|
+
:username => args.shift
|
76
|
+
acc.password = Ghaki::Account::Password.parse_opts(cur_opts)
|
77
|
+
end
|
78
|
+
raise ArgumentError, 'Missing Hostname' if acc.hostname.nil?
|
79
|
+
raise ArgumentError, 'Missing Username' if acc.username.nil?
|
80
|
+
acc.collapse_opts(cur_opts)
|
81
|
+
acc
|
82
|
+
end
|
83
|
+
|
84
|
+
######################################################################
|
85
|
+
public
|
86
|
+
######################################################################
|
87
|
+
|
88
|
+
def self.start *args
|
89
|
+
cur_opts = args_to_opts( args )
|
90
|
+
acc = args_to_account( args, cur_opts )
|
91
|
+
raw_opts = raw_opts_setup( cur_opts )
|
92
|
+
begin
|
93
|
+
raw_ssh = ::Net::SSH.start( acc.hostname, acc.username, raw_opts )
|
94
|
+
cur_ssh = Ghaki::NetSSH::Shell.new( raw_ssh, cur_opts )
|
95
|
+
if block_given?
|
96
|
+
begin yield cur_ssh ensure raw_ssh.close end
|
97
|
+
else
|
98
|
+
return cur_ssh
|
99
|
+
end
|
100
|
+
rescue ::Net::SSH::HostKeyMismatch
|
101
|
+
$!.remember_host!
|
102
|
+
retry
|
103
|
+
rescue Net::SSH::AuthenticationFailed
|
104
|
+
if acc.retry_password?
|
105
|
+
acc.fail_password
|
106
|
+
unless cur_opts[:logger].nil?
|
107
|
+
cur_opts[:logger].warn "failed password attempt for: #{acc}"
|
108
|
+
end
|
109
|
+
retry
|
110
|
+
else
|
111
|
+
raise
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
attr_accessor :raw_ssh, :account
|
117
|
+
|
118
|
+
def initialize obj, opts={}
|
119
|
+
setup_logger opts
|
120
|
+
@account = opts[:account]
|
121
|
+
@raw_ssh = obj
|
122
|
+
super obj
|
123
|
+
end
|
124
|
+
|
125
|
+
def sftp
|
126
|
+
ftp_obj = Ghaki::NetSSH::FTP.new( self )
|
127
|
+
if block_given?
|
128
|
+
yield ftp_obj
|
129
|
+
else
|
130
|
+
return ftp_obj
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def telnet opts={}
|
135
|
+
tel_obj = Ghaki::NetSSH::Telnet.new( self, opts )
|
136
|
+
if block_given?
|
137
|
+
begin
|
138
|
+
yield tel_obj
|
139
|
+
ensure
|
140
|
+
tel_obj.close
|
141
|
+
end
|
142
|
+
else
|
143
|
+
return tel_obj
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def exec! cmd
|
148
|
+
self.log_exec! 'SSH', cmd do
|
149
|
+
@raw_ssh.exec!( cmd )
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def remove! rem_file
|
154
|
+
sftp.remove! rem_file
|
155
|
+
end
|
156
|
+
|
157
|
+
def upload! loc_file, rem_file
|
158
|
+
sftp.upload! loc_file, rem_file
|
159
|
+
end
|
160
|
+
|
161
|
+
def download! rem_file, loc_file
|
162
|
+
sftp.download! rem_file, loc_file
|
163
|
+
end
|
164
|
+
|
165
|
+
def discover cmd, lookup
|
166
|
+
return lookup.match_lines( self.exec!(cmd).split("\n") ) do
|
167
|
+
raise RemoteCommandError, 'SSH Discovery Output Not Matched'
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def redirect rem_file, loc_file, &block
|
172
|
+
sftp.remove! rem_file
|
173
|
+
out = block.call
|
174
|
+
sftp.download! rem_file, loc_file
|
175
|
+
out
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ghaki/net_ssh/shell'
|
2
|
+
require 'ghaki/logger/spec_helper'
|
3
|
+
|
4
|
+
module Ghaki #:nodoc:
|
5
|
+
module NetSSH #:nodoc:
|
6
|
+
|
7
|
+
module SpecHelper
|
8
|
+
include Ghaki::Logger::SpecHelper
|
9
|
+
|
10
|
+
def stub_raw_net_ssh
|
11
|
+
@tel_raw = stub_everything('Net::Telnet')
|
12
|
+
::Net::SSH::Telnet.stubs({
|
13
|
+
:new => @tel_raw,
|
14
|
+
})
|
15
|
+
@ssh_raw = stub_everything('Net::SSH')
|
16
|
+
::Net::SSH.stubs({
|
17
|
+
:start => @ssh_raw,
|
18
|
+
})
|
19
|
+
@ftp_raw = stub_everything('Net::SFTP')
|
20
|
+
@ssh_raw.stubs({
|
21
|
+
:sftp => @ftp_raw,
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
def stub_gak_net_ssh
|
26
|
+
stub_raw_net_ssh
|
27
|
+
@ftp_gak = stub_everything('Ghaki::NetSSH::FTP')
|
28
|
+
Ghaki::NetSSH::FTP.stubs({
|
29
|
+
:new => @ftp_gak,
|
30
|
+
})
|
31
|
+
@tel_gak = stub_everything('Ghaki::NetSSH::Telnet')
|
32
|
+
Ghaki::NetSSH::Telnet.stubs({
|
33
|
+
:new => @tel_gak,
|
34
|
+
})
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear_safe_gak_net_ssh
|
38
|
+
@ssh_gak = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup_safe_gak_net_ssh opts={}
|
42
|
+
return unless @ssh_gak.nil?
|
43
|
+
setup_safe_logger
|
44
|
+
stub_gak_net_ssh
|
45
|
+
opts[:hostname] ||= 'host'
|
46
|
+
opts[:username] ||= 'user'
|
47
|
+
opts[:password] ||= 'secret'
|
48
|
+
opts[:logger] ||= @logger
|
49
|
+
@ssh_gak = Ghaki::NetSSH::Shell.start(opts)
|
50
|
+
@ssh_gak.stubs({
|
51
|
+
:sftp => @ftp_gak,
|
52
|
+
:telnet => @tel_gak,
|
53
|
+
})
|
54
|
+
Ghaki::NetSSH::Shell.stubs({
|
55
|
+
:new => @ssh_gak,
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
def reset_safe_gak_net_ssh opts={}
|
60
|
+
clear_safe_gak_net_ssh
|
61
|
+
setup_safe_gak_net_ssh opts
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'net/ssh/telnet'
|
5
|
+
require 'ghaki/net_ssh/shell'
|
6
|
+
|
7
|
+
module Ghaki #:nodoc:
|
8
|
+
module NetSSH #:nodoc:
|
9
|
+
|
10
|
+
class Telnet < DelegateClass(::Net::SSH::Telnet)
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
attr_accessor :raw_telnet, :shell, :auto_close
|
14
|
+
|
15
|
+
def_delegators :@shell,
|
16
|
+
:log_command_on, :log_output_on, :log_all_on,
|
17
|
+
:log_command_off, :log_output_off, :log_all_off,
|
18
|
+
:log_exec!, :log_command!
|
19
|
+
|
20
|
+
def self.args_to_tel_opts args
|
21
|
+
case args.length
|
22
|
+
when 2
|
23
|
+
return Hash.new
|
24
|
+
when 1, 3
|
25
|
+
return args.last[:telnet_options] || {}
|
26
|
+
else
|
27
|
+
raise ArgumentError, "Invalid Arguments Passed: (1..3) != #{args.length}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.start *args, &block
|
32
|
+
tel_opt = args_to_tel_opts( args )
|
33
|
+
gak_ssh = Shell.start( *args )
|
34
|
+
gak_tel = Telnet.new( gak_ssh, tel_opt )
|
35
|
+
gak_tel.auto_close = true
|
36
|
+
if block_given?
|
37
|
+
begin
|
38
|
+
block.call( gak_tel )
|
39
|
+
ensure
|
40
|
+
gak_tel.close
|
41
|
+
end
|
42
|
+
else
|
43
|
+
return gak_tel
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def auto_close?
|
48
|
+
@auto_close
|
49
|
+
end
|
50
|
+
|
51
|
+
def close
|
52
|
+
super
|
53
|
+
@shell.close if @auto_close
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize ssh, in_opts={}
|
57
|
+
@auto_close = false
|
58
|
+
@shell = ssh
|
59
|
+
out_opts = in_opts.dup
|
60
|
+
out_opts['Session'] = @shell.raw_ssh
|
61
|
+
@raw_telnet = ::Net::SSH::Telnet.new(out_opts)
|
62
|
+
super @raw_telnet
|
63
|
+
end
|
64
|
+
|
65
|
+
def exec! cmd
|
66
|
+
log_exec!( 'TELNET', cmd ) do
|
67
|
+
@raw_telnet.cmd( cmd )
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'net/ssh/telnet'
|
3
|
+
require 'net/sftp'
|
4
|
+
|
5
|
+
require 'ghaki/account/base'
|
6
|
+
require 'ghaki/core_ext/file/with_temp'
|
7
|
+
|
8
|
+
require 'ghaki/net_ssh/errors'
|
9
|
+
require 'ghaki/net_ssh/shell'
|
10
|
+
require 'ghaki/net_ssh/ftp'
|
11
|
+
require 'ghaki/net_ssh/logger'
|
12
|
+
require 'ghaki/net_ssh/telnet'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ghaki/net_ssh/common_helper'
|
2
|
+
require 'ghaki/net_ssh/account'
|
3
|
+
|
4
|
+
module Ghaki module NetSSH module Account_Testing
|
5
|
+
describe Account do
|
6
|
+
include CommonHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
setup_common
|
10
|
+
@account = Ghaki::NetSSH::Account.new(@user_opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
it { should be_kind_of(Ghaki::Account::Base) }
|
14
|
+
it { should respond_to :logger }
|
15
|
+
it { should respond_to :logger= }
|
16
|
+
|
17
|
+
describe '#start_shell' do
|
18
|
+
it 'should create shell connection' do
|
19
|
+
Ghaki::NetSSH::Shell.expects(:start).
|
20
|
+
with( :account => subject ).returns(:shell_started)
|
21
|
+
subject.start_shell.should == :shell_started
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#start_ftp' do
|
26
|
+
it 'should create ftp connection' do
|
27
|
+
Ghaki::NetSSH::FTP.expects(:start).
|
28
|
+
with( :account => subject ).returns(:sftp_started)
|
29
|
+
subject.start_ftp.should == :sftp_started
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#start_telnet' do
|
34
|
+
it 'should create telnet connection' do
|
35
|
+
Ghaki::NetSSH::Telnet.expects(:start).
|
36
|
+
with( :account => subject ).returns(:telnet_started)
|
37
|
+
subject.start_telnet.should == :telnet_started
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end end end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ghaki/account/base'
|
2
|
+
require 'ghaki/net_ssh/spec_helper'
|
3
|
+
|
4
|
+
module CommonHelper
|
5
|
+
include Ghaki::NetSSH::SpecHelper
|
6
|
+
|
7
|
+
def setup_common
|
8
|
+
setup_safe_logger
|
9
|
+
stub_raw_net_ssh
|
10
|
+
@user_opts = {
|
11
|
+
:username => 'user',
|
12
|
+
:hostname => 'host',
|
13
|
+
:password => 'secret',
|
14
|
+
}
|
15
|
+
@account = Ghaki::Account::Base.new @user_opts
|
16
|
+
@test_opts = {
|
17
|
+
:account => @account,
|
18
|
+
:logger => @logger,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'ghaki/net_ssh/ftp'
|
2
|
+
require 'ghaki/net_ssh/common_helper'
|
3
|
+
|
4
|
+
module Ghaki module NetSSH module FTP_Testing
|
5
|
+
describe FTP do
|
6
|
+
include CommonHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
setup_common
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'class' do
|
13
|
+
subject { FTP }
|
14
|
+
describe '#start' do
|
15
|
+
it 'should yield ftp' do
|
16
|
+
@ssh_raw.expects(:close).once
|
17
|
+
FTP.start(@test_opts) do |sftp|
|
18
|
+
sftp.should be_an_instance_of(FTP)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
it 'should return ftp' do
|
22
|
+
@ssh_raw.expects(:close).once
|
23
|
+
sftp = FTP.start(@test_opts)
|
24
|
+
sftp.should be_an_instance_of(FTP)
|
25
|
+
sftp.close
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'object' do
|
31
|
+
|
32
|
+
before(:each) do
|
33
|
+
@ftp_gak = FTP.start(@test_opts)
|
34
|
+
end
|
35
|
+
subject { @ftp_gak }
|
36
|
+
|
37
|
+
context 'logging delegates' do
|
38
|
+
[ :log_command_on, :log_output_on, :log_all_on,
|
39
|
+
:log_command_off, :log_output_off, :log_all_off,
|
40
|
+
:log_exec!, :log_command!,
|
41
|
+
].each do |token|
|
42
|
+
it { should respond_to token }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#remove!' do
|
47
|
+
it 'should delegate remove' do
|
48
|
+
@ftp_raw.expects(:remove!).with('remote_file')
|
49
|
+
@ftp_gak.remove! 'remote_file'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#upload!' do
|
54
|
+
it 'should delegate upload, rename, and remove' do
|
55
|
+
seq = sequence('uploader')
|
56
|
+
src = 'local_file'; dst = 'remote_file'
|
57
|
+
@ftp_raw.expects(:upload!).with(src,is_a(String)).in_sequence(seq)
|
58
|
+
@ftp_raw.expects(:rename!).with(is_a(String),dst).in_sequence(seq)
|
59
|
+
@ftp_raw.expects(:remove!).with(is_a(String)).in_sequence(seq)
|
60
|
+
@ftp_gak.upload! src, dst
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#download!' do
|
65
|
+
it 'should delegate download' do
|
66
|
+
src = 'remote_file'; dst = 'local_file'; tmp = 'tmp_file'
|
67
|
+
::File.expects(:with_named_temp).yields(tmp)
|
68
|
+
@ftp_raw.expects(:download!).with(src,tmp)
|
69
|
+
@ftp_gak.download! src, dst
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end end end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'ghaki/net_ssh/logger'
|
2
|
+
require 'ghaki/net_ssh/common_helper'
|
3
|
+
|
4
|
+
module Ghaki module NetSSH module Logger_Testing
|
5
|
+
describe Logger do
|
6
|
+
include CommonHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
setup_common
|
10
|
+
end
|
11
|
+
|
12
|
+
class UsingLogger
|
13
|
+
include Logger
|
14
|
+
attr_accessor :account
|
15
|
+
def initialize opts={}
|
16
|
+
setup_logger opts
|
17
|
+
@account = opts[:account]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'objects including' do
|
22
|
+
|
23
|
+
describe '#setup_logger' do
|
24
|
+
it 'should accept opt <log_ssh_command>' do
|
25
|
+
@subj = UsingLogger.new( :logger => @logger, :log_ssh_command => false )
|
26
|
+
@subj.should_log_command.should be_false
|
27
|
+
end
|
28
|
+
it 'should default opt <log_ssh_command>' do
|
29
|
+
@subj = UsingLogger.new( :logger => @logger )
|
30
|
+
@subj.should_log_command.should be_true
|
31
|
+
end
|
32
|
+
it 'should accept opt <log_ssh_output>' do
|
33
|
+
@subj = UsingLogger.new( :logger => @logger, :log_ssh_output => false )
|
34
|
+
@subj.should_log_output.should be_false
|
35
|
+
end
|
36
|
+
it 'should default opt <log_ssh_output>' do
|
37
|
+
@subj = UsingLogger.new( :logger => @logger )
|
38
|
+
@subj.should_log_output.should be_true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
before(:each) do
|
43
|
+
@subj = UsingLogger.new(@test_opts)
|
44
|
+
end
|
45
|
+
subject { @subj }
|
46
|
+
|
47
|
+
describe '#log_command!' do
|
48
|
+
it 'should log title, command, and host' do
|
49
|
+
@logger.expects(:puts).with('SSH host : who').once
|
50
|
+
@subj.log_command! 'SSH', 'who'
|
51
|
+
end
|
52
|
+
it 'should not log when supressed' do
|
53
|
+
@subj.should_log_command = false
|
54
|
+
@logger.expects(:puts).never
|
55
|
+
@subj.log_command! 'SSH', 'who'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#log_exec!' do
|
60
|
+
it 'should log title and output' do
|
61
|
+
@logger.expects(:puts).with('SSH host : who').once
|
62
|
+
@logger.expects(:puts).with('output').once
|
63
|
+
@logger.expects(:liner).twice
|
64
|
+
@subj.log_exec!('SSH', 'who') do 'output' end.should == 'output'
|
65
|
+
end
|
66
|
+
it 'should log only output when command is supressed' do
|
67
|
+
@subj.should_log_command = false
|
68
|
+
@logger.expects(:puts).with('SSH host : who').never
|
69
|
+
@logger.expects(:puts).with('output').once
|
70
|
+
@logger.expects(:liner).twice
|
71
|
+
@subj.log_exec!('SSH', 'who') do 'output' end.should == 'output'
|
72
|
+
end
|
73
|
+
it 'should not log when both are supressed' do
|
74
|
+
@subj.should_log_command = false
|
75
|
+
@subj.should_log_output = false
|
76
|
+
@logger.expects(:puts).never
|
77
|
+
@logger.expects(:liner).never
|
78
|
+
@subj.log_exec!('SSH', 'who') do 'output' end.should == 'output'
|
79
|
+
end
|
80
|
+
it 'should default for no output' do
|
81
|
+
@subj.should_log_command = false
|
82
|
+
@logger.expects(:puts).with('** NO OUTPUT **').once
|
83
|
+
@logger.expects(:liner).never
|
84
|
+
@subj.log_exec!('SSH', 'who') do nil end.should == ''
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#log_all_on' do
|
89
|
+
before(:each) do
|
90
|
+
@subj.should_log_command = @subj.should_log_output = false
|
91
|
+
end
|
92
|
+
it 'should apply only within block' do
|
93
|
+
@subj.log_all_on do
|
94
|
+
@subj.should_log_command.should be_true
|
95
|
+
@subj.should_log_output.should be_true
|
96
|
+
end
|
97
|
+
@subj.should_log_command.should be_false
|
98
|
+
@subj.should_log_output.should be_false
|
99
|
+
end
|
100
|
+
it 'should set permanently' do
|
101
|
+
@subj.log_all_on
|
102
|
+
@subj.should_log_command.should be_true
|
103
|
+
@subj.should_log_output.should be_true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#log_all_off' do
|
108
|
+
it 'should apply only within block' do
|
109
|
+
@subj.log_all_off do
|
110
|
+
@subj.should_log_command.should be_false
|
111
|
+
@subj.should_log_output.should be_false
|
112
|
+
end
|
113
|
+
@subj.should_log_command.should be_true
|
114
|
+
@subj.should_log_output.should be_true
|
115
|
+
end
|
116
|
+
it 'should set permanently' do
|
117
|
+
@subj.log_all_off
|
118
|
+
@subj.should_log_command.should be_false
|
119
|
+
@subj.should_log_output.should be_false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#log_command_on' do
|
124
|
+
before(:each) do @subj.should_log_command = false end
|
125
|
+
it 'should apply only within block' do
|
126
|
+
@subj.log_command_on do
|
127
|
+
@subj.should_log_command.should be_true
|
128
|
+
end
|
129
|
+
@subj.should_log_command.should be_false
|
130
|
+
end
|
131
|
+
it 'should set permanently' do
|
132
|
+
@subj.log_command_on
|
133
|
+
@subj.should_log_command.should be_true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#log_command_off' do
|
138
|
+
it 'should apply only within block' do
|
139
|
+
@subj.log_command_off do
|
140
|
+
@subj.should_log_command.should be_false
|
141
|
+
end
|
142
|
+
@subj.should_log_command.should be_true
|
143
|
+
end
|
144
|
+
it 'should set permanently' do
|
145
|
+
@subj.log_command_off
|
146
|
+
@subj.should_log_command.should be_false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#log_output_on' do
|
151
|
+
before(:each) do @subj.should_log_output = false end
|
152
|
+
it 'should apply only within block' do
|
153
|
+
@subj.log_output_on do
|
154
|
+
@subj.should_log_output.should be_true
|
155
|
+
end
|
156
|
+
@subj.should_log_output.should be_false
|
157
|
+
end
|
158
|
+
it 'should set permanently' do
|
159
|
+
@subj.log_output_on
|
160
|
+
@subj.should_log_output.should be_true
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#log_output_off' do
|
165
|
+
it 'should apply only within block' do
|
166
|
+
@subj.log_output_off do
|
167
|
+
@subj.should_log_output.should be_false
|
168
|
+
end
|
169
|
+
@subj.should_log_output.should be_true
|
170
|
+
end
|
171
|
+
it 'should set permanently' do
|
172
|
+
@subj.log_output_off
|
173
|
+
@subj.should_log_output.should be_false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end end end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'ghaki/net_ssh/shell'
|
2
|
+
require 'ghaki/net_ssh/common_helper'
|
3
|
+
require 'ghaki/match/parser/base'
|
4
|
+
|
5
|
+
module Ghaki module NetSSH module Shell_Testing
|
6
|
+
describe Shell do
|
7
|
+
include CommonHelper
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
setup_common
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'eigen class' do
|
14
|
+
subject { Shell }
|
15
|
+
|
16
|
+
describe '#start' do
|
17
|
+
it 'returns ssh' do
|
18
|
+
subject.start(@test_opts).should be_an_instance_of(Shell)
|
19
|
+
end
|
20
|
+
it 'yields ssh' do
|
21
|
+
@ssh_raw.expects(:close).once
|
22
|
+
subject.start(@test_opts) do |ssh|
|
23
|
+
ssh.should be_an_instance_of(Shell)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
it 'handles password retries' do
|
27
|
+
@account.passwords = ['invalid','secret']
|
28
|
+
::Net::SSH.expects(:start).raises(::Net::SSH::AuthenticationFailed).then.returns(@ssh_raw)
|
29
|
+
@logger.expects(:warn).with(regexp_matches(%r{failed\spassword\sattempt}))
|
30
|
+
subject.start(@test_opts).should be_an_instance_of(Shell)
|
31
|
+
@account.failed_passwords?.should be_true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'object instance' do
|
38
|
+
before(:each) do
|
39
|
+
@ssh_gak = Shell.start(@test_opts)
|
40
|
+
end
|
41
|
+
subject { @ssh_gak }
|
42
|
+
|
43
|
+
describe '#exec!' do
|
44
|
+
it 'delegates to ssh' do
|
45
|
+
@ssh_raw.expects(:exec!).with('who').returns('nobody')
|
46
|
+
@ssh_gak.exec! 'who'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#telnet' do
|
51
|
+
it 'creates telnet' do
|
52
|
+
tel = @ssh_gak.telnet
|
53
|
+
tel.should be_an_instance_of(Telnet)
|
54
|
+
end
|
55
|
+
it 'yields telnet' do
|
56
|
+
@tel_raw.expects(:close).once
|
57
|
+
@ssh_gak.telnet do |tel|
|
58
|
+
tel.should be_an_instance_of(Telnet)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#discover' do
|
64
|
+
before(:each) do
|
65
|
+
@matcher = Ghaki::Match::Parser::Base.new({
|
66
|
+
%r{foo}o => :foo,
|
67
|
+
})
|
68
|
+
end
|
69
|
+
it 'matches if found' do
|
70
|
+
@ssh_raw.expects(:exec!).with('who').returns('foo')
|
71
|
+
@ssh_gak.discover( 'who', @matcher ).should == :foo
|
72
|
+
end
|
73
|
+
it 'rejects if not found' do
|
74
|
+
lambda do
|
75
|
+
@ssh_raw.expects(:exec!).with('who').returns('bar')
|
76
|
+
@ssh_gak.discover( 'who', @matcher )
|
77
|
+
end.should raise_error(RemoteCommandError)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#sftp' do
|
82
|
+
it 'creates ftp' do
|
83
|
+
ftp = @ssh_gak.sftp
|
84
|
+
ftp.should be_an_instance_of(FTP)
|
85
|
+
end
|
86
|
+
it 'yields ftp' do
|
87
|
+
@ssh_gak.sftp do |ftp|
|
88
|
+
ftp.should be_an_instance_of(FTP)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
####################################################################
|
94
|
+
describe 'sftp helpers' do
|
95
|
+
|
96
|
+
before(:each) do
|
97
|
+
@ftp_gak = mock('Ghaki::NetSSH::FTP')
|
98
|
+
FTP.stubs( :new => @ftp_gak )
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#remove!' do
|
102
|
+
it 'delegates to ftp' do
|
103
|
+
trg = 'remote_file'
|
104
|
+
@ftp_gak.expects(:remove!).with(trg)
|
105
|
+
@ssh_gak.remove! trg
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#upload!' do
|
110
|
+
it 'delegates to ftp' do
|
111
|
+
src,dst = 'local_file', 'remote_file'
|
112
|
+
@ftp_gak.expects(:upload!).with(src,dst)
|
113
|
+
@ssh_gak.upload! src, dst
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#download!' do
|
118
|
+
it 'delegates to ftp' do
|
119
|
+
src,dst = 'remote_file', 'local_file'
|
120
|
+
@ftp_gak.expects(:download!).with(src,dst)
|
121
|
+
@ssh_gak.download! src, dst
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#redirect' do
|
126
|
+
it 'delegates to ftp' do
|
127
|
+
src,dst = 'remote_file', 'local_file'
|
128
|
+
put = 'output'
|
129
|
+
@ftp_gak.expects(:remove!).with(src)
|
130
|
+
@ftp_gak.expects(:download!).with(src,dst)
|
131
|
+
@ssh_gak.redirect(src,dst) do put end.should == put
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end end end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'ghaki/net_ssh/telnet'
|
2
|
+
require 'ghaki/net_ssh/common_helper'
|
3
|
+
|
4
|
+
module Ghaki module NetSSH module Telnet_Testing
|
5
|
+
describe Telnet do
|
6
|
+
include CommonHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
setup_common
|
10
|
+
end
|
11
|
+
|
12
|
+
########################################################################
|
13
|
+
context 'class' do
|
14
|
+
|
15
|
+
subject { Telnet }
|
16
|
+
|
17
|
+
describe '#start' do
|
18
|
+
|
19
|
+
it 'should yield telnet' do
|
20
|
+
@tel_raw.expects(:close).once
|
21
|
+
@ssh_raw.expects(:close).once
|
22
|
+
Telnet.start(@test_opts) do |tel|
|
23
|
+
tel.should be_an_instance_of(Telnet)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return telnet' do
|
28
|
+
@tel_raw.expects(:close).once
|
29
|
+
@ssh_raw.expects(:close).once
|
30
|
+
tel = Telnet.start(@test_opts)
|
31
|
+
tel.should be_an_instance_of(Telnet)
|
32
|
+
tel.close
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
########################################################################
|
40
|
+
context 'object' do
|
41
|
+
|
42
|
+
before(:each) do
|
43
|
+
@tel_gak = Telnet.start(@test_opts)
|
44
|
+
end
|
45
|
+
subject { @tel_gak }
|
46
|
+
|
47
|
+
context 'logging delegates' do
|
48
|
+
[ :log_command_on, :log_output_on, :log_all_on,
|
49
|
+
:log_command_off, :log_output_off, :log_all_off,
|
50
|
+
:log_exec!, :log_command!,
|
51
|
+
].each do |token|
|
52
|
+
it { should respond_to token }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#exec!' do
|
57
|
+
it 'should delegate to telnet' do
|
58
|
+
@tel_raw.expects(:cmd).with('who').returns('moo')
|
59
|
+
@tel_gak.exec!('who').should == 'moo'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end end end
|
67
|
+
############################################################################
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ghaki-net-ssh
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2011.11.30.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gerald Kalafut
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ghaki-account
|
16
|
+
requirement: &74945690 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2011.11.29.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *74945690
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ghaki-app
|
27
|
+
requirement: &74945450 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2011.11.29.1
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *74945450
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: ghaki-ext-file
|
38
|
+
requirement: &74945230 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2011.11.29.1
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *74945230
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: ghaki-logger
|
49
|
+
requirement: &74945000 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2011.11.29.1
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *74945000
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: highline
|
60
|
+
requirement: &74944780 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.6.1
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *74944780
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: net-ssh
|
71
|
+
requirement: &74944530 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 2.2.1
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *74944530
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: net-ssh-telnet
|
82
|
+
requirement: &74944270 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.0.2
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *74944270
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: net-sftp
|
93
|
+
requirement: &74944030 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 2.0.5
|
99
|
+
type: :runtime
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *74944030
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rspec
|
104
|
+
requirement: &74943800 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.6.0
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *74943800
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rdoc
|
115
|
+
requirement: &74943570 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 3.9.4
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *74943570
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: mocha
|
126
|
+
requirement: &74943320 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.9.12
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *74943320
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: ghaki-match
|
137
|
+
requirement: &74943090 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 2011.11.30.1
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *74943090
|
146
|
+
description: Ghaki Net SSH is a collection of extensions for the Net SSH gem library.
|
147
|
+
email: gerald@kalafut.org
|
148
|
+
executables: []
|
149
|
+
extensions: []
|
150
|
+
extra_rdoc_files:
|
151
|
+
- README
|
152
|
+
files:
|
153
|
+
- lib/ghaki/net_ssh/logger.rb
|
154
|
+
- lib/ghaki/net_ssh/ftp.rb
|
155
|
+
- lib/ghaki/net_ssh/account.rb
|
156
|
+
- lib/ghaki/net_ssh/telnet.rb
|
157
|
+
- lib/ghaki/net_ssh/spec_helper.rb
|
158
|
+
- lib/ghaki/net_ssh/errors.rb
|
159
|
+
- lib/ghaki/net_ssh/shell.rb
|
160
|
+
- lib/ghaki/net_ssh.rb
|
161
|
+
- README
|
162
|
+
- LICENSE
|
163
|
+
- VERSION
|
164
|
+
- spec/ghaki/net_ssh/account_spec.rb
|
165
|
+
- spec/ghaki/net_ssh/logger_spec.rb
|
166
|
+
- spec/ghaki/net_ssh/ftp_spec.rb
|
167
|
+
- spec/ghaki/net_ssh/telnet_spec.rb
|
168
|
+
- spec/ghaki/net_ssh/shell_spec.rb
|
169
|
+
- spec/spec_helper.rb
|
170
|
+
- spec/ghaki/net_ssh/common_helper.rb
|
171
|
+
homepage: http://github.com/ghaki
|
172
|
+
licenses: []
|
173
|
+
post_install_message:
|
174
|
+
rdoc_options: []
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
+
none: false
|
185
|
+
requirements:
|
186
|
+
- - ! '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: 1.3.6
|
189
|
+
requirements: []
|
190
|
+
rubyforge_project: ghaki-net-ssh
|
191
|
+
rubygems_version: 1.8.10
|
192
|
+
signing_key:
|
193
|
+
specification_version: 3
|
194
|
+
summary: Secure Shell helpers
|
195
|
+
test_files:
|
196
|
+
- spec/ghaki/net_ssh/account_spec.rb
|
197
|
+
- spec/ghaki/net_ssh/logger_spec.rb
|
198
|
+
- spec/ghaki/net_ssh/ftp_spec.rb
|
199
|
+
- spec/ghaki/net_ssh/telnet_spec.rb
|
200
|
+
- spec/ghaki/net_ssh/shell_spec.rb
|
201
|
+
- spec/spec_helper.rb
|
202
|
+
- spec/ghaki/net_ssh/common_helper.rb
|