Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
aibou committed Sep 24, 2013
2 parents 67e59fe + 038ad41 commit 79533a3
Show file tree
Hide file tree
Showing 66 changed files with 3,297 additions and 142 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -3,6 +3,7 @@
*.swp
.bundle
.rvmrc
.versions.conf
.config
.yardoc
.rspec
Expand All @@ -21,3 +22,4 @@ test/version_tmp
tmp
Vagrantfile
vendor/
.DS_Store
14 changes: 6 additions & 8 deletions Rakefile
Expand Up @@ -4,9 +4,9 @@ require 'rspec/core/rake_task'
task :spec => 'spec:all'

namespace :spec do
oses = %w( darwin debian gentoo redhat solaris solaris10 solaris11 smartos )
oses = %w( darwin debian gentoo redhat aix solaris solaris10 solaris11 smartos windows freebsd)

task :all => [ oses.map {|os| "spec:#{os}" }, :helpers, :exec, :ssh ].flatten
task :all => [ oses.map {|os| "spec:#{os}" }, :helpers, :exec, :ssh, :cmd, :winrm, :powershell ].flatten

oses.each do |os|
RSpec::Core::RakeTask.new(os.to_sym) do |t|
Expand All @@ -18,11 +18,9 @@ namespace :spec do
t.pattern = "spec/helpers/*_spec.rb"
end

RSpec::Core::RakeTask.new(:exec) do |t|
t.pattern = "spec/backend/exec/*_spec.rb"
end

RSpec::Core::RakeTask.new(:ssh) do |t|
t.pattern = "spec/backend/ssh/*_spec.rb"
[:exec, :ssh, :cmd, :winrm, :powershell].each do |backend|
RSpec::Core::RakeTask.new(backend) do |t|
t.pattern = "spec/backend/#{backend.to_s}/*_spec.rb"
end
end
end
88 changes: 88 additions & 0 deletions WindowsSupport.md
@@ -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
```
7 changes: 7 additions & 0 deletions lib/serverspec.rb
Expand Up @@ -11,11 +11,14 @@
require 'serverspec/commands/redhat'
require 'serverspec/commands/debian'
require 'serverspec/commands/gentoo'
require 'serverspec/commands/aix'
require 'serverspec/commands/solaris'
require 'serverspec/commands/solaris10'
require 'serverspec/commands/solaris11'
require 'serverspec/commands/smartos'
require 'serverspec/commands/darwin'
require 'serverspec/commands/windows'
require 'serverspec/commands/freebsd'
require 'serverspec/configuration'
require 'rspec/core/formatters/base_formatter'

Expand All @@ -34,15 +37,19 @@ def configuration
c.include(Serverspec::Helper::RedHat, :os => :redhat)
c.include(Serverspec::Helper::Debian, :os => :debian)
c.include(Serverspec::Helper::Gentoo, :os => :gentoo)
c.include(Serverspec::Helper::AIX, :os => :aix)
c.include(Serverspec::Helper::Solaris, :os => :solaris)
c.include(Serverspec::Helper::Solaris10, :os => :solaris10)
c.include(Serverspec::Helper::Solaris11, :os => :solaris11)
c.include(Serverspec::Helper::SmartOS, :os => :smartos)
c.include(Serverspec::Helper::Darwin, :os => :darwin)
c.include(Serverspec::Helper::Windows, :os => :windows)
c.include(Serverspec::Helper::FreeBSD, :os => :freebsd)
c.add_setting :os, :default => nil
c.add_setting :host, :default => nil
c.add_setting :ssh, :default => nil
c.add_setting :sudo_password, :default => nil
c.add_setting :winrm, :default => nil
Serverspec.configuration.defaults.each { |k, v| c.add_setting k, :default => v }
c.before :each do
backend.set_example(example)
Expand Down
5 changes: 5 additions & 0 deletions lib/serverspec/backend.rb
@@ -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'
31 changes: 31 additions & 0 deletions lib/serverspec/backend/base.rb
@@ -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
35 changes: 35 additions & 0 deletions lib/serverspec/backend/cmd.rb
@@ -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
29 changes: 5 additions & 24 deletions lib/serverspec/backend/exec.rb
Expand Up @@ -2,20 +2,7 @@

module Serverspec
module Backend
class Exec
include Singleton

def set_commands(c)
@commands = c
end

def set_example(e)
@example = e
end

def commands
@commands
end
class Exec < Base

def run_command(cmd, opts={})
cmd = build_command(cmd)
Expand Down Expand Up @@ -52,16 +39,6 @@ def add_pre_command(cmd)
cmd
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

def check_running(process)
ret = run_command(commands.check_running(process))
if ret[:exit_status] == 1 || ret[:stdout] =~ /stopped/
Expand Down Expand Up @@ -189,6 +166,8 @@ def check_os
'Debian'
elsif run_command('ls /etc/gentoo-release')[:exit_status] == 0
'Gentoo'
elsif run_command('uname -s')[:stdout] =~ /AIX/i
'AIX'
elsif (os = run_command('uname -sr')[:stdout]) && os =~ /SunOS/i
if os =~ /5.10/
'Solaris10'
Expand All @@ -201,6 +180,8 @@ def check_os
end
elsif run_command('uname -s')[:stdout] =~ /Darwin/i
'Darwin'
elsif run_command('uname -s')[:stdout] =~ /FreeBSD/i
'FreeBSD'
else
'Base'
end
Expand Down
36 changes: 36 additions & 0 deletions lib/serverspec/backend/powershell/command.rb
@@ -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

0 comments on commit 79533a3

Please sign in to comment.