sshkit-backends-netssh_global 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Brewfile +5 -0
- data/Gemfile +3 -0
- data/LICENSE.md +674 -0
- data/README.md +59 -0
- data/Rakefile +27 -0
- data/Vagrantfile +20 -0
- data/lib/sshkit/backends/netssh_global.rb +87 -0
- data/lib/sshkit/backends/version.rb +7 -0
- data/lib/sshkit/command_sudo_ssh_forward.rb +74 -0
- data/sshkit-backends-netssh_global.gemspec +28 -0
- data/test/boxes.json +13 -0
- data/test/functional/backends/test_netssh_global.rb +300 -0
- data/test/helper.rb +33 -0
- data/test/support/vagrant_wrapper.rb +63 -0
- data/test/unit/backends/test_netssh_global.rb +59 -0
- data/test/unit/test_command_sudo_ssh_forward.rb +239 -0
- metadata +147 -0
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# SSHKit Backends Netssh Global
|
2
|
+
|
3
|
+
**SSHKit Backends Netssh Global** is a backend to be used in conjunction with
|
4
|
+
Capistrano 3 and SSHKit to allow global configuration to be set. For example,
|
5
|
+
all commands can be run under a different user or folder - without modifying the
|
6
|
+
command.
|
7
|
+
|
8
|
+
This is designed to make it possible for Capistrano 3 to deploy on systems where
|
9
|
+
users login as one identity and then need to sudo to a different identity for
|
10
|
+
each command.
|
11
|
+
|
12
|
+
This works globally so that default tasks will automatically `sudo` and `cd`
|
13
|
+
without modification. This allows the default tasks to be used in this kind of
|
14
|
+
setup without them being altered.
|
15
|
+
|
16
|
+
If a task specifically `sudo`'s or `cd`'s then the global setting will not take
|
17
|
+
effect.
|
18
|
+
|
19
|
+
In some setups the ssh agent also needs to be forwarded (such as git clone).
|
20
|
+
Here the setting `ssh_commands` can be set to automatically forward the ssh
|
21
|
+
agent to the sudo user for certain commands.
|
22
|
+
|
23
|
+
### To run tests
|
24
|
+
|
25
|
+
To setup an OSX machine to run the tests, install Homebrew then:
|
26
|
+
|
27
|
+
```
|
28
|
+
brew tap Homebrew/bundle
|
29
|
+
brew bundle
|
30
|
+
vagrant up --provision
|
31
|
+
bundle
|
32
|
+
rake
|
33
|
+
```
|
34
|
+
|
35
|
+
### Usage
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
require 'sshkit/backends/netssh_global'
|
39
|
+
|
40
|
+
SSHKit::Backend::NetsshGlobal.configure do |config|
|
41
|
+
config.owner = 'bob' # Which user to sudo as for every command
|
42
|
+
config.directory = '/home/bob' # Can be specified if it is important to default commands to run in a
|
43
|
+
# certain directory. This can be used to overcome permission problems when
|
44
|
+
# sudo'ing
|
45
|
+
config.ssh_commands = [:git] # Setting for which commands require SSH forwarding
|
46
|
+
config.shell = 'bash -l' # Setting that allows the shell that sudo runs to be overriden
|
47
|
+
end
|
48
|
+
|
49
|
+
# Per host configuration
|
50
|
+
Host.new("example.com").tap do |h|
|
51
|
+
h.properties.owner = 'fred'
|
52
|
+
h.properties.directory = '/home/fred'
|
53
|
+
h.properties.ssh_commands = [:git, :bundle]
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
### Credits
|
58
|
+
|
59
|
+
The code and test suite are built on top of [SSHKit](http://github.com/capistrano/sshkit).
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc "Run all tests"
|
9
|
+
task :test => ['test:units', 'test:functional']
|
10
|
+
|
11
|
+
namespace :test do
|
12
|
+
|
13
|
+
Rake::TestTask.new(:units) do |t|
|
14
|
+
t.libs << "test"
|
15
|
+
t.test_files = FileList['test/unit/**/test*.rb']
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::TestTask.new(:functional) do |t|
|
19
|
+
t.libs << "test"
|
20
|
+
t.test_files = FileList['test/functional/**/test*.rb']
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::Task["test:functional"].enhance do
|
26
|
+
warn "Remember there are still some VMs running, kill them with `vagrant halt` if you are finished using them."
|
27
|
+
end
|
data/Vagrantfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
VAGRANTFILE_API_VERSION = "2"
|
2
|
+
|
3
|
+
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
4
|
+
config.vm.box = 'hashicorp/precise64'
|
5
|
+
|
6
|
+
json_config_path = File.join("test", "boxes.json")
|
7
|
+
list = File.open(json_config_path).read
|
8
|
+
list = JSON.parse(list)
|
9
|
+
|
10
|
+
list.each do |vm|
|
11
|
+
config.vm.define vm["name"] do |web|
|
12
|
+
web.vm.network "forwarded_port", guest: 22, host: vm["port"]
|
13
|
+
web.vm.provision "shell", inline: "apt-get update && apt-get install --yes acl csh"
|
14
|
+
|
15
|
+
vm["users"].each do |user|
|
16
|
+
web.vm.provision "shell", inline: "useradd --create-home #{user}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'sshkit/command_sudo_ssh_forward'
|
2
|
+
|
3
|
+
module SSHKit
|
4
|
+
module Backend
|
5
|
+
class NetsshGlobal < Netssh
|
6
|
+
class Configuration < Netssh::Configuration
|
7
|
+
attr_accessor :owner, :directory, :shell
|
8
|
+
attr_writer :ssh_commands
|
9
|
+
|
10
|
+
def ssh_commands
|
11
|
+
@ssh_commands || [:ssh, :git, :'ssh-add', :bundle]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def config
|
17
|
+
@config ||= Configuration.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
@pool = SSHKit::Backend::ConnectionPool.new
|
22
|
+
|
23
|
+
def upload!(local, remote, options = {})
|
24
|
+
execute :setfacl, "-m u:#{ssh_user}:rwx #{File.dirname(remote)}; true"
|
25
|
+
execute :setfacl, "-m u:#{ssh_user}:rw #{remote}; true"
|
26
|
+
super
|
27
|
+
as :root do
|
28
|
+
# Required as uploaded file is owned by SSH user, not owner
|
29
|
+
execute :chown, property(:owner), remote
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def user
|
36
|
+
@user || property(:owner)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ssh_user
|
40
|
+
host.user || configure_host.ssh_options.fetch(:user)
|
41
|
+
end
|
42
|
+
|
43
|
+
def pwd
|
44
|
+
@pwd.nil? ? property(:directory) : File.join(@pwd)
|
45
|
+
end
|
46
|
+
|
47
|
+
def property(name)
|
48
|
+
host.properties.public_send(name) || self.class.config.public_send(name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def with_ssh
|
52
|
+
configure_host
|
53
|
+
conn = self.class.pool.checkout(
|
54
|
+
String(host.hostname),
|
55
|
+
host.username,
|
56
|
+
host.netssh_options,
|
57
|
+
&Net::SSH.method(:start)
|
58
|
+
)
|
59
|
+
begin
|
60
|
+
yield conn.connection
|
61
|
+
ensure
|
62
|
+
self.class.pool.checkin conn
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def configure_host
|
67
|
+
host.tap do |h|
|
68
|
+
h.ssh_options = self.class.config.ssh_options.merge(host.ssh_options || {})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def command(*args)
|
73
|
+
options = args.extract_options!
|
74
|
+
options.merge!(
|
75
|
+
in: pwd,
|
76
|
+
env: @env,
|
77
|
+
host: configure_host,
|
78
|
+
user: user,
|
79
|
+
group: @group,
|
80
|
+
ssh_commands: property(:ssh_commands),
|
81
|
+
shell: property(:shell)
|
82
|
+
)
|
83
|
+
SSHKit::CommandSudoSshForward.new(*[*args, options])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SSHKit
|
2
|
+
class CommandSudoSshForward < SSHKit::Command
|
3
|
+
def to_command
|
4
|
+
return command.to_s unless should_map?
|
5
|
+
|
6
|
+
within do
|
7
|
+
ssh_agent do
|
8
|
+
umask do
|
9
|
+
with do
|
10
|
+
user do
|
11
|
+
in_background do
|
12
|
+
group do
|
13
|
+
to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def environment_hash
|
24
|
+
default_env.merge(options_env)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ssh_agent(&block)
|
28
|
+
return yield unless ssh_forwarding_required?
|
29
|
+
"setfacl -m #{options[:user]}:x $(dirname $SSH_AUTH_SOCK) && setfacl -m #{options[:user]}:rw $SSH_AUTH_SOCK && %s" % yield
|
30
|
+
end
|
31
|
+
|
32
|
+
def user(&block)
|
33
|
+
return yield unless options[:user]
|
34
|
+
shell = options[:shell] || 'sh'
|
35
|
+
"sudo -u #{options[:user]} #{environment_string + " " unless environment_string.empty?}-- #{shell} -c '%s'" % %Q{#{yield}}
|
36
|
+
end
|
37
|
+
|
38
|
+
def with(&block)
|
39
|
+
return yield if environment_hash.empty? || sudo_command?
|
40
|
+
"( #{environment_string} %s )" % yield
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def options_env
|
46
|
+
(options[:env] || {}).merge(default_ssh_options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_env
|
50
|
+
SSHKit.config.default_env || {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def default_ssh_options
|
54
|
+
ssh_forwarding_required? ? {'SSH_AUTH_SOCK' => '$SSH_AUTH_SOCK'} : {}
|
55
|
+
end
|
56
|
+
|
57
|
+
def ssh_forwarding_required?
|
58
|
+
ssh_command? && sudo_command? && ssh_forwarding_enabled?
|
59
|
+
end
|
60
|
+
|
61
|
+
def ssh_command?
|
62
|
+
options.fetch(:ssh_commands, []).include?(command)
|
63
|
+
end
|
64
|
+
|
65
|
+
def ssh_forwarding_enabled?
|
66
|
+
options[:host] && options[:host].ssh_options[:forward_agent]
|
67
|
+
end
|
68
|
+
|
69
|
+
def sudo_command?
|
70
|
+
options[:user]
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sshkit/backends/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
|
6
|
+
gem.authors = ["Theo Cushion", "Dennis Ideler"]
|
7
|
+
gem.email = ["tcushion@pivotal.io", "dennis.ideler@fundingcircle.com"]
|
8
|
+
gem.summary = %q{SSHKit backend for globally sudoing commands}
|
9
|
+
gem.description = %q{A backend to be used in conjunction with Capistrano 3
|
10
|
+
and SSHKit to allow deployment on setups where users login as one identity and
|
11
|
+
then need to sudo to a different identity for each command.}
|
12
|
+
gem.homepage = "http://github.com/fundingcircle/sshkit-backends-netssh_global"
|
13
|
+
# gem.license = "GPL3"
|
14
|
+
|
15
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
gem.files = `git ls-files`.split("\n")
|
17
|
+
gem.test_files = `git ls-files -- test/*`.split("\n")
|
18
|
+
gem.name = "sshkit-backends-netssh_global"
|
19
|
+
gem.require_paths = ["lib"]
|
20
|
+
gem.version = SSHKit::Backends::NetsshGlobal::VERSION
|
21
|
+
|
22
|
+
gem.add_runtime_dependency('sshkit', '1.7.1')
|
23
|
+
|
24
|
+
gem.add_development_dependency('minitest', ['>= 2.11.3', '< 2.12.0'])
|
25
|
+
gem.add_development_dependency('rake')
|
26
|
+
gem.add_development_dependency('turn')
|
27
|
+
gem.add_development_dependency('mocha')
|
28
|
+
end
|
data/test/boxes.json
ADDED
@@ -0,0 +1,300 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
require 'sshkit/backends/netssh_global'
|
5
|
+
|
6
|
+
module SSHKit
|
7
|
+
module Backend
|
8
|
+
class TestNetsshGlobalFunctional < FunctionalTest
|
9
|
+
def setup
|
10
|
+
super
|
11
|
+
NetsshGlobal.configure do |config|
|
12
|
+
config.owner = a_user
|
13
|
+
config.directory = nil
|
14
|
+
config.shell = nil
|
15
|
+
end
|
16
|
+
VagrantWrapper.reset!
|
17
|
+
end
|
18
|
+
|
19
|
+
def a_user
|
20
|
+
a_box.fetch('users').fetch(0)
|
21
|
+
end
|
22
|
+
|
23
|
+
def another_user
|
24
|
+
a_box.fetch('users').fetch(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
def a_box
|
28
|
+
VagrantWrapper.boxes_list.first
|
29
|
+
end
|
30
|
+
|
31
|
+
def a_host
|
32
|
+
VagrantWrapper.hosts['one']
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_capture
|
36
|
+
File.open('/dev/null', 'w') do |dnull|
|
37
|
+
SSHKit.capture_output(dnull) do
|
38
|
+
captured_command_result = nil
|
39
|
+
NetsshGlobal.new(a_host) do
|
40
|
+
captured_command_result = capture(:uname)
|
41
|
+
end.run
|
42
|
+
|
43
|
+
assert captured_command_result
|
44
|
+
assert_match captured_command_result, /Linux|Darwin/
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_ssh_option_merge
|
50
|
+
a_host.ssh_options = { paranoid: true }
|
51
|
+
host_ssh_options = {}
|
52
|
+
SSHKit::Backend::NetsshGlobal.config.ssh_options = { forward_agent: false }
|
53
|
+
NetsshGlobal.new(a_host) do |host|
|
54
|
+
capture(:uname)
|
55
|
+
host_ssh_options = host.ssh_options
|
56
|
+
end.run
|
57
|
+
assert_equal({ forward_agent: false, paranoid: true }, host_ssh_options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_configure_owner_via_global_config
|
61
|
+
NetsshGlobal.configure do |config|
|
62
|
+
config.owner = a_user
|
63
|
+
end
|
64
|
+
|
65
|
+
output = ''
|
66
|
+
NetsshGlobal.new(a_host) do
|
67
|
+
output = capture :whoami
|
68
|
+
end.run
|
69
|
+
assert_equal a_user, output
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_configure_owner_via_host
|
73
|
+
a_host.properties.owner = another_user
|
74
|
+
|
75
|
+
output = ''
|
76
|
+
NetsshGlobal.new(a_host) do
|
77
|
+
output = capture :whoami
|
78
|
+
end.run
|
79
|
+
assert_equal another_user, output
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_configure_shell_via_global_config
|
83
|
+
NetsshGlobal.configure do |config|
|
84
|
+
config.shell = "csh"
|
85
|
+
end
|
86
|
+
|
87
|
+
running_shell = ''
|
88
|
+
NetsshGlobal.new(a_host) do
|
89
|
+
running_shell = capture :echo, '$shell'
|
90
|
+
end.run
|
91
|
+
|
92
|
+
assert_equal '/bin/csh', running_shell
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_configure_directory_to_nil_has_no_effect
|
96
|
+
NetsshGlobal.configure do |config|
|
97
|
+
config.directory = nil
|
98
|
+
end
|
99
|
+
|
100
|
+
output = ''
|
101
|
+
NetsshGlobal.new(a_host) do
|
102
|
+
output = capture :pwd
|
103
|
+
end.run
|
104
|
+
assert_equal "/home/#{a_host.user}", output
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_configure_directory_via_global_config
|
108
|
+
NetsshGlobal.configure do |config|
|
109
|
+
config.directory = '/tmp'
|
110
|
+
end
|
111
|
+
|
112
|
+
output = ''
|
113
|
+
NetsshGlobal.new(a_host) do
|
114
|
+
output = capture :pwd
|
115
|
+
end.run
|
116
|
+
assert_equal '/tmp', output
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_configure_directory_via_host
|
120
|
+
NetsshGlobal.configure do |config|
|
121
|
+
config.directory = '/usr'
|
122
|
+
end
|
123
|
+
|
124
|
+
a_host.properties.directory = '/tmp'
|
125
|
+
output = ''
|
126
|
+
NetsshGlobal.new(a_host) do
|
127
|
+
output = capture :pwd
|
128
|
+
end.run
|
129
|
+
assert_equal '/tmp', output
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_execute_raises_on_non_zero_exit_status_and_captures_stdout_and_stderr
|
133
|
+
err = assert_raises SSHKit::Command::Failed do
|
134
|
+
NetsshGlobal.new(a_host) do
|
135
|
+
execute :echo, "\"Test capturing stderr\" 1>&2; false"
|
136
|
+
end.run
|
137
|
+
end
|
138
|
+
assert_equal "echo exit status: 1\necho stdout: Nothing written\necho stderr: Test capturing stderr\n", err.message
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_test_does_not_raise_on_non_zero_exit_status
|
142
|
+
NetsshGlobal.new(a_host) do
|
143
|
+
test :false
|
144
|
+
end.run
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_test_executes_as_owner_when_command_contains_no_spaces
|
148
|
+
result = NetsshGlobal.new(a_host) do
|
149
|
+
test 'test', '"$USER" = "owner"'
|
150
|
+
end.run
|
151
|
+
|
152
|
+
assert(result, 'Expected test to execute as "owner", but it did not')
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_test_executes_as_ssh_user_when_command_contains_spaces
|
156
|
+
result = NetsshGlobal.new(a_host) do
|
157
|
+
test 'test "$USER" = "vagrant"'
|
158
|
+
end.run
|
159
|
+
|
160
|
+
assert(result, 'Expected test to execute as "vagrant", but it did not')
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_upload_file
|
164
|
+
file_contents = ""
|
165
|
+
file_owner = nil
|
166
|
+
file_name = File.join("/tmp", SecureRandom.uuid)
|
167
|
+
File.open file_name, 'w+' do |f|
|
168
|
+
f.write 'example_file'
|
169
|
+
end
|
170
|
+
|
171
|
+
NetsshGlobal.new(a_host) do
|
172
|
+
upload!(file_name, file_name)
|
173
|
+
file_contents = capture(:cat, file_name)
|
174
|
+
file_owner = capture(:stat, '-c', '%U', file_name)
|
175
|
+
end.run
|
176
|
+
|
177
|
+
assert_equal 'example_file', file_contents
|
178
|
+
assert_equal a_user, file_owner
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_upload_file_to_folder_owned_by_user
|
182
|
+
dir = File.join('/tmp', SecureRandom.uuid)
|
183
|
+
NetsshGlobal.new(a_host) do
|
184
|
+
execute(:mkdir, dir)
|
185
|
+
end.run
|
186
|
+
|
187
|
+
file_name = SecureRandom.uuid
|
188
|
+
local_file = File.join('/tmp', file_name)
|
189
|
+
File.open local_file, 'w+' do |f|
|
190
|
+
f.write 'example_file'
|
191
|
+
end
|
192
|
+
|
193
|
+
file_contents = ""
|
194
|
+
file_owner = nil
|
195
|
+
remote_file = File.join(dir, file_name)
|
196
|
+
NetsshGlobal.new(a_host) do
|
197
|
+
upload!(local_file, remote_file)
|
198
|
+
file_contents = capture(:cat, remote_file)
|
199
|
+
file_owner = capture(:stat, '-c', '%U', remote_file)
|
200
|
+
end.run
|
201
|
+
|
202
|
+
assert_equal 'example_file', file_contents
|
203
|
+
assert_equal a_user, file_owner
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_upload_file_overtop_of_existing_file
|
207
|
+
file_name = File.join('/tmp', SecureRandom.uuid)
|
208
|
+
File.open file_name, 'w+' do |f|
|
209
|
+
f.write 'example_file'
|
210
|
+
end
|
211
|
+
|
212
|
+
NetsshGlobal.new(a_host) do
|
213
|
+
upload!(file_name, file_name)
|
214
|
+
end.run
|
215
|
+
|
216
|
+
file_contents = ""
|
217
|
+
file_owner = nil
|
218
|
+
NetsshGlobal.new(a_host) do
|
219
|
+
upload!(file_name, file_name)
|
220
|
+
file_contents = capture(:cat, file_name)
|
221
|
+
file_owner = capture(:stat, '-c', '%U', file_name)
|
222
|
+
end.run
|
223
|
+
|
224
|
+
assert_equal 'example_file', file_contents
|
225
|
+
assert_equal a_user, file_owner
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_upload_string_io
|
229
|
+
file_contents = ""
|
230
|
+
file_owner = nil
|
231
|
+
NetsshGlobal.new(a_host) do
|
232
|
+
file_name = File.join("/tmp", SecureRandom.uuid)
|
233
|
+
upload!(StringIO.new('example_io'), file_name)
|
234
|
+
file_contents = download!(file_name)
|
235
|
+
file_owner = capture(:stat, '-c', '%U', file_name)
|
236
|
+
end.run
|
237
|
+
assert_equal "example_io", file_contents
|
238
|
+
assert_equal a_user, file_owner
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_upload_large_file
|
242
|
+
size = 25
|
243
|
+
fills = SecureRandom.random_bytes(1024*1024)
|
244
|
+
file_name = "/tmp/file-#{SecureRandom.uuid}-#{size}.txt"
|
245
|
+
File.open(file_name, 'w') do |f|
|
246
|
+
(size).times {f.write(fills) }
|
247
|
+
end
|
248
|
+
|
249
|
+
file_contents = ""
|
250
|
+
NetsshGlobal.new(a_host) do
|
251
|
+
upload!(file_name, file_name)
|
252
|
+
file_contents = download!(file_name)
|
253
|
+
end.run
|
254
|
+
|
255
|
+
assert_equal File.open(file_name).read, file_contents
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_ssh_forwarded_when_command_is_ssh_command
|
259
|
+
remote_ssh_output = ''
|
260
|
+
local_ssh_output = `ssh-add -l 2>&1`.strip
|
261
|
+
a_host.ssh_options = { forward_agent: true }
|
262
|
+
NetsshGlobal.new(a_host) do |host|
|
263
|
+
remote_ssh_output = capture 'ssh-add', '-l', '2>&1;', 'true'
|
264
|
+
end.run
|
265
|
+
|
266
|
+
assert_equal local_ssh_output, remote_ssh_output
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_ssh_not_forwarded_when_command_is_not_an_ssh_command
|
270
|
+
echo_output = ''
|
271
|
+
|
272
|
+
a_host.ssh_options = { forward_agent: true }
|
273
|
+
a_host.properties.ssh_commands = [:not_echo]
|
274
|
+
NetsshGlobal.new(a_host) do |host|
|
275
|
+
echo_output = capture :echo, '$SSH_AUTH_SOCK'
|
276
|
+
end.run
|
277
|
+
|
278
|
+
assert_match '', echo_output
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_can_configure_ssh_commands
|
282
|
+
echo_output = ''
|
283
|
+
|
284
|
+
a_host.ssh_options = { forward_agent: true }
|
285
|
+
a_host.properties.ssh_commands = [:echo]
|
286
|
+
NetsshGlobal.new(a_host) do |host|
|
287
|
+
echo_output = capture :echo, '$SSH_AUTH_SOCK'
|
288
|
+
end.run
|
289
|
+
|
290
|
+
assert_match /\/tmp\//, echo_output
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_default_ssh_commands
|
294
|
+
ssh_commands = NetsshGlobal.config.ssh_commands
|
295
|
+
|
296
|
+
assert_equal [:ssh, :git, :'ssh-add', :bundle], ssh_commands
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|