specinfra 2.25.1 → 2.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/specinfra/backend/base.rb +31 -29
- data/lib/specinfra/backend/docker.rb +87 -85
- data/lib/specinfra/backend/dockerfile.rb +25 -24
- data/lib/specinfra/backend/exec.rb +58 -56
- data/lib/specinfra/backend/lxc.rb +34 -32
- data/lib/specinfra/backend/shell_script.rb +19 -17
- data/lib/specinfra/backend/ssh.rb +131 -129
- data/lib/specinfra/backend/telnet.rb +87 -85
- data/lib/specinfra/backend/winrm.rb +19 -17
- data/lib/specinfra/command/module/systemd.rb +44 -37
- data/lib/specinfra/command/module/zfs.rb +21 -14
- data/lib/specinfra/command/module.rb +6 -1
- data/lib/specinfra/command.rb +4 -1
- data/lib/specinfra/core.rb +18 -0
- data/lib/specinfra/ext/class.rb +9 -0
- data/lib/specinfra/ext/string.rb +14 -0
- data/lib/specinfra/ext.rb +2 -0
- data/lib/specinfra/helper/detect_os.rb +15 -13
- data/lib/specinfra/helper/os.rb +21 -16
- data/lib/specinfra/helper/set.rb +8 -3
- data/lib/specinfra/version.rb +1 -1
- data/lib/specinfra.rb +1 -38
- metadata +6 -2
@@ -3,171 +3,173 @@ require 'specinfra/backend/exec'
|
|
3
3
|
require 'net/ssh'
|
4
4
|
require 'net/scp'
|
5
5
|
|
6
|
-
module Specinfra
|
7
|
-
|
8
|
-
|
9
|
-
cmd =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
module Specinfra
|
7
|
+
module Backend
|
8
|
+
class Ssh < Exec
|
9
|
+
def run_command(cmd, opt={})
|
10
|
+
cmd = build_command(cmd)
|
11
|
+
cmd = add_pre_command(cmd)
|
12
|
+
ret = with_env do
|
13
|
+
ssh_exec!(cmd)
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
ret[:stdout].gsub!(/\r\n/, "\n")
|
17
|
+
ret[:stdout].gsub!(/\A\n/, "") if sudo?
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
if @example
|
20
|
+
@example.metadata[:command] = cmd
|
21
|
+
@example.metadata[:stdout] = ret[:stdout]
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
CommandResult.new ret
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
def send_file(from, to)
|
28
|
+
scp_upload!(from, to)
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def send_directory(from, to)
|
32
|
+
scp_upload!(from, to, :recursive => true)
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
def build_command(cmd)
|
36
|
+
cmd = super(cmd)
|
37
|
+
if sudo?
|
38
|
+
cmd = "#{sudo} -p '#{prompt}' #{cmd}"
|
39
|
+
end
|
40
|
+
cmd
|
38
41
|
end
|
39
|
-
cmd
|
40
|
-
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
private
|
44
|
+
def prompt
|
45
|
+
'Password: '
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def with_env
|
49
|
+
env = get_config(:env) || {}
|
50
|
+
env[:LANG] ||= 'C'
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
ssh_options = get_config(:ssh_options) || {}
|
53
|
+
ssh_options[:send_env] ||= []
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
env.each do |key, value|
|
56
|
+
key = key.to_s
|
57
|
+
ENV["_SPECINFRA_#{key}"] = ENV[key];
|
58
|
+
ENV[key] = value
|
59
|
+
ssh_options[:send_env] << key
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
yield
|
63
|
+
ensure
|
64
|
+
env.each do |key, value|
|
65
|
+
key = key.to_s
|
66
|
+
ENV[key] = ENV.delete("_SPECINFRA_#{key}");
|
67
|
+
end
|
66
68
|
end
|
67
|
-
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
def create_scp
|
78
|
-
ssh = get_config(:ssh)
|
79
|
-
if ssh.nil?
|
80
|
-
ssh = create_ssh
|
70
|
+
def create_ssh
|
71
|
+
Net::SSH.start(
|
72
|
+
get_config(:host),
|
73
|
+
get_config(:ssh_options)[:user],
|
74
|
+
get_config(:ssh_options)
|
75
|
+
)
|
81
76
|
end
|
82
|
-
Net::SCP.new(ssh)
|
83
|
-
end
|
84
77
|
|
85
|
-
|
86
|
-
|
87
|
-
|
78
|
+
def create_scp
|
79
|
+
ssh = get_config(:ssh)
|
80
|
+
if ssh.nil?
|
81
|
+
ssh = create_ssh
|
82
|
+
end
|
83
|
+
Net::SCP.new(ssh)
|
88
84
|
end
|
89
85
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
95
|
-
|
96
|
-
def ssh_exec!(command)
|
97
|
-
stdout_data = ''
|
98
|
-
stderr_data = ''
|
99
|
-
exit_status = nil
|
100
|
-
exit_signal = nil
|
101
|
-
retry_prompt = /^Sorry, try again/
|
86
|
+
def scp_upload!(from, to, opt={})
|
87
|
+
if get_config(:scp).nil?
|
88
|
+
set_config(:scp, create_scp)
|
89
|
+
end
|
102
90
|
|
103
|
-
|
104
|
-
|
91
|
+
tmp = File.join('/tmp', File.basename(to))
|
92
|
+
scp = get_config(:scp)
|
93
|
+
scp.upload!(from, tmp, opt)
|
94
|
+
run_command(command.get(:move_file, tmp, to))
|
105
95
|
end
|
106
96
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
97
|
+
def ssh_exec!(command)
|
98
|
+
stdout_data = ''
|
99
|
+
stderr_data = ''
|
100
|
+
exit_status = nil
|
101
|
+
exit_signal = nil
|
102
|
+
retry_prompt = /^Sorry, try again/
|
103
|
+
|
104
|
+
if get_config(:ssh).nil?
|
105
|
+
set_config(:ssh, create_ssh)
|
113
106
|
end
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
channel.send_data "#{get_config(:sudo_password)}\n"
|
121
|
-
else
|
122
|
-
stdout_data += data
|
107
|
+
|
108
|
+
ssh = get_config(:ssh)
|
109
|
+
ssh.open_channel do |channel|
|
110
|
+
if get_config(:sudo_password) or get_config(:request_pty)
|
111
|
+
channel.request_pty do |ch, success|
|
112
|
+
abort "Could not obtain pty " if !success
|
123
113
|
end
|
124
114
|
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
115
|
+
channel.exec("#{command}") do |ch, success|
|
116
|
+
abort "FAILED: couldn't execute command (ssh.channel.exec)" if !success
|
117
|
+
channel.on_data do |ch, data|
|
118
|
+
if data.match retry_prompt
|
119
|
+
abort 'Wrong sudo password! Please confirm your password.'
|
120
|
+
elsif data.match /^#{prompt}/
|
121
|
+
channel.send_data "#{get_config(:sudo_password)}\n"
|
122
|
+
else
|
123
|
+
stdout_data += data
|
124
|
+
end
|
129
125
|
end
|
130
126
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
127
|
+
channel.on_extended_data do |ch, type, data|
|
128
|
+
if data.match /you must have a tty to run sudo/
|
129
|
+
abort 'Please write "set :request_pty, true" in your spec_helper.rb or other appropriate file.'
|
130
|
+
end
|
131
|
+
|
132
|
+
if data.match /^sudo: no tty present and no askpass program specified/
|
133
|
+
abort 'Please set sudo password to Specinfra.configuration.sudo_password.'
|
134
|
+
else
|
135
|
+
stderr_data += data
|
136
|
+
end
|
135
137
|
end
|
136
|
-
end
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
|
139
|
+
channel.on_request("exit-status") do |ch, data|
|
140
|
+
exit_status = data.read_long
|
141
|
+
end
|
141
142
|
|
142
|
-
|
143
|
-
|
143
|
+
channel.on_request("exit-signal") do |ch, data|
|
144
|
+
exit_signal = data.read_long
|
145
|
+
end
|
144
146
|
end
|
145
147
|
end
|
148
|
+
ssh.loop
|
149
|
+
{ :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal }
|
146
150
|
end
|
147
|
-
ssh.loop
|
148
|
-
{ :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal }
|
149
|
-
end
|
150
151
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
152
|
+
def sudo
|
153
|
+
if sudo_path = get_config(:sudo_path)
|
154
|
+
sudo_path += '/sudo'
|
155
|
+
else
|
156
|
+
sudo_path = 'sudo'
|
157
|
+
end
|
157
158
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
sudo_options = get_config(:sudo_options)
|
160
|
+
if sudo_options
|
161
|
+
sudo_options = sudo_options.shelljoin if sudo_options.is_a?(Array)
|
162
|
+
sudo_options = ' ' + sudo_options
|
163
|
+
end
|
163
164
|
|
164
|
-
|
165
|
-
|
165
|
+
"#{sudo_path.shellescape}#{sudo_options}"
|
166
|
+
end
|
166
167
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
168
|
+
def sudo?
|
169
|
+
user = get_config(:ssh_options)[:user]
|
170
|
+
disable_sudo = get_config(:disable_sudo)
|
171
|
+
user != 'root' && !disable_sudo
|
172
|
+
end
|
171
173
|
end
|
172
174
|
end
|
173
175
|
end
|
@@ -2,108 +2,110 @@
|
|
2
2
|
require 'specinfra/backend/exec'
|
3
3
|
require 'net/telnet'
|
4
4
|
|
5
|
-
module Specinfra
|
6
|
-
|
7
|
-
|
8
|
-
cmd =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@example
|
15
|
-
|
16
|
-
|
5
|
+
module Specinfra
|
6
|
+
module Backend
|
7
|
+
class Telnet < Exec
|
8
|
+
def run_command(cmd, opt={})
|
9
|
+
cmd = build_command(cmd)
|
10
|
+
cmd = add_pre_command(cmd)
|
11
|
+
ret = with_env do
|
12
|
+
telnet_exec!(cmd)
|
13
|
+
end
|
14
|
+
if @example
|
15
|
+
@example.metadata[:command] = cmd
|
16
|
+
@example.metadata[:stdout] = ret[:stdout]
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
CommandResult.new ret
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
def build_command(cmd)
|
23
|
+
cmd = super(cmd)
|
24
|
+
cmd
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
private
|
28
|
+
def prompt
|
29
|
+
'Login: '
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
def with_env
|
33
|
+
env = get_config(:env) || {}
|
34
|
+
env[:LANG] ||= 'C'
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
env.each do |key, value|
|
37
|
+
key = key.to_s
|
38
|
+
ENV["_SPECINFRA_#{key}"] = ENV[key];
|
39
|
+
ENV[key] = value
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
yield
|
43
|
+
ensure
|
44
|
+
env.each do |key, value|
|
45
|
+
key = key.to_s
|
46
|
+
ENV[key] = ENV.delete("_SPECINFRA_#{key}");
|
47
|
+
end
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
def add_pre_command(cmd)
|
51
|
+
if get_config(:pre_command)
|
52
|
+
pre_cmd = build_command(get_config(:pre_command))
|
53
|
+
"#{pre_cmd} && #{cmd}"
|
54
|
+
else
|
55
|
+
cmd
|
56
|
+
end
|
55
57
|
end
|
56
|
-
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
def telnet_exec!( command )
|
60
|
+
stdout_data = ''
|
61
|
+
stderr_data = ''
|
62
|
+
exit_status = nil
|
63
|
+
exit_signal = nil
|
64
|
+
retry_prompt = /^Login: /
|
65
|
+
if get_config(:telnet).nil?
|
66
|
+
set_config(:telnet, create_telnet)
|
67
|
+
end
|
68
|
+
telnet = get_config(:telnet)
|
69
|
+
re = []
|
70
|
+
unless telnet.nil?
|
71
|
+
re = telnet.cmd( "#{command}; echo $?" ).split("\n")[0..-2]
|
72
|
+
exit_status = re.last.to_i
|
73
|
+
stdout_data = re[1..-2].join("\n")
|
74
|
+
end
|
75
|
+
{ :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal }
|
66
76
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
77
|
+
|
78
|
+
def create_telnet
|
79
|
+
tel = Net::Telnet.new( "Host" => get_config(:host) )
|
80
|
+
tel.login(
|
81
|
+
"Name" => get_config(:telnet_options)[:user],
|
82
|
+
"Password" => get_config(:telnet_options)[:pass]
|
83
|
+
)
|
84
|
+
tel
|
85
|
+
rescue
|
86
|
+
return nil
|
73
87
|
end
|
74
|
-
{ :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal }
|
75
|
-
end
|
76
|
-
|
77
|
-
def create_telnet
|
78
|
-
tel = Net::Telnet.new( "Host" => get_config(:host) )
|
79
|
-
tel.login(
|
80
|
-
"Name" => get_config(:telnet_options)[:user],
|
81
|
-
"Password" => get_config(:telnet_options)[:pass]
|
82
|
-
)
|
83
|
-
tel
|
84
|
-
rescue
|
85
|
-
return nil
|
86
|
-
end
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
89
|
+
def sudo
|
90
|
+
if sudo_path = get_config(:sudo_path)
|
91
|
+
sudo_path += '/sudo'
|
92
|
+
else
|
93
|
+
sudo_path = 'sudo'
|
94
|
+
end
|
95
|
+
|
96
|
+
sudo_options = get_config(:sudo_options)
|
97
|
+
if sudo_options
|
98
|
+
sudo_options = sudo_options.shelljoin if sudo_options.is_a?(Array)
|
99
|
+
sudo_options = ' ' + sudo_options
|
100
|
+
end
|
94
101
|
|
95
|
-
|
96
|
-
if sudo_options
|
97
|
-
sudo_options = sudo_options.shelljoin if sudo_options.is_a?(Array)
|
98
|
-
sudo_options = ' ' + sudo_options
|
102
|
+
"#{sudo_path.shellescape}#{sudo_options}"
|
99
103
|
end
|
100
104
|
|
101
|
-
|
102
|
-
|
105
|
+
def sudo?
|
106
|
+
false
|
107
|
+
end
|
103
108
|
|
104
|
-
def sudo?
|
105
|
-
false
|
106
109
|
end
|
107
|
-
|
108
110
|
end
|
109
111
|
end
|
@@ -1,24 +1,26 @@
|
|
1
|
-
module Specinfra
|
2
|
-
|
3
|
-
|
1
|
+
module Specinfra
|
2
|
+
module Backend
|
3
|
+
class Winrm < Base
|
4
|
+
include PowerShell::ScriptHelper
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def run_command(cmd, opts={})
|
7
|
+
set_config(:os, {:family => 'windows'})
|
8
|
+
script = create_script(cmd)
|
9
|
+
winrm = get_config(:winrm)
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
result = winrm.powershell(script)
|
12
|
+
stdout, stderr = [:stdout, :stderr].map do |s|
|
13
|
+
result[:data].select {|item| item.key? s}.map {|item| item[s]}.join
|
14
|
+
end
|
15
|
+
result[:exitcode] = 1 if result[:exitcode] == 0 and !stderr.empty?
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
if @example
|
18
|
+
@example.metadata[:command] = script
|
19
|
+
@example.metadata[:stdout] = stdout + stderr
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
+
CommandResult.new :stdout => stdout, :stderr => stderr, :exit_status => result[:exitcode]
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -1,40 +1,47 @@
|
|
1
|
-
module Specinfra
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Specinfra
|
2
|
+
module Command
|
3
|
+
module Module
|
4
|
+
module Systemd
|
5
|
+
def check_is_enabled(service, level="multi-user.target")
|
6
|
+
if level.to_s =~ /^\d+$/
|
7
|
+
level = "runlevel#{level}.target"
|
8
|
+
end
|
9
|
+
unless service.include?('.')
|
10
|
+
service += '.service'
|
11
|
+
end
|
12
|
+
|
13
|
+
"systemctl --plain list-dependencies #{level} | grep '\\(^\\| \\)#{escape(service)}$'"
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_is_running(service)
|
17
|
+
"systemctl is-active #{escape(service)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def enable(service)
|
21
|
+
"systemctl enable #{escape(service)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def disable(service)
|
25
|
+
"systemctl disable #{escape(service)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def start(service)
|
29
|
+
"systemctl start #{escape(service)}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop(service)
|
33
|
+
"systemctl stop #{escape(service)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def restart(service)
|
37
|
+
"systemctl restart #{escape(service)}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def reload(service)
|
41
|
+
"systemctl reload #{escape(service)}"
|
42
|
+
end
|
43
|
+
end
|
5
44
|
end
|
6
|
-
unless service.include?('.')
|
7
|
-
service += '.service'
|
8
|
-
end
|
9
|
-
|
10
|
-
"systemctl --plain list-dependencies #{level} | grep '\\(^\\| \\)#{escape(service)}$'"
|
11
|
-
end
|
12
|
-
|
13
|
-
def check_is_running(service)
|
14
|
-
"systemctl is-active #{escape(service)}"
|
15
|
-
end
|
16
|
-
|
17
|
-
def enable(service)
|
18
|
-
"systemctl enable #{escape(service)}"
|
19
|
-
end
|
20
|
-
|
21
|
-
def disable(service)
|
22
|
-
"systemctl disable #{escape(service)}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def start(service)
|
26
|
-
"systemctl start #{escape(service)}"
|
27
|
-
end
|
28
|
-
|
29
|
-
def stop(service)
|
30
|
-
"systemctl stop #{escape(service)}"
|
31
|
-
end
|
32
|
-
|
33
|
-
def restart(service)
|
34
|
-
"systemctl restart #{escape(service)}"
|
35
|
-
end
|
36
|
-
|
37
|
-
def reload(service)
|
38
|
-
"systemctl reload #{escape(service)}"
|
39
45
|
end
|
40
46
|
end
|
47
|
+
|
@@ -1,18 +1,25 @@
|
|
1
|
-
module Specinfra
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Specinfra
|
2
|
+
module Command
|
3
|
+
module Module
|
4
|
+
module Zfs
|
5
|
+
def check_exists(zfs)
|
6
|
+
"zfs list -H #{escape(zfs)}"
|
7
|
+
end
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
def check_has_property(zfs, property=nil)
|
10
|
+
commands = []
|
11
|
+
property.sort.each do |key, value|
|
12
|
+
regexp = "^#{value}$"
|
13
|
+
commands << "zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}"
|
14
|
+
end
|
15
|
+
commands.join(' && ')
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
def get_property(zfs)
|
19
|
+
"zfs get -Hp -o property,value all #{escape(zfs)}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
17
23
|
end
|
18
24
|
end
|
25
|
+
|