serverspec 0.10.6 → 0.10.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{WindowsSupport.md → WINDOWS_SUPPORT.md} +11 -2
- data/lib/serverspec/backend/cmd.rb +3 -4
- data/lib/serverspec/backend/powershell/command.rb +4 -0
- data/lib/serverspec/backend/powershell/script_helper.rb +20 -4
- data/lib/serverspec/backend/powershell/support/check_file_access_rules.ps1 +3 -7
- data/lib/serverspec/backend/powershell/support/is_port_listening.ps1 +1 -1
- data/lib/serverspec/commands/windows.rb +3 -1
- data/lib/serverspec/version.rb +1 -1
- data/spec/backend/powershell/script_helper_spec.rb +27 -0
- data/spec/spec_helper.rb +1 -4
- data/spec/windows/command_spec.rb +71 -0
- data/spec/windows/service_spec.rb +9 -0
- data/spec/windows/windows_registry_key_spec.rb +68 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05c1dc06b5b4833b7e537d596b488b3bb07aba0e
|
4
|
+
data.tar.gz: c8fa93b1eab1507daa911da2a1e1b55c20dcac9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eeab306443ccc7261c6dacf25553d98481fed15453e650c55f79c574223485a02dab66ac73751b8ca7468275defb4fbf5de8d66dbc763b941023c26f4a00c5e4
|
7
|
+
data.tar.gz: 7c53f323cfcee38681c359ce7bdbef51b0e85089cec4dda10537a11aebf1af200ec93f1ca8a88a4d26e7a1084f5533b8483f57d44eba993737ccadf66ee2ba60
|
@@ -33,7 +33,7 @@ RSpec.configure do |c|
|
|
33
33
|
end
|
34
34
|
```
|
35
35
|
|
36
|
-
For different authentication mechanisms check the Microsoft WinRM documentation and verify the ones that are supported by [WinRb/WinRM](https://github.com/WinRb/WinRM)
|
36
|
+
For how to configure the guest to accept WinRM connections and the different authentication mechanisms check the Microsoft WinRM documentation and verify the ones that are supported by [WinRb/WinRM](https://github.com/WinRb/WinRM).
|
37
37
|
|
38
38
|
|
39
39
|
###RSpec Examples for windows target hosts
|
@@ -75,6 +75,10 @@ describe group('MYDOMAIN\Domain Users') do
|
|
75
75
|
it { should exist }
|
76
76
|
end
|
77
77
|
|
78
|
+
describe command('& "ipconfig"') do
|
79
|
+
it { should return_stdout(/IPv4 Address(\.| )*: 192\.168\.1\.100/) }
|
80
|
+
end
|
81
|
+
|
78
82
|
describe windows_registry_key('HKEY_USERS\S-1-5-21-1319311448-2088773778-316617838-32407\Test MyKey') do
|
79
83
|
it { should exist }
|
80
84
|
it { should have_property('string value') }
|
@@ -85,4 +89,9 @@ describe windows_registry_key('HKEY_USERS\S-1-5-21-1319311448-2088773778-3166178
|
|
85
89
|
it { should have_property_value('qword value', :type_qword, 'adff32') }
|
86
90
|
it { should have_property_value('binary value', :type_binary, 'dfa0f066') }
|
87
91
|
end
|
88
|
-
```
|
92
|
+
```
|
93
|
+
|
94
|
+
###Notes:
|
95
|
+
* Not all the matchers you are used to in Linux-like OS are supported in Windows, some because of differences between the operating systems (e.g. users and permissions model), some because they haven't been yet implemented.
|
96
|
+
* All commands in the windows backend are run via powershell, so the output in case of stderr is a pretty ugly xml-like thing. Still it should contain some information to help troubleshooting.
|
97
|
+
* The *command* type is executed again through powershell, so bear that in mind if you mean to run old CMD windows batch or programs. (i.e run the command using the **Invoke-Expression** Cmdlet, or the **&** Call Operator)
|
@@ -7,7 +7,7 @@ module Serverspec
|
|
7
7
|
|
8
8
|
def run_command(cmd, opts={})
|
9
9
|
script = create_script(cmd)
|
10
|
-
result = execute_script script
|
10
|
+
result = execute_script %Q{powershell -encodedCommand #{encode_script(script)}}
|
11
11
|
|
12
12
|
if @example
|
13
13
|
@example.metadata[:command] = script
|
@@ -18,15 +18,14 @@ module Serverspec
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def execute_script script
|
21
|
-
ps_script = %Q{powershell -encodedCommand #{encode_script(script)}}
|
22
21
|
if Open3.respond_to? :capture3
|
23
|
-
stdout, stderr, status = Open3.capture3(
|
22
|
+
stdout, stderr, status = Open3.capture3(script)
|
24
23
|
# powershell still exits with 0 even if there are syntax errors, although it spits the error out into stderr
|
25
24
|
# so we have to resort to return an error exit code if there is anything in the standard error
|
26
25
|
status = 1 if status == 0 and !stderr.empty?
|
27
26
|
{ :stdout => stdout, :stderr => stderr, :status => status }
|
28
27
|
else
|
29
|
-
stdout = `#{
|
28
|
+
stdout = `#{script} 2>&1`
|
30
29
|
{ :stdout => stdout, :stderr => nil, :status => $? }
|
31
30
|
end
|
32
31
|
end
|
@@ -47,10 +47,11 @@ EOF
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def create_script command
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
if command.is_a? Command
|
51
|
+
ps_functions = command.import_functions.map { |f| File.read(File.join(File.dirname(__FILE__), 'support', f)) }
|
52
|
+
script = build_command(command.script)
|
53
|
+
script = add_pre_command(script)
|
54
|
+
<<-EOF
|
54
55
|
$exitCode = 1
|
55
56
|
try {
|
56
57
|
#{ps_functions.join("\n")}
|
@@ -62,6 +63,21 @@ try {
|
|
62
63
|
Write-Output "Exiting with code: $exitCode"
|
63
64
|
exit $exitCode
|
64
65
|
EOF
|
66
|
+
else
|
67
|
+
script = build_command(command.to_s)
|
68
|
+
add_pre_command(script)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_running(process)
|
73
|
+
ret = run_command(commands.check_running(process))
|
74
|
+
|
75
|
+
# If the service is not registered, check the process
|
76
|
+
if ret[:exit_status] == 1
|
77
|
+
ret = run_command(commands.check_process(process))
|
78
|
+
end
|
79
|
+
|
80
|
+
ret[:exit_status] == 0
|
65
81
|
end
|
66
82
|
end
|
67
83
|
end
|
@@ -2,11 +2,7 @@ function CheckFileAccessRules
|
|
2
2
|
{
|
3
3
|
param($path, $identity, $rules)
|
4
4
|
|
5
|
-
$
|
6
|
-
$
|
7
|
-
|
8
|
-
$match = $accessRules.FileSystemRights.ToString() -Split (', ') | ?{$rules -contains $_}
|
9
|
-
$result = $match -ne $null -or $match.length -gt 0
|
10
|
-
}
|
11
|
-
$result
|
5
|
+
$accessRules = @((Get-Acl $path).access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq $identity })
|
6
|
+
$match = @($accessRules | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? {$rules -contains $_}) -ne $null})
|
7
|
+
$match.count -gt 0
|
12
8
|
}
|
@@ -6,7 +6,7 @@ function IsPortListening
|
|
6
6
|
foreach ($ipaddress in $networkIPs)
|
7
7
|
{
|
8
8
|
$matchExpression = ("$ipaddress" + ":" + $portNumber)
|
9
|
-
if ($protocol) { $matchExpression = ($protocol.toUpper() + "\s+$matchExpression") }
|
9
|
+
if ($protocol) { $matchExpression = ($protocol.toUpper() + "\s+$matchExpression") }
|
10
10
|
if ($netstatOutput -match $matchExpression) { return $true }
|
11
11
|
}
|
12
12
|
$false
|
@@ -192,7 +192,9 @@ module Serverspec
|
|
192
192
|
when :type_binary
|
193
193
|
byte_array = [property[:value]].pack('H*').bytes.to_a
|
194
194
|
"([byte[]] #{byte_array.join(',')})"
|
195
|
-
when:type_dword
|
195
|
+
when :type_dword
|
196
|
+
[property[:value].scan(/[0-9a-f]{2}/i).reverse.join].pack("H*").unpack("l").first
|
197
|
+
when :type_qword
|
196
198
|
property[:value].hex
|
197
199
|
else
|
198
200
|
string_array = property[:value].split("\n").map {|s| "'#{s}'"}.reduce {|acc, s| "#{acc},#{s}"}
|
data/lib/serverspec/version.rb
CHANGED
@@ -75,3 +75,30 @@ describe "script encoding" do
|
|
75
75
|
script.should == "dABlAHMAdABfAHAAbwB3AGUAcgBzAGgAZQBsAGwAXwBzAGMAcgBpAHAAdAA="
|
76
76
|
end
|
77
77
|
end
|
78
|
+
|
79
|
+
describe 'script creation' do
|
80
|
+
context "powershell command" do
|
81
|
+
File.should_receive(:read).with(/test_function1.ps1/).and_return 'function test1'
|
82
|
+
command = Backend::PowerShell::Command.new do
|
83
|
+
using 'test_function1.ps1'
|
84
|
+
exec 'test command'
|
85
|
+
end
|
86
|
+
script = create_script command
|
87
|
+
script.should == <<-eof
|
88
|
+
$exitCode = 1
|
89
|
+
try {
|
90
|
+
function test1
|
91
|
+
$success = (test command)
|
92
|
+
if ($success -is [Boolean] -and $success) { $exitCode = 0 }
|
93
|
+
} catch {
|
94
|
+
Write-Output $_.Exception.Message
|
95
|
+
}
|
96
|
+
Write-Output "Exiting with code: $exitCode"
|
97
|
+
exit $exitCode
|
98
|
+
eof
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'simple command' do
|
102
|
+
create_script('test command').should == 'test command'
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -39,10 +39,7 @@ module Serverspec
|
|
39
39
|
clz.class_eval do
|
40
40
|
include TestCommandRunner
|
41
41
|
def run_command(cmd)
|
42
|
-
|
43
|
-
cmd = cmd.script
|
44
|
-
end
|
45
|
-
cmd = build_command(cmd)
|
42
|
+
cmd = build_command(cmd.to_s)
|
46
43
|
cmd = add_pre_command(cmd)
|
47
44
|
do_run cmd
|
48
45
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Serverspec::Helper::Cmd
|
4
|
+
RSpec.configure do |c|
|
5
|
+
c.os = 'Windows'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe command('test_cmd /test/path/file') do
|
9
|
+
let(:stdout) { "test output 1.2.3\r\n" }
|
10
|
+
it { should return_stdout("test output 1.2.3") }
|
11
|
+
its(:command) { should eq 'test_cmd /test/path/file' }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'complete matching of stdout' do
|
15
|
+
context command('test_cmd /test/path/file') do
|
16
|
+
let(:stdout) { "foocontent-should-be-includedbar\r\n" }
|
17
|
+
it { should_not return_stdout('content-should-be-included') }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'regexp matching of stdout' do
|
22
|
+
context command('test_cmd /test/path/file') do
|
23
|
+
let(:stdout) { "test output 1.2.3\r\n" }
|
24
|
+
it { should return_stdout(/1\.2\.3/) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe command('test_cmd /test/path/file') do
|
29
|
+
let(:stdout) { "No such file or directory\r\n" }
|
30
|
+
it { should return_stderr("No such file or directory") }
|
31
|
+
its(:command) { should eq 'test_cmd /test/path/file' }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'complete matching of stderr' do
|
35
|
+
context command('test_cmd /test/path/file') do
|
36
|
+
let(:stdout) { "No such file or directory\r\n" }
|
37
|
+
it { should_not return_stdout('file') }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'regexp matching of stderr' do
|
42
|
+
context command('test_cmd /test/path/file') do
|
43
|
+
let(:stdout) { "No such file or directory\r\n" }
|
44
|
+
it { should return_stderr(/file/) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe command('test_cmd /test/path/file') do
|
49
|
+
it { should return_exit_status 0 }
|
50
|
+
its(:command) { should eq 'test_cmd /test/path/file' }
|
51
|
+
end
|
52
|
+
|
53
|
+
describe command('dir "c:\"') do
|
54
|
+
let(:stdout) { <<EOF
|
55
|
+
Directory: C:\
|
56
|
+
|
57
|
+
Mode LastWriteTime Length Name
|
58
|
+
---- ------------- ------ ----
|
59
|
+
d-r-- 23/09/2013 10:46 AM Program Files
|
60
|
+
d-r-- 23/09/2013 1:21 PM Program Files (x86)
|
61
|
+
d---- 17/10/2013 8:46 PM temp
|
62
|
+
d-r-- 23/09/2013 11:52 AM Users
|
63
|
+
d---- 23/09/2013 1:21 PM Windows
|
64
|
+
EOF
|
65
|
+
}
|
66
|
+
|
67
|
+
its(:stdout) { should match /Program Files/ }
|
68
|
+
its(:stderr) { should match /Program Files/ }
|
69
|
+
|
70
|
+
its(:stdout) { should eq stdout }
|
71
|
+
end
|
@@ -22,3 +22,12 @@ end
|
|
22
22
|
describe service('invalid-daemon') do
|
23
23
|
it { should_not be_running }
|
24
24
|
end
|
25
|
+
|
26
|
+
describe service('Test service') do
|
27
|
+
it "should raise error if trying to check service process controller" do
|
28
|
+
expect { should be_running.under('supervisor') }.to raise_error
|
29
|
+
end
|
30
|
+
it "should raise error if trying to check service monitoring" do
|
31
|
+
expect { should_not be_monitored_by('monit') }.to raise_error
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Serverspec::Helper::Cmd
|
4
|
+
RSpec.configure do |c|
|
5
|
+
c.os = 'Windows'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
9
|
+
it { should exist }
|
10
|
+
its(:command) { should == "(Get-Item 'Registry::PATH/TO/THE_KEY') -ne $null" }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
14
|
+
it { should have_value('Test Value') }
|
15
|
+
its(:command) { should == "(Compare-Object (Get-Item 'Registry::PATH/TO/THE_KEY').GetValue('') @('Test Value')) -eq $null" }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'Key value types' do
|
19
|
+
context 'default type' do
|
20
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
21
|
+
it { should have_property('TestProperty') }
|
22
|
+
its(:command) { should == "(Get-Item 'Registry::PATH/TO/THE_KEY').GetValueKind('TestProperty') -eq 'String'" }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
{
|
27
|
+
:type_string => 'String',
|
28
|
+
:type_binary => 'Binary',
|
29
|
+
:type_dword => 'DWord',
|
30
|
+
:type_qword => 'QWord',
|
31
|
+
:type_multistring => 'MultiString',
|
32
|
+
:type_expandstring => 'ExpandString'
|
33
|
+
}.each do |sym, type|
|
34
|
+
context "type #{type}" do
|
35
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
36
|
+
it { should have_property('TestProperty', sym) }
|
37
|
+
its(:command) { should == "(Get-Item 'Registry::PATH/TO/THE_KEY').GetValueKind('TestProperty') -eq '#{type}'" }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
44
|
+
it { should have_property_value('TestProperty', :type_binary, '12a07b') }
|
45
|
+
its(:command) { should == "(Compare-Object (Get-Item 'Registry::PATH/TO/THE_KEY').GetValue('TestProperty') ([byte[]] 18,160,123)) -eq $null" }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
49
|
+
it { should have_property_value('TestProperty', :type_dword, 'fffffd6c') }
|
50
|
+
its(:command) { should == "(Compare-Object (Get-Item 'Registry::PATH/TO/THE_KEY').GetValue('TestProperty') -660) -eq $null" }
|
51
|
+
end
|
52
|
+
|
53
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
54
|
+
it { should have_property_value('TestProperty', :type_qword, '1e240') }
|
55
|
+
its(:command) { should == "(Compare-Object (Get-Item 'Registry::PATH/TO/THE_KEY').GetValue('TestProperty') 123456) -eq $null" }
|
56
|
+
end
|
57
|
+
|
58
|
+
describe windows_registry_key('PATH/TO/THE_KEY') do
|
59
|
+
it {
|
60
|
+
value = <<-EOF
|
61
|
+
test line1
|
62
|
+
test line2
|
63
|
+
test line3
|
64
|
+
EOF
|
65
|
+
should have_property_value('TestProperty', :type_multistring, value)
|
66
|
+
}
|
67
|
+
its(:command) { should == "(Compare-Object (Get-Item 'Registry::PATH/TO/THE_KEY').GetValue('TestProperty') @('test line1','test line2','test line3')) -eq $null" }
|
68
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serverspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gosuke Miyashita
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ssh
|
@@ -95,7 +95,7 @@ files:
|
|
95
95
|
- LICENSE.txt
|
96
96
|
- README.md
|
97
97
|
- Rakefile
|
98
|
-
-
|
98
|
+
- WINDOWS_SUPPORT.md
|
99
99
|
- bin/serverspec-init
|
100
100
|
- lib/serverspec.rb
|
101
101
|
- lib/serverspec/attributes.rb
|
@@ -368,11 +368,13 @@ files:
|
|
368
368
|
- spec/solaris11/zfs_spec.rb
|
369
369
|
- spec/spec_helper.rb
|
370
370
|
- spec/support/powershell_command_runner.rb
|
371
|
+
- spec/windows/command_spec.rb
|
371
372
|
- spec/windows/file_spec.rb
|
372
373
|
- spec/windows/group_spec.rb
|
373
374
|
- spec/windows/port_spec.rb
|
374
375
|
- spec/windows/service_spec.rb
|
375
376
|
- spec/windows/user_spec.rb
|
377
|
+
- spec/windows/windows_registry_key_spec.rb
|
376
378
|
homepage: http://serverspec.org/
|
377
379
|
licenses:
|
378
380
|
- MIT
|
@@ -564,8 +566,10 @@ test_files:
|
|
564
566
|
- spec/solaris11/zfs_spec.rb
|
565
567
|
- spec/spec_helper.rb
|
566
568
|
- spec/support/powershell_command_runner.rb
|
569
|
+
- spec/windows/command_spec.rb
|
567
570
|
- spec/windows/file_spec.rb
|
568
571
|
- spec/windows/group_spec.rb
|
569
572
|
- spec/windows/port_spec.rb
|
570
573
|
- spec/windows/service_spec.rb
|
571
574
|
- spec/windows/user_spec.rb
|
575
|
+
- spec/windows/windows_registry_key_spec.rb
|