-
Notifications
You must be signed in to change notification settings - Fork 369
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #244 from serverspec/windows
[WIP]Support Windows
- Loading branch information
Showing
37 changed files
with
1,160 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
## Windows support | ||
|
||
Serverspec is now providing a limited support for Microsoft Windows. | ||
|
||
If you want to test Windows based machines you need to set the target host's OS explicitly in your `spec/spec_helper.rb` | ||
|
||
For local testing (equivalent to the Exec option in Linux/Unix systems) simply do: | ||
|
||
```ruby | ||
require 'serverspec' | ||
|
||
include Serverspec::Helper::Cmd | ||
include Serverspec::Helper::Windows | ||
|
||
``` | ||
|
||
For remote testing you have to configure Windows Remote Management in order to communicate to the target host: | ||
|
||
```ruby | ||
require 'serverspec' | ||
require 'winrm' | ||
|
||
include Serverspec::Helper::WinRM | ||
include Serverspec::Helper::Windows | ||
|
||
RSpec.configure do |c| | ||
user = <username> | ||
pass = <password> | ||
endpoint = "http://<hostname>:5985/wsman" | ||
|
||
c.winrm = ::WinRM::WinRMWebService.new(endpoint, :ssl, :user => user, :pass => pass, :basic_auth_only => true) | ||
c.winrm.set_timeout 300 # 5 minutes max timeout for any operation | ||
end | ||
``` | ||
|
||
For different authentication mechanisms check the Microsoft WinRM documentation and verify the ones that are supported by [WinRb/WinRM](https://github.com/WinRb/WinRM) | ||
|
||
|
||
###RSpec Examples for windows target hosts | ||
```ruby | ||
describe file('c:/windows') do | ||
it { should be_directory } | ||
it { should be_readable } | ||
it { should_not be_writable.by('Everyone') } | ||
end | ||
|
||
describe file('c:/temp/test.txt') do | ||
it { should be_file } | ||
it { should contain "some text" } | ||
end | ||
|
||
describe package('Adobe AIR') do | ||
it { should be_installed} | ||
end | ||
|
||
describe service('DNS Client') do | ||
it { should be_enabled } | ||
it { should be_running } | ||
end | ||
|
||
describe port(139) do | ||
it { should be_listening } | ||
end | ||
|
||
describe user('some.admin') do | ||
it { should exist } | ||
it { should belong_to_group('Administrators')} | ||
end | ||
|
||
describe group('Guests') do | ||
it { should exist } | ||
end | ||
|
||
describe group('MYDOMAIN\Domain Users') do | ||
it { should exist } | ||
end | ||
|
||
describe windows_registry_key('HKEY_USERS\S-1-5-21-1319311448-2088773778-316617838-32407\Test MyKey') do | ||
it { should exist } | ||
it { should have_property('string value') } | ||
it { should have_property('binary value', :type_binary) } | ||
it { should have_property('dword value', :type_dword) } | ||
it { should have_value('test default data') } | ||
it { should have_property_value('multistring value', :type_multistring, "test\nmulti\nstring\ndata") } | ||
it { should have_property_value('qword value', :type_qword, 'adff32') } | ||
it { should have_property_value('binary value', :type_binary, 'dfa0f066') } | ||
end | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,7 @@ | ||
require 'serverspec/backend/base' | ||
require 'serverspec/backend/ssh' | ||
require 'serverspec/backend/exec' | ||
require 'serverspec/backend/powershell/script_helper' | ||
require 'serverspec/backend/powershell/command' | ||
require 'serverspec/backend/cmd' | ||
require 'serverspec/backend/winrm' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
require 'singleton' | ||
|
||
module Serverspec | ||
module Backend | ||
class Base | ||
include Singleton | ||
|
||
def set_commands(c) | ||
@commands = c | ||
end | ||
|
||
def set_example(e) | ||
@example = e | ||
end | ||
|
||
def commands | ||
@commands | ||
end | ||
|
||
def check_zero(cmd, *args) | ||
ret = run_command(commands.send(cmd, *args)) | ||
ret[:exit_status] == 0 | ||
end | ||
|
||
# Default action is to call check_zero with args | ||
def method_missing(meth, *args, &block) | ||
check_zero(meth, *args) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
require 'open3' | ||
|
||
module Serverspec | ||
module Backend | ||
class Cmd < Base | ||
include PowerShell::ScriptHelper | ||
|
||
def run_command(cmd, opts={}) | ||
script = create_script(cmd) | ||
result = execute_script script | ||
|
||
if @example | ||
@example.metadata[:command] = script | ||
@example.metadata[:stdout] = result[:stdout] + result[:stderr] | ||
end | ||
{ :stdout => result[:stdout], :stderr => result[:stderr], | ||
:exit_status => result[:status], :exit_signal => nil } | ||
end | ||
|
||
def execute_script script | ||
ps_script = %Q{powershell -encodedCommand #{encode_script(script)}} | ||
if Open3.respond_to? :capture3 | ||
stdout, stderr, status = Open3.capture3(ps_script) | ||
# powershell still exits with 0 even if there are syntax errors, although it spits the error out into stderr | ||
# so we have to resort to return an error exit code if there is anything in the standard error | ||
status = 1 if status == 0 and !stderr.empty? | ||
{ :stdout => stdout, :stderr => stderr, :status => status } | ||
else | ||
stdout = `#{ps_script} 2>&1` | ||
{ :stdout => stdout, :stderr => nil, :status => $? } | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
module Serverspec | ||
module Backend | ||
module PowerShell | ||
class Command | ||
attr_reader :import_functions, :script | ||
def initialize &block | ||
@import_functions = [] | ||
@script = "" | ||
instance_eval &block if block_given? | ||
end | ||
|
||
def using *functions | ||
functions.each { |f| import_functions << f } | ||
end | ||
|
||
def exec code | ||
@script = code | ||
end | ||
|
||
def convert_regexp(target) | ||
case target | ||
when Regexp | ||
target.source | ||
else | ||
target.to_s.gsub '/', '' | ||
end | ||
end | ||
|
||
def get_identity id | ||
raise "You must provide a specific Windows user/group" if id =~ /(owner|group|others)/ | ||
identity = id || 'Everyone' | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.