From 5bb30a202c98e98c2a5497bd8a1c3de032244eaf Mon Sep 17 00:00:00 2001 From: Takahiro OKUMURA Date: Sat, 22 Jun 2013 23:08:15 +0900 Subject: [PATCH 01/43] Detect FreeBSD for beginning to suppert it. --- lib/serverspec.rb | 2 ++ lib/serverspec/backend/exec.rb | 2 ++ lib/serverspec/commands/freebsd.rb | 9 +++++++++ lib/serverspec/helper.rb | 1 + lib/serverspec/helper/freebsd.rb | 9 +++++++++ 5 files changed, 23 insertions(+) create mode 100644 lib/serverspec/commands/freebsd.rb create mode 100644 lib/serverspec/helper/freebsd.rb diff --git a/lib/serverspec.rb b/lib/serverspec.rb index b605878a..a68f4111 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -13,6 +13,7 @@ require 'serverspec/commands/gentoo' require 'serverspec/commands/solaris' require 'serverspec/commands/darwin' +require 'serverspec/commands/freebsd' require 'serverspec/configuration' require 'rspec/core/formatters/base_formatter' @@ -33,6 +34,7 @@ def configuration c.include(Serverspec::Helper::Gentoo, :os => :gentoo) c.include(Serverspec::Helper::Solaris, :os => :solaris) c.include(Serverspec::Helper::Darwin, :os => :darwin) + c.include(Serverspec::Helper::Darwin, :os => :freebsd) c.add_setting :os, :default => nil c.add_setting :host, :default => nil c.add_setting :ssh, :default => nil diff --git a/lib/serverspec/backend/exec.rb b/lib/serverspec/backend/exec.rb index dcefc5ca..efa78252 100644 --- a/lib/serverspec/backend/exec.rb +++ b/lib/serverspec/backend/exec.rb @@ -185,6 +185,8 @@ def check_os 'Solaris' elsif run_command('uname -s')[:stdout] =~ /Darwin/i 'Darwin' + elsif run_command('uname -s')[:stdout] =~ /FreeBSD/i + 'FreeBSD' else 'Base' end diff --git a/lib/serverspec/commands/freebsd.rb b/lib/serverspec/commands/freebsd.rb new file mode 100644 index 00000000..553639d6 --- /dev/null +++ b/lib/serverspec/commands/freebsd.rb @@ -0,0 +1,9 @@ +require 'shellwords' + +module Serverspec + module Commands + class FreeBSD < Base + class NotImplementedError < Exception; end + end + end +end diff --git a/lib/serverspec/helper.rb b/lib/serverspec/helper.rb index 2d9cfcac..e34fc602 100644 --- a/lib/serverspec/helper.rb +++ b/lib/serverspec/helper.rb @@ -11,6 +11,7 @@ require 'serverspec/helper/gentoo' require 'serverspec/helper/solaris' require 'serverspec/helper/darwin' +require 'serverspec/helper/freebsd' require 'serverspec/helper/detect_os' # Attributes helper diff --git a/lib/serverspec/helper/freebsd.rb b/lib/serverspec/helper/freebsd.rb new file mode 100644 index 00000000..b4d4c2f8 --- /dev/null +++ b/lib/serverspec/helper/freebsd.rb @@ -0,0 +1,9 @@ +module Serverspec + module Helper + module FreeBSD + def commands + Serverspec::Commands::FreeBSD.new + end + end + end +end From f4de1b099444ddb8c5f6f0d5d7edda0fcf8a521c Mon Sep 17 00:00:00 2001 From: Takahiro OKUMURA Date: Sat, 22 Jun 2013 23:12:11 +0900 Subject: [PATCH 02/43] Fixed --- lib/serverspec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec.rb b/lib/serverspec.rb index a68f4111..dc7059b4 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -34,7 +34,7 @@ def configuration c.include(Serverspec::Helper::Gentoo, :os => :gentoo) c.include(Serverspec::Helper::Solaris, :os => :solaris) c.include(Serverspec::Helper::Darwin, :os => :darwin) - c.include(Serverspec::Helper::Darwin, :os => :freebsd) + 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 From 82f620dd496c6f652137d2a630340fde973a9a81 Mon Sep 17 00:00:00 2001 From: Takahiro OKUMURA Date: Sun, 23 Jun 2013 12:50:25 +0900 Subject: [PATCH 03/43] Remove an extra space --- lib/serverspec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec.rb b/lib/serverspec.rb index dc7059b4..bf86fc03 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -34,7 +34,7 @@ def configuration c.include(Serverspec::Helper::Gentoo, :os => :gentoo) c.include(Serverspec::Helper::Solaris, :os => :solaris) c.include(Serverspec::Helper::Darwin, :os => :darwin) - c.include(Serverspec::Helper::FreeBSD, :os => :freebsd) + 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 From 52a55108d991b61b576a6aa16899b92a2be2f682 Mon Sep 17 00:00:00 2001 From: Takahiro OKUMURA Date: Sun, 23 Jun 2013 17:14:40 +0900 Subject: [PATCH 04/43] Remove an unnecessary line because already defined in Base class. --- lib/serverspec/commands/freebsd.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/serverspec/commands/freebsd.rb b/lib/serverspec/commands/freebsd.rb index 553639d6..70cbe8a8 100644 --- a/lib/serverspec/commands/freebsd.rb +++ b/lib/serverspec/commands/freebsd.rb @@ -3,7 +3,18 @@ module Serverspec module Commands class FreeBSD < Base - class NotImplementedError < Exception; end + def check_enabled service + "service -e | grep -- #{escape(service)}" + end + + def check_installed package + "pkg_version -X -s #{escape(package)}" + end + + def check_listening port + regexp = ":#{port} " + "sockstat -46l -p #{port} | grep -- #{escape(regexp)}" + end end end end From 9efd1af90492d73d6aea885267c1370e5c5954e2 Mon Sep 17 00:00:00 2001 From: Takahiro OKUMURA Date: Sun, 23 Jun 2013 18:10:26 +0900 Subject: [PATCH 05/43] Add parentheses according to Ruby Styleguide. --- lib/serverspec/commands/freebsd.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/serverspec/commands/freebsd.rb b/lib/serverspec/commands/freebsd.rb index 70cbe8a8..7cfa97a6 100644 --- a/lib/serverspec/commands/freebsd.rb +++ b/lib/serverspec/commands/freebsd.rb @@ -3,15 +3,15 @@ module Serverspec module Commands class FreeBSD < Base - def check_enabled service + def check_enabled(service) "service -e | grep -- #{escape(service)}" end - def check_installed package + def check_installed(package) "pkg_version -X -s #{escape(package)}" end - def check_listening port + def check_listening(port) regexp = ":#{port} " "sockstat -46l -p #{port} | grep -- #{escape(regexp)}" end From 2c1d3468282d4d2d66d68d78c5ab2825dfbb00b3 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Tue, 10 Sep 2013 16:00:44 +0100 Subject: [PATCH 06/43] Aix support added --- Rakefile | 2 +- lib/serverspec.rb | 2 ++ lib/serverspec/backend/exec.rb | 2 ++ lib/serverspec/helper.rb | 1 + lib/serverspec/version.rb | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index a44099c5..52fa16c4 100644 --- a/Rakefile +++ b/Rakefile @@ -4,7 +4,7 @@ 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 ) task :all => [ oses.map {|os| "spec:#{os}" }, :helpers, :exec, :ssh ].flatten diff --git a/lib/serverspec.rb b/lib/serverspec.rb index 6ebfc1cd..550762c3 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -11,6 +11,7 @@ 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' @@ -34,6 +35,7 @@ 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) diff --git a/lib/serverspec/backend/exec.rb b/lib/serverspec/backend/exec.rb index 177f7353..8b5a5767 100644 --- a/lib/serverspec/backend/exec.rb +++ b/lib/serverspec/backend/exec.rb @@ -189,6 +189,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' diff --git a/lib/serverspec/helper.rb b/lib/serverspec/helper.rb index 2e8439c2..4da21861 100644 --- a/lib/serverspec/helper.rb +++ b/lib/serverspec/helper.rb @@ -9,6 +9,7 @@ require 'serverspec/helper/redhat' require 'serverspec/helper/debian' require 'serverspec/helper/gentoo' +require 'serverspec/helper/aix' require 'serverspec/helper/solaris' require 'serverspec/helper/solaris10' require 'serverspec/helper/solaris11' diff --git a/lib/serverspec/version.rb b/lib/serverspec/version.rb index f1916854..1bc97042 100644 --- a/lib/serverspec/version.rb +++ b/lib/serverspec/version.rb @@ -1,3 +1,3 @@ module Serverspec - VERSION = "0.7.13" + VERSION = "0.7.14" end From d3ec54e45b20267ad957572c9b6a8eba84ca7311 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Tue, 10 Sep 2013 17:43:07 +0100 Subject: [PATCH 07/43] Aix support added --- lib/serverspec/commands/aix.rb | 36 +++ lib/serverspec/helper/aix.rb | 9 + spec/aix/command_spec.rb | 48 +++ spec/aix/commands_spec.rb | 13 + spec/aix/cron_spec.rb | 21 ++ spec/aix/default_gateway_spec.rb | 16 + spec/aix/file_spec.rb | 395 ++++++++++++++++++++++++ spec/aix/group_spec.rb | 21 ++ spec/aix/host_spec.rb | 58 ++++ spec/aix/interface_spec.rb | 24 ++ spec/aix/iptables_spec.rb | 21 ++ spec/aix/kernel_module_spec.rb | 12 + spec/aix/linux_kernel_parameter_spec.rb | 36 +++ spec/aix/package_spec.rb | 94 ++++++ spec/aix/php_config_spec.rb | 36 +++ spec/aix/port_spec.rb | 30 ++ spec/aix/routing_table_spec.rb | 120 +++++++ spec/aix/selinux_spec.rb | 18 ++ spec/aix/service_spec.rb | 93 ++++++ spec/aix/user_spec.rb | 58 ++++ spec/aix/yumrepo_spec.rb | 25 ++ spec/aix/zfs_spec.rb | 18 ++ 22 files changed, 1202 insertions(+) create mode 100644 lib/serverspec/commands/aix.rb create mode 100644 lib/serverspec/helper/aix.rb create mode 100644 spec/aix/command_spec.rb create mode 100644 spec/aix/commands_spec.rb create mode 100644 spec/aix/cron_spec.rb create mode 100644 spec/aix/default_gateway_spec.rb create mode 100644 spec/aix/file_spec.rb create mode 100644 spec/aix/group_spec.rb create mode 100644 spec/aix/host_spec.rb create mode 100644 spec/aix/interface_spec.rb create mode 100644 spec/aix/iptables_spec.rb create mode 100644 spec/aix/kernel_module_spec.rb create mode 100644 spec/aix/linux_kernel_parameter_spec.rb create mode 100644 spec/aix/package_spec.rb create mode 100644 spec/aix/php_config_spec.rb create mode 100644 spec/aix/port_spec.rb create mode 100644 spec/aix/routing_table_spec.rb create mode 100644 spec/aix/selinux_spec.rb create mode 100644 spec/aix/service_spec.rb create mode 100644 spec/aix/user_spec.rb create mode 100644 spec/aix/yumrepo_spec.rb create mode 100644 spec/aix/zfs_spec.rb diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb new file mode 100644 index 00000000..f96f8d20 --- /dev/null +++ b/lib/serverspec/commands/aix.rb @@ -0,0 +1,36 @@ +require 'shellwords' + +module Serverspec + module Commands + class Aix < Base +# +# SJT Aix class +# + class NotImplementedError < Exception; end + + def check_access_by_user(file, user, access) + "su -s sh -c \"test -#{access} #{file}\" #{user}" + end + + def check_enabled(service,level=nil) + "lssrc -s #{escape(service)} | grep active" + end + + def check_running(service) + "ps -ef | grep -v grep | grep #{escape(service)}" + end + + def check_installed(package,version=nil) + "lslpp -L #{escape(package)}" + end + + def check_listening(port) + regexp = "*.#{port} " + "netstat -an -f inet | awk '{print $4}' | grep -- #{regexp}" + #"netstat -an -f inet | awk '{print $4}' | grep -- #{escape(regexp)}" + end + + + end + end +end diff --git a/lib/serverspec/helper/aix.rb b/lib/serverspec/helper/aix.rb new file mode 100644 index 00000000..75a19d2e --- /dev/null +++ b/lib/serverspec/helper/aix.rb @@ -0,0 +1,9 @@ +module Serverspec + module Helper + module Aix + def commands + Serverspec::Commands::Aix.new + end + end + end +end diff --git a/spec/aix/command_spec.rb b/spec/aix/command_spec.rb new file mode 100644 index 00000000..1f23b424 --- /dev/null +++ b/spec/aix/command_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe command('cat /etc/resolv.conf') do + let(:stdout) { "nameserver 127.0.0.1\r\n" } + it { should return_stdout("nameserver 127.0.0.1") } + its(:command) { should eq 'cat /etc/resolv.conf' } +end + +describe 'complete matching of stdout' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "foocontent-should-be-includedbar\r\n" } + it { should_not return_stdout('content-should-be-included') } + end +end + +describe 'regexp matching of stdout' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "nameserver 127.0.0.1\r\n" } + it { should return_stdout(/127\.0\.0\.1/) } + end +end + +describe command('cat /etc/resolv.conf') do + let(:stdout) { "No such file or directory\r\n" } + it { should return_stderr("No such file or directory") } + its(:command) { should eq 'cat /etc/resolv.conf' } +end + +describe 'complete matching of stderr' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "No such file or directory\r\n" } + it { should_not return_stdout('file') } + end +end + +describe 'regexp matching of stderr' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "No such file or directory\r\n" } + it { should return_stderr(/file/) } + end +end + +describe command('cat /etc/resolv.conf') do + it { should return_exit_status 0 } + its(:command) { should eq 'cat /etc/resolv.conf' } +end diff --git a/spec/aix/commands_spec.rb b/spec/aix/commands_spec.rb new file mode 100644 index 00000000..7dc4aec6 --- /dev/null +++ b/spec/aix/commands_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe 'check_yumrepo' do + subject { commands.check_yumrepo('epel') } + it { should eq 'yum repolist all -C | grep ^epel' } +end + +describe 'check_yumrepo_enabled' do + subject { commands.check_yumrepo_enabled('epel') } + it { should eq 'yum repolist all -C | grep ^epel | grep enabled' } +end diff --git a/spec/aix/cron_spec.rb b/spec/aix/cron_spec.rb new file mode 100644 index 00000000..ba30ec20 --- /dev/null +++ b/spec/aix/cron_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe cron do + it { should have_entry '* * * * * /usr/local/bin/batch.sh' } + its(:command) { should eq 'crontab -l | grep -- \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ /usr/local/bin/batch.sh' } +end + +describe cron do + it { should_not have_entry 'invalid entry' } +end + +describe cron do + it { should have_entry('* * * * * /usr/local/bin/batch.sh').with_user('root') } + its(:command) { should eq 'crontab -u root -l | grep -- \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ /usr/local/bin/batch.sh' } +end + +describe cron do + it { should_not have_entry('* * * * * /usr/local/bin/batch.sh').with_user('invalid-user') } +end diff --git a/spec/aix/default_gateway_spec.rb b/spec/aix/default_gateway_spec.rb new file mode 100644 index 00000000..2250a789 --- /dev/null +++ b/spec/aix/default_gateway_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe default_gateway do + let(:stdout) { "default via 192.168.1.1 dev eth1 \r\n" } + + its(:ipaddress) { should eq '192.168.1.1' } + its(:command) { should eq "ip route | grep -E '^default |^default '" } + + its(:interface) { should eq 'eth1' } + its(:command) { should eq "ip route | grep -E '^default |^default '" } + + its(:ipaddress) { should_not eq '192.168.1.2' } + its(:interface) { should_not eq 'eth0' } +end diff --git a/spec/aix/file_spec.rb b/spec/aix/file_spec.rb new file mode 100644 index 00000000..444939b0 --- /dev/null +++ b/spec/aix/file_spec.rb @@ -0,0 +1,395 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe file('/etc/ssh/sshd_config') do + it { should be_file } + its(:command) { should eq "test -f /etc/ssh/sshd_config" } +end + +describe file('/etc/invalid_file') do + it { should_not be_file } +end + +describe file('/etc/ssh') do + it { should be_directory } + its(:command) { should eq "test -d /etc/ssh" } +end + +describe file('/etc/invalid_directory') do + it { should_not be_directory } +end + +describe file('/var/run/unicorn.sock') do + it { should be_socket } + its(:command) { should eq "test -S /var/run/unicorn.sock" } +end + +describe file('/etc/invalid_socket') do + it { should_not be_socket } +end + +describe file('/etc/ssh/sshd_config') do + it { should contain 'This is the sshd server system-wide configuration file' } + its(:command) { should eq "grep -q -- This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config || grep -qF -- This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config" } +end + +describe file('/etc/ssh/sshd_config') do + it { should contain /^This is the sshd server system-wide configuration file/ } + its(:command) { should eq "grep -q -- \\^This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config || grep -qF -- \\^This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain 'This is invalid text!!' } +end + +describe file('Gemfile') do + it { should contain('rspec').from(/^group :test do/).to(/^end/) } + its(:command) { should eq "sed -n /\\^group\\ :test\\ do/,/\\^end/p Gemfile | grep -q -- rspec - || sed -n /\\^group\\ :test\\ do/,/\\^end/p Gemfile | grep -qF -- rspec -" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain('This is invalid text!!').from(/^group :test do/).to(/^end/) } +end + +describe file('Gemfile') do + it { should contain('rspec').after(/^group :test do/) } + its(:command) { should eq "sed -n /\\^group\\ :test\\ do/,\\$p Gemfile | grep -q -- rspec - || sed -n /\\^group\\ :test\\ do/,\\$p Gemfile | grep -qF -- rspec -" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain('This is invalid text!!').after(/^group :test do/) } +end + +describe file('Gemfile') do + it { should contain('rspec').before(/^end/) } + its(:command) { should eq "sed -n 1,/\\^end/p Gemfile | grep -q -- rspec - || sed -n 1,/\\^end/p Gemfile | grep -qF -- rspec -" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain('This is invalid text!!').before(/^end/) } +end + +describe file('/etc/passwd') do + it { should be_mode 644 } + its(:command) { should eq "stat -c %a /etc/passwd | grep -- \\^644\\$" } +end + +describe file('/etc/passwd') do + it { should_not be_mode 'invalid' } +end + +describe file('/etc/passwd') do + it { should be_owned_by 'root' } + its(:command) { should eq "stat -c %U /etc/passwd | grep -- \\^root\\$" } +end + +describe file('/etc/passwd') do + it { should_not be_owned_by 'invalid-owner' } +end + +describe file('/etc/passwd') do + it { should be_grouped_into 'root' } + its(:command) { should eq "stat -c %G /etc/passwd | grep -- \\^root\\$" } +end + +describe file('/etc/passwd') do + it { should_not be_grouped_into 'invalid-group' } +end + +describe file('/etc/pam.d/system-auth') do + it { should be_linked_to '/etc/pam.d/system-auth-ac' } + its(:command) { should eq "stat -c %N /etc/pam.d/system-auth | grep -- /etc/pam.d/system-auth-ac" } +end + +describe file('dummy-link') do + it { should_not be_linked_to '/invalid/target' } +end + +describe file('/dev') do + let(:stdout) { "755\r\n" } + it { should be_readable } + its(:command) { should eq "stat -c %a /dev" } +end + +describe file('/dev') do + let(:stdout) { "333\r\n" } + it { should_not be_readable } +end + +describe file('/dev') do + let(:stdout) { "400\r\n" } + it { should be_readable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "044\r\n" } + it { should_not be_readable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "040\r\n" } + it { should be_readable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "404\r\n" } + it { should_not be_readable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "044\r\n" } + it { should be_readable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "443\r\n" } + it { should_not be_readable.by('others') } +end + +describe file('/tmp') do + it { should be_readable.by_user('mail') } + its(:command) { should eq "runuser -s /bin/sh -c \"test -r /tmp\" mail" } +end + +describe file('/tmp') do + it { should_not be_readable.by_user('invalid-user') } +end + +describe file('/dev') do + let(:stdout) { "755\r\n" } + it { should be_writable } + its(:command) { should eq "stat -c %a /dev" } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable } +end + +describe file('/dev') do + let(:stdout) { "200\r\n" } + it { should be_writable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "030\r\n" } + it { should be_writable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should be_writable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable.by('others') } +end + +describe file('/tmp') do + it { should be_writable.by_user('mail') } + its(:command) { should eq "runuser -s /bin/sh -c \"test -w /tmp\" mail" } +end + +describe file('/tmp') do + it { should_not be_writable.by_user('invalid-user') } +end + +describe file('/dev') do + let(:stdout) { "755\r\n" } + it { should be_executable } + its(:command) { should eq "stat -c %a /dev" } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable } +end + +describe file('/dev') do + let(:stdout) { "100\r\n" } + it { should be_executable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "070\r\n" } + it { should be_executable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "001\r\n" } + it { should be_executable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable.by('others') } +end + +describe file('/tmp') do + it { should be_executable.by_user('mail') } + its(:command) { should eq "runuser -s /bin/sh -c \"test -x /tmp\" mail" } +end + +describe file('/tmp') do + it { should_not be_executable.by_user('invalid-user') } +end + +describe file('/') do + it { should be_mounted } + its(:command) { should eq "mount | grep -w -- on\\ /" } +end + +describe file('/etc/invalid-mount') do + it { should_not be_mounted } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4', :options => { :rw => true } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4', :options => { :mode => 620 } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_root' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'xfs' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4', :options => { :rw => false } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4', :options => { :mode => 600 } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'xfs', :device => '/dev/mapper/VolGroup-lv_root' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_r00t' ) } +end + +describe file('/etc/invalid-mount') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_root', + :type => 'ext4', + :options => { + :rw => true, + :mode => 620, + } + ) + end +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should_not be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_root', + :type => 'ext4', + :options => { + :rw => true, + :mode => 620, + :bind => true, + } + ) + end +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should_not be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_root', + :type => 'ext4', + :options => { + :rw => true, + } + ) + end +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should_not be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_roooooooooot', + :type => 'ext4', + :options => { + :rw => true, + :mode => 620, + } + ) + end +end + +describe file('/etc/invalid-mount') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.only_with( :type => 'ext4' ) } +end + +describe file('/etc/services') do + it { should match_md5checksum '35435ea447c19f0ea5ef971837ab9ced' } + its(:command) { should eq "md5sum /etc/services | grep -iw -- \\^35435ea447c19f0ea5ef971837ab9ced" } +end + +describe file('invalid-file') do + it { should_not match_md5checksum 'INVALIDMD5CHECKSUM' } +end + +describe file('/etc/services') do + it { should match_sha256checksum '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' } + its(:command) { should eq "sha256sum /etc/services | grep -iw -- \\^0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a" } +end + +describe file('invalid-file') do + it { should_not match_sha256checksum 'INVALIDSHA256CHECKSUM' } +end diff --git a/spec/aix/group_spec.rb b/spec/aix/group_spec.rb new file mode 100644 index 00000000..994945b2 --- /dev/null +++ b/spec/aix/group_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe group('root') do + it { should exist } + its(:command) { should eq "getent group | grep -wq -- root" } +end + +describe group('invalid-group') do + it { should_not exist } +end + +describe group('root') do + it { should have_gid 0 } + its(:command) { should eq "getent group | grep -w -- \\^root | cut -f 3 -d ':' | grep -w -- 0" } +end + +describe group('root') do + it { should_not have_gid 'invalid-gid' } +end diff --git a/spec/aix/host_spec.rb b/spec/aix/host_spec.rb new file mode 100644 index 00000000..913aba67 --- /dev/null +++ b/spec/aix/host_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe host('127.0.0.1') do + it { should be_resolvable } + its(:command) { should eq "getent hosts 127.0.0.1" } +end + +describe host('invalid-name') do + it { should_not be_resolvable } +end + +describe host('127.0.0.1') do + it { should be_resolvable.by('hosts') } + its(:command) { should eq "grep -w -- 127.0.0.1 /etc/hosts" } +end + +describe host('invalid-name') do + it { should_not be_resolvable.by('hosts') } +end + +describe host('127.0.0.1') do + it { should be_resolvable.by('dns') } + its(:command) { should eq "nslookup -timeout=1 127.0.0.1" } +end + +describe host('invalid-name') do + it { should_not be_resolvable.by('dns') } +end + +describe host('127.0.0.1') do + it { should be_reachable } + its(:command) { should eq "ping -n 127.0.0.1 -w 5 -c 2" } +end + +describe host('invalid-host') do + it { should_not be_reachable } +end + +describe host('127.0.0.1') do + it { should be_reachable.with(:proto => "icmp", :timeout=> 1) } + its(:command) { should eq "ping -n 127.0.0.1 -w 1 -c 2" } +end + +describe host('127.0.0.1') do + it { should be_reachable.with(:proto => "tcp", :port => 22, :timeout=> 1) } + its(:command) { should eq "nc -vvvvzt 127.0.0.1 22 -w 1" } +end + +describe host('127.0.0.1') do + it { should be_reachable.with(:proto => "udp", :port => 53, :timeout=> 1) } + its(:command) { should eq "nc -vvvvzu 127.0.0.1 53 -w 1" } +end + +describe host('invalid-host') do + it { should_not be_reachable.with(:proto => "udp", :port => 53, :timeout=> 1) } +end diff --git a/spec/aix/interface_spec.rb b/spec/aix/interface_spec.rb new file mode 100644 index 00000000..9118092e --- /dev/null +++ b/spec/aix/interface_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe interface('eth0') do + let(:stdout) { '1000' } + its(:speed) { should eq 1000 } + its(:command) { should eq "ethtool eth0 | grep Speed | gawk '{print gensub(/Speed: ([0-9]+)Mb\\/s/,\"\\\\1\",\"\")}'" } +end + +describe interface('eth0') do + it { should have_ipv4_address("192.168.10.10") } + its(:command) { should eq "ip addr show eth0 | grep 'inet 192\\.168\\.10\\.10/'" } +end + +describe interface('eth0') do + it { should have_ipv4_address("192.168.10.10/24") } + its(:command) { should eq "ip addr show eth0 | grep 'inet 192\\.168\\.10\\.10/24 '" } +end + +describe interface('invalid-interface') do + let(:stdout) { '1000' } + its(:speed) { should_not eq 100 } +end diff --git a/spec/aix/iptables_spec.rb b/spec/aix/iptables_spec.rb new file mode 100644 index 00000000..aea079be --- /dev/null +++ b/spec/aix/iptables_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe iptables do + it { should have_rule '-P INPUT ACCEPT' } + its(:command) { should eq "iptables -S | grep -- -P\\ INPUT\\ ACCEPT" } +end + +describe iptables do + it { should_not have_rule 'invalid-rule' } +end + +describe iptables do + it { should have_rule('-P INPUT ACCEPT').with_table('mangle').with_chain('INPUT') } + its(:command) { should eq "iptables -t mangle -S INPUT | grep -- -P\\ INPUT\\ ACCEPT" } +end + +describe iptables do + it { should_not have_rule('invalid-rule').with_table('mangle').with_chain('INPUT') } +end diff --git a/spec/aix/kernel_module_spec.rb b/spec/aix/kernel_module_spec.rb new file mode 100644 index 00000000..d9708318 --- /dev/null +++ b/spec/aix/kernel_module_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe kernel_module('lp') do + it { should be_loaded } + its(:command) { should eq "lsmod | grep ^lp" } +end + +describe kernel_module('invalid-module') do + it { should_not be_loaded } +end diff --git a/spec/aix/linux_kernel_parameter_spec.rb b/spec/aix/linux_kernel_parameter_spec.rb new file mode 100644 index 00000000..b04e52a8 --- /dev/null +++ b/spec/aix/linux_kernel_parameter_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe linux_kernel_parameter('net.ipv4.tcp_syncookies') do + let(:stdout) { "1\n" } + its(:value) { should eq 1 } + its(:command) { should eq "/sbin/sysctl -q -n net.ipv4.tcp_syncookies" } +end + +describe linux_kernel_parameter('net.ipv4.tcp_syncookies') do + let(:stdout) { "1\n" } + its(:value) { should_not eq 2 } +end + +describe linux_kernel_parameter('kernel.osrelease') do + let(:stdout) { "2.6.32-131.0.15.el6.x86_64\n" } + its(:value) { should eq "2.6.32-131.0.15.el6.x86_64" } + its(:command) { should eq "/sbin/sysctl -q -n kernel.osrelease" } +end + +describe linux_kernel_parameter('kernel.osrelease') do + let(:stdout) { "2.6.32-131.0.15.el6.x86_64\n" } + its(:value) { should_not eq "2.6.32-131.0.15.el6.i386" } +end + +describe linux_kernel_parameter('net.ipv4.tcp_wmem') do + let(:stdout) { "4096 16384 4194304\n" } + its(:value) { should match /16384/ } + its(:command) { should eq "/sbin/sysctl -q -n net.ipv4.tcp_wmem" } +end + +describe linux_kernel_parameter('net.ipv4.tcp_wmem') do + let(:stdout) { "4096 16384 4194304\n" } + its(:value) { should_not match /123456/ } +end diff --git a/spec/aix/package_spec.rb b/spec/aix/package_spec.rb new file mode 100644 index 00000000..ee1cd44e --- /dev/null +++ b/spec/aix/package_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe package('httpd') do + it { should be_installed } + its(:command) { should eq "rpm -q httpd" } +end + +describe package('invalid-package') do + it { should_not be_installed } +end + +package('invalid-package') do + it { should_not be_installed.by('rpm') } +end + +describe package('httpd') do + it { should be_installed.with_version('2.2.15-28.el6') } + its(:command) { should eq "rpm -q httpd | grep -w -- 2.2.15-28.el6" } +end + +describe package('httpd') do + it { should be_installed.by('rpm').with_version('2.2.15-28.el6') } + its(:command) { should eq "rpm -q httpd | grep -w -- 2.2.15-28.el6" } +end + +describe package('httpd') do + it { should_not be_installed.with_version('invalid-version') } +end + +describe package('jekyll') do + it { should be_installed.by('gem') } + its(:command) { should eq "gem list --local | grep -w -- \\^jekyll" } +end + +describe package('invalid-gem') do + it { should_not be_installed.by('gem') } +end + +describe package('jekyll') do + it { should be_installed.by('gem').with_version('1.1.1') } + its(:command) { should eq "gem list --local | grep -w -- \\^jekyll | grep -w -- 1.1.1" } +end + +describe package('jekyll') do + it { should_not be_installed.by('gem').with_version('invalid-version') } +end + +describe package('bower') do + it { should be_installed.by('npm') } + its(:command) { should eq "npm ls bower -g" } +end + +describe package('invalid-npm-package') do + it { should_not be_installed.by('npm') } +end + +describe package('bower') do + it { should be_installed.by('npm').with_version('0.9.2') } + its(:command) { should eq "npm ls bower -g | grep -w -- 0.9.2" } +end + +describe package('bower') do + it { should_not be_installed.by('npm').with_version('invalid-version') } +end + + +describe package('mongo') do + it { should be_installed.by('pecl') } + its(:command) { should eq "pecl list | grep -w -- \\^mongo" } +end + +describe package('invalid-pecl') do + it { should_not be_installed.by('pecl') } +end + +describe package('mongo') do + it { should be_installed.by('pecl').with_version('1.4.1') } + its(:command) { should eq "pecl list | grep -w -- \\^mongo | grep -w -- 1.4.1" } +end + +describe package('mongo') do + it { should_not be_installed.by('pecl').with_version('invalid-version') } +end + +describe package('supervisor') do + it { should be_installed.by('pip').with_version('3.0') } + its(:command) { should eq "pip list | grep -w -- \\^supervisor | grep -w -- 3.0" } +end + +describe package('invalid-pip') do + it { should_not be_installed.by('pip').with_version('invalid-version') } +end diff --git a/spec/aix/php_config_spec.rb b/spec/aix/php_config_spec.rb new file mode 100644 index 00000000..56b2f37f --- /dev/null +++ b/spec/aix/php_config_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe php_config('default_mimetype') do + let(:stdout) { 'text/html' } + its(:value) { should eq 'text/html' } + its(:command) { should eq "php -r 'echo get_cfg_var( \"default_mimetype\" );'" } +end + +describe php_config('default_mimetype') do + let(:stdout) { 'text/html' } + its(:value) { should_not eq 'text/plain' } +end + +describe php_config('session.cache_expire') do + let(:stdout) { '180' } + its(:value) { should eq 180 } + its(:command) { should eq "php -r 'echo get_cfg_var( \"session.cache_expire\" );'" } +end + +describe php_config('session.cache_expire') do + let(:stdout) { '180' } + its(:value) { should_not eq 360 } +end + +describe php_config('mbstring.http_output_conv_mimetypes') do + let(:stdout) { 'application' } + its(:value) { should match /application/ } + its(:command) { should eq "php -r 'echo get_cfg_var( \"mbstring.http_output_conv_mimetypes\" );'" } +end + +describe php_config('mbstring.http_output_conv_mimetypes') do + let(:stdout) { 'application' } + its(:value) { should_not match /html/ } +end diff --git a/spec/aix/port_spec.rb b/spec/aix/port_spec.rb new file mode 100644 index 00000000..f427a38f --- /dev/null +++ b/spec/aix/port_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe port(80) do + it { should be_listening } + its(:command) { should eq 'netstat -tunl | grep -- :80\\ ' } +end + +describe port('invalid') do + it { should_not be_listening } +end + +describe port(80) do + it { should be_listening.with("tcp") } + its(:command) { should eq 'netstat -tunl | grep -- \\^tcp\\ .\\*:80\\ ' } +end + +describe port(123) do + it { should be_listening.with("udp") } + its(:command) { should eq 'netstat -tunl | grep -- \\^udp\\ .\\*:123\\ ' } +end + +describe port(80) do + it { + expect { + should be_listening.with('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_listening` matcher doesn\'t support/) + } +end diff --git a/spec/aix/routing_table_spec.rb b/spec/aix/routing_table_spec.rb new file mode 100644 index 00000000..6c69863d --- /dev/null +++ b/spec/aix/routing_table_spec.rb @@ -0,0 +1,120 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe routing_table do + let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it { should have_entry( :destination => '192.168.100.0/24' ) } + its(:command) { should eq "ip route | grep -E '^192.168.100.0/24 |^default '" } +end + +describe routing_table do + let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it { should_not have_entry( :destination => '192.168.100.100/24' ) } + its(:command) { should eq "ip route | grep -E '^192.168.100.100/24 |^default '" } +end + +describe routing_table do + let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it do + should have_entry( + :destination => '192.168.100.0/24', + :gateway => '192.168.100.1' + ) + end + + it do + should have_entry( + :destination => '192.168.100.0/24', + :gateway => '192.168.100.1', + :interface => 'eth1' + ) + end + + it do + should_not have_entry( + :gateway => '192.168.100.1', + :interface => 'eth1' + ) + end + + it do + should_not have_entry( + :destination => '192.168.100.0/32', + :gateway => '192.168.100.1', + :interface => 'eth1' + ) + end +end + +describe routing_table do + let(:stdout) { "192.168.200.0/24 via 192.168.200.1 dev eth0 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it { should have_entry( :destination => '192.168.200.0/24' ) } + it { should_not have_entry( :destination => '192.168.200.200/24' ) } + + it do + should have_entry( + :destination => '192.168.200.0/24', + :gateway => '192.168.200.1' + ) + end + + it do + should have_entry( + :destination => '192.168.200.0/24', + :gateway => '192.168.200.1', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :gateway => '192.168.200.1', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :destination => '192.168.200.0/32', + :gateway => '192.168.200.1', + :interface => 'eth0' + ) + end +end + +describe routing_table do + let(:stdout) { "default via 10.0.2.2 dev eth0 \r\n" } + it { should have_entry( :destination => 'default' ) } + it { should_not have_entry( :destination => 'defaulth' ) } + + it do + should have_entry( + :destination => 'default', + :gateway => '10.0.2.2' + ) + end + + it do + should have_entry( + :destination => 'default', + :gateway => '10.0.2.2', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :gateway => '10.0.2.2', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :destination => 'default', + :gateway => '10.0.2.1', + :interface => 'eth0' + ) + end +end diff --git a/spec/aix/selinux_spec.rb b/spec/aix/selinux_spec.rb new file mode 100644 index 00000000..72809877 --- /dev/null +++ b/spec/aix/selinux_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe selinux do + it { should be_enforcing } + its(:command) { should eq "getenforce | grep -i -- enforcing && grep -i -- ^SELINUX=enforcing$ /etc/selinux/config" } +end + +describe selinux do + it { should be_permissive } + its(:command) { should eq "getenforce | grep -i -- permissive && grep -i -- ^SELINUX=permissive$ /etc/selinux/config" } +end + +describe selinux do + it { should be_disabled } + its(:command) { should eq "test ! -f /etc/selinux/config || (getenforce | grep -i -- disabled && grep -i -- ^SELINUX=disabled$ /etc/selinux/config)" } +end diff --git a/spec/aix/service_spec.rb b/spec/aix/service_spec.rb new file mode 100644 index 00000000..925ee788 --- /dev/null +++ b/spec/aix/service_spec.rb @@ -0,0 +1,93 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe service('sshd') do + it { should be_enabled } + its(:command) { should eq "chkconfig --list sshd | grep 3:on" } +end + +describe service('invalid-service') do + it { should_not be_enabled } +end + +describe service('sshd') do + it { should be_enabled.with_level(4) } + its(:command) { should eq "chkconfig --list sshd | grep 4:on" } +end + +describe service('invalid-service') do + it { should_not be_enabled.with_level(4) } +end + +describe service('sshd') do + it { should be_running } + its(:command) { should eq "service sshd status" } +end + +describe service('invalid-daemon') do + it { should_not be_running } +end + +describe service('sshd') do + let(:stdout) { "sshd is stopped\r\n" } + it { should be_running } +end + +describe service('sshd') do + it { should be_running.under('supervisor') } + its(:command) { should eq "supervisorctl status sshd | grep RUNNING" } +end + +describe service('invalid-daemon') do + it { should_not be_running.under('supervisor') } +end + +describe service('sshd') do + it { should be_running.under('upstart') } + its(:command) { should eq "initctl status sshd | grep running" } +end + +describe service('invalid-daemon') do + it { should_not be_running.under('upstart') } +end + +describe service('sshd') do + it { + expect { + should be_running.under('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_running` matcher doesn\'t support/) + } +end + +describe service('sshd') do + let(:stdout) { "Process 'sshd'\r\n status running\r\n monitoring status monitored" } + it { should be_monitored_by('monit') } + its(:command) { should eq "monit status" } +end + +describe service('sshd') do + let(:stdout) { "Process 'sshd'\r\n status not monitored\r\n monitoring status not monitored" } + it { should_not be_monitored_by('monit') } +end + +describe service('invalid-daemon') do + it { should_not be_monitored_by('monit') } +end + +describe service('unicorn') do + it { should be_monitored_by('god') } + its(:command) { should eq "god status unicorn" } +end + +describe service('invalid-daemon') do + it { should_not be_monitored_by('god') } +end + +describe service('sshd') do + it { + expect { + should be_monitored_by('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_monitored_by` matcher doesn\'t support/) + } +end diff --git a/spec/aix/user_spec.rb b/spec/aix/user_spec.rb new file mode 100644 index 00000000..0049a3fe --- /dev/null +++ b/spec/aix/user_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + + +describe user('root') do + it { should exist } + its(:command) { should eq "id root" } +end + +describe user('invalid-user') do + it { should_not exist } +end + +describe user('root') do + it { should belong_to_group 'root' } + its(:command) { should eq "id root | awk '{print $3}' | grep -- root" } +end + +describe user('root') do + it { should_not belong_to_group 'invalid-group' } +end + +describe user('root') do + it { should have_uid 0 } + its(:command) { should eq "id root | grep -- \\^uid\\=0\\(" } +end + +describe user('root') do + it { should_not have_uid 'invalid-uid' } +end + +describe user('root') do + it { should have_login_shell '/bin/bash' } + its(:command) { should eq "getent passwd root | cut -f 7 -d ':' | grep -w -- /bin/bash" } +end + +describe user('root') do + it { should_not have_login_shell 'invalid-login-shell' } +end + +describe user('root') do + it { should have_home_directory '/root' } + its(:command) { should eq "getent passwd root | cut -f 6 -d ':' | grep -w -- /root" } +end + +describe user('root') do + it { should_not have_home_directory 'invalid-home-directory' } +end + +describe user('root') do + it { should have_authorized_key 'ssh-rsa ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH foo@bar.local' } + its(:command) { should eq "grep -w -- ssh-rsa\\ ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH ~root/.ssh/authorized_keys" } +end + +describe user('root') do + it { should_not have_authorized_key 'invalid-key' } +end diff --git a/spec/aix/yumrepo_spec.rb b/spec/aix/yumrepo_spec.rb new file mode 100644 index 00000000..894fdd84 --- /dev/null +++ b/spec/aix/yumrepo_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe 'Serverspec yumrepo matchers of Red Hat family' do + describe 'exist' do + describe yumrepo('epel') do + it { should exist } + end + + describe yumrepo('invalid-repository') do + it { should_not exist } + end + end + + describe 'be_enabled' do + describe yumrepo('epel') do + it { should be_enabled } + end + + describe yumrepo('invalid-repository') do + it { should_not be_enabled } + end + end +end diff --git a/spec/aix/zfs_spec.rb b/spec/aix/zfs_spec.rb new file mode 100644 index 00000000..349736a4 --- /dev/null +++ b/spec/aix/zfs_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +include Serverspec::Helper::RedHat + +describe zfs('rpool') do + it { should exist } + its(:command) { should eq "zfs list -H rpool" } +end + +describe zfs('rpool') do + it { should have_property 'mountpoint' => '/rpool' } + its(:command) { should eq "zfs list -H -o mountpoint rpool | grep -- \\^/rpool\\$" } +end + +describe zfs('rpool') do + it { should have_property 'mountpoint' => '/rpool', 'compression' => 'off' } + its(:command) { should eq "zfs list -H -o compression rpool | grep -- \\^off\\$ && zfs list -H -o mountpoint rpool | grep -- \\^/rpool\\$" } +end From cffc1f8131bc6eb995885122ce52fd047e1d6eb4 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Wed, 11 Sep 2013 10:22:45 +0100 Subject: [PATCH 08/43] Update user commands for aix --- lib/serverspec.rb | 2 +- lib/serverspec/commands/aix.rb | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/serverspec.rb b/lib/serverspec.rb index 550762c3..e013e310 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -35,7 +35,7 @@ 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::Aix, :os => :aix) c.include(Serverspec::Helper::Solaris, :os => :solaris) c.include(Serverspec::Helper::Solaris10, :os => :solaris10) c.include(Serverspec::Helper::Solaris11, :os => :solaris11) diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index f96f8d20..b9b3efcb 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -3,9 +3,6 @@ module Serverspec module Commands class Aix < Base -# -# SJT Aix class -# class NotImplementedError < Exception; end def check_access_by_user(file, user, access) @@ -30,6 +27,10 @@ def check_listening(port) #"netstat -an -f inet | awk '{print $4}' | grep -- #{escape(regexp)}" end + def check_belonging_group(user, group) + "groups #{escape(user)} | awk -F':' '{print $2}' | grep -- #{escape(group)}" + end + end end From e1cea317ceafa35bc9346a224f3d95e0c193ce3f Mon Sep 17 00:00:00 2001 From: worldostugs Date: Wed, 11 Sep 2013 13:08:35 +0100 Subject: [PATCH 09/43] aix tweak --- lib/serverspec/commands/aix.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index b9b3efcb..77f7ef9d 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -28,9 +28,21 @@ def check_listening(port) end def check_belonging_group(user, group) - "groups #{escape(user)} | awk -F':' '{print $2}' | grep -- #{escape(group)}" + "lsuser -a groups #{escape(user)} | awk -F'=' '{print $2}'| sed -e 's/,/ /g' |grep -w -- #{escape(group)}" end + def check_gid(group, gid) + regexp = "^#{group}" + "cat etc/group | grep -w -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}" + end + + def check_login_shell(user, path_to_shell) + "lsuser -a shell #{escape(user)} |awk -F'=' '{print $2} | grep -w -- #{escape(path_to_shell)}" + end + + def check_home_directory(user, path_to_home) + "lsuser -a home #{escape(user)} | awk -F'=''{print $2}' | grep -w -- #{escape(path_to_home)}" + end end end From b89b22abe721ceaa14b8734c9a8037e72da5e3d7 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Wed, 11 Sep 2013 13:15:48 +0100 Subject: [PATCH 10/43] Aix tweaks --- lib/serverspec/commands/aix.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index 77f7ef9d..36b9366b 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -37,11 +37,11 @@ def check_gid(group, gid) end def check_login_shell(user, path_to_shell) - "lsuser -a shell #{escape(user)} |awk -F'=' '{print $2} | grep -w -- #{escape(path_to_shell)}" + "lsuser -a shell #{escape(user)} |awk -F'=' '{print $2}' | grep -w -- #{escape(path_to_shell)}" end def check_home_directory(user, path_to_home) - "lsuser -a home #{escape(user)} | awk -F'=''{print $2}' | grep -w -- #{escape(path_to_home)}" + "lsuser -a home #{escape(user)} | awk -F'=' '{print $2}' | grep -w -- #{escape(path_to_home)}" end end From 982417f65c03e127006cab78675b7c08038481c7 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Wed, 11 Sep 2013 15:07:20 +0100 Subject: [PATCH 11/43] aix support for package versions --- lib/serverspec/commands/aix.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index 36b9366b..ca9d5c85 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -17,8 +17,13 @@ def check_running(service) "ps -ef | grep -v grep | grep #{escape(service)}" end - def check_installed(package,version=nil) - "lslpp -L #{escape(package)}" + def check_installed(package,version) + + if version + "lslpp -L #{escape(package)} | awk '{print $2}' | grep -w -- #{version}" + else + "lslpp -L #{escape(package)}" + end end def check_listening(port) From 0b19aa56a49e785715f4eb0beb64a4a270eb4b88 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Wed, 11 Sep 2013 16:04:48 +0100 Subject: [PATCH 12/43] fix aix file mode checks --- lib/serverspec/commands/aix.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index ca9d5c85..62501da9 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -49,6 +49,22 @@ def check_home_directory(user, path_to_home) "lsuser -a home #{escape(user)} | awk -F'=' '{print $2}' | grep -w -- #{escape(path_to_home)}" end + def check_mode(file, mode) + regexp = "^#{mode}$" + echo "#{escape(file)}" | ruby -e 'puts sprintf("%o",File.stat(STDIN.read.chomp).mode).slice!(3,3) | grep -- #{escape(regexp)}"' + end + + def check_owner(file, owner) + regexp = "^#{owner}$" + "stat -c %U #{escape(file)} | grep -- #{escape(regexp)}" + end + + def check_grouped(file, group) + regexp = "^#{group}$" + "stat -c %G #{escape(file)} | grep -- #{escape(regexp)}" + end + + end end end From 44ca09e93017df56e06a132c6e240ffe3eea7b63 Mon Sep 17 00:00:00 2001 From: worldostugs Date: Thu, 12 Sep 2013 14:47:29 +0100 Subject: [PATCH 13/43] aix tweaks --- lib/serverspec/commands/aix.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index 62501da9..69da0a12 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -50,18 +50,17 @@ def check_home_directory(user, path_to_home) end def check_mode(file, mode) - regexp = "^#{mode}$" - echo "#{escape(file)}" | ruby -e 'puts sprintf("%o",File.stat(STDIN.read.chomp).mode).slice!(3,3) | grep -- #{escape(regexp)}"' + false unless sprintf("%o",File.stat(file).mode).slice!(3,3) == mode end def check_owner(file, owner) regexp = "^#{owner}$" - "stat -c %U #{escape(file)} | grep -- #{escape(regexp)}" + "ls -al #{escape(file)} | awk '{print $3}' | grep -- #{escape(regexp)}" end def check_grouped(file, group) regexp = "^#{group}$" - "stat -c %G #{escape(file)} | grep -- #{escape(regexp)}" + "ls -al #{escape(file)} | awk '{print $4}' | grep -- #{escape(regexp)}" end From 02436d525b4e4f85e80125fae94040c3e53f3379 Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Tue, 17 Sep 2013 16:39:39 +1000 Subject: [PATCH 14/43] added cmd backend --- .gitignore | 1 + Rakefile | 14 +++++------ lib/serverspec/backend/base.rb | 31 +++++++++++++++++++++++ lib/serverspec/backend/cmd.rb | 35 ++++++++++++++++++++++++++ lib/serverspec/helper/cmd.rb | 15 +++++++++++ spec/backend/cmd/configuration_spec.rb | 9 +++++++ 6 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 lib/serverspec/backend/base.rb create mode 100644 lib/serverspec/backend/cmd.rb create mode 100644 lib/serverspec/helper/cmd.rb create mode 100644 spec/backend/cmd/configuration_spec.rb diff --git a/.gitignore b/.gitignore index 9eedf918..47939cc4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.swp .bundle .rvmrc +.versions.conf .config .yardoc .rspec diff --git a/Rakefile b/Rakefile index a44099c5..d93167fe 100644 --- a/Rakefile +++ b/Rakefile @@ -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 solaris solaris10 solaris11 smartos windows) - 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| @@ -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 diff --git a/lib/serverspec/backend/base.rb b/lib/serverspec/backend/base.rb new file mode 100644 index 00000000..4f07a8a2 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/lib/serverspec/backend/cmd.rb b/lib/serverspec/backend/cmd.rb new file mode 100644 index 00000000..e2137a60 --- /dev/null +++ b/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 diff --git a/lib/serverspec/helper/cmd.rb b/lib/serverspec/helper/cmd.rb new file mode 100644 index 00000000..a4bb9dc0 --- /dev/null +++ b/lib/serverspec/helper/cmd.rb @@ -0,0 +1,15 @@ +module Serverspec + module Helper + module Cmd + def backend(commands_object=nil) + if ! respond_to?(:commands) + commands_object = Serverspec::Commands::Windows.new + end + instance = Serverspec::Backend::Cmd.instance + instance.set_commands(commands_object || commands) + instance + end + end + end +end + diff --git a/spec/backend/cmd/configuration_spec.rb b/spec/backend/cmd/configuration_spec.rb new file mode 100644 index 00000000..75b10ac7 --- /dev/null +++ b/spec/backend/cmd/configuration_spec.rb @@ -0,0 +1,9 @@ +require 'spec_helper' +require 'support/powershell_command_runner' + +include Serverspec::Helper::Cmd +include Serverspec::Helper::Windows + +describe "Cmd" do + it_behaves_like "a powershell command runner" +end From b723e647e5721befe0e8662b0bba3da4cd466187 Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Tue, 17 Sep 2013 16:42:10 +1000 Subject: [PATCH 15/43] ignoring mac .DS_Store files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 47939cc4..75251011 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ test/version_tmp tmp Vagrantfile vendor/ +.DS_Store \ No newline at end of file From 4ac940064d51714933fa83463243981d69a82199 Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Tue, 17 Sep 2013 16:48:14 +1000 Subject: [PATCH 16/43] adding windows powershell commands --- lib/serverspec/backend/powershell/command.rb | 36 +++ .../backend/powershell/script_helper.rb | 61 +++++ .../support/check_file_access_rules.ps1 | 12 + .../backend/powershell/support/crop_text.ps1 | 11 + .../backend/powershell/support/find_group.ps1 | 8 + .../support/find_installed_application.ps1 | 7 + .../powershell/support/find_service.ps1 | 5 + .../backend/powershell/support/find_user.ps1 | 8 + .../powershell/support/find_usergroup.ps1 | 9 + .../powershell/support/is_port_listening.ps1 | 13 ++ lib/serverspec/commands/windows.rb | 212 ++++++++++++++++++ lib/serverspec/helper.rb | 3 + lib/serverspec/helper/windows.rb | 9 + spec/backend/powershell/script_helper_spec.rb | 77 +++++++ spec/support/powershell_command_runner.rb | 52 +++++ 15 files changed, 523 insertions(+) create mode 100644 lib/serverspec/backend/powershell/command.rb create mode 100644 lib/serverspec/backend/powershell/script_helper.rb create mode 100644 lib/serverspec/backend/powershell/support/check_file_access_rules.ps1 create mode 100644 lib/serverspec/backend/powershell/support/crop_text.ps1 create mode 100644 lib/serverspec/backend/powershell/support/find_group.ps1 create mode 100644 lib/serverspec/backend/powershell/support/find_installed_application.ps1 create mode 100644 lib/serverspec/backend/powershell/support/find_service.ps1 create mode 100644 lib/serverspec/backend/powershell/support/find_user.ps1 create mode 100644 lib/serverspec/backend/powershell/support/find_usergroup.ps1 create mode 100644 lib/serverspec/backend/powershell/support/is_port_listening.ps1 create mode 100644 lib/serverspec/commands/windows.rb create mode 100644 lib/serverspec/helper/windows.rb create mode 100644 spec/backend/powershell/script_helper_spec.rb create mode 100644 spec/support/powershell_command_runner.rb diff --git a/lib/serverspec/backend/powershell/command.rb b/lib/serverspec/backend/powershell/command.rb new file mode 100644 index 00000000..44a48cbb --- /dev/null +++ b/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 diff --git a/lib/serverspec/backend/powershell/script_helper.rb b/lib/serverspec/backend/powershell/script_helper.rb new file mode 100644 index 00000000..8eb3fcf3 --- /dev/null +++ b/lib/serverspec/backend/powershell/script_helper.rb @@ -0,0 +1,61 @@ +module Serverspec + module Backend + module PowerShell + module ScriptHelper + def build_command(cmd) + path = Serverspec.configuration.path || RSpec.configuration.path + if path + cmd.strip! + cmd = +<<-EOF +$env:path = "#{path};$env:path" +#{cmd} +EOF + end + cmd + end + + def add_pre_command(cmd) + path = Serverspec.configuration.path || RSpec.configuration.path + if Serverspec.configuration.pre_command + cmd.strip! + cmd = +<<-EOF +if (#{Serverspec.configuration.pre_command}) +{ +#{cmd} +} +EOF + cmd = "$env:path = \"#{path};$env:path\"\n#{cmd}" if path + end + cmd + end + + def encode_script script + script_text = script.chars.to_a.join("\x00").chomp + script_text << "\x00" unless script_text[-1].eql? "\x00" + script_text = script_text.encode('ASCII-8BIT') + Base64.strict_encode64(script_text) + end + + def create_script command + script = build_command(command.script) + script = add_pre_command(script) + ps_functions = command.import_functions.map { |f| File.read(File.join(File.dirname(__FILE__), 'support', f)) } + <<-EOF +$exitCode = 1 +try { + #{ps_functions.join("\n")} + $success = (#{script}) + if ($success -is [Boolean] -and $success) { $exitCode = 0 } +} catch { + Write-Output $_.Exception.Message +} +Write-Output "Exiting with code: $exitCode" +exit $exitCode + EOF + end + end + end + end +end \ No newline at end of file diff --git a/lib/serverspec/backend/powershell/support/check_file_access_rules.ps1 b/lib/serverspec/backend/powershell/support/check_file_access_rules.ps1 new file mode 100644 index 00000000..15cbe196 --- /dev/null +++ b/lib/serverspec/backend/powershell/support/check_file_access_rules.ps1 @@ -0,0 +1,12 @@ +function CheckFileAccessRules +{ + param($path, $identity, $rules) + + $result = $false + $accessRules = (Get-Acl $path).access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq $identity } + if ($accessRules) { + $match = $accessRules.FileSystemRights.ToString() -Split (', ') | ?{$rules -contains $_} + $result = $match -ne $null -or $match.length -gt 0 + } + $result +} diff --git a/lib/serverspec/backend/powershell/support/crop_text.ps1 b/lib/serverspec/backend/powershell/support/crop_text.ps1 new file mode 100644 index 00000000..59f1d232 --- /dev/null +++ b/lib/serverspec/backend/powershell/support/crop_text.ps1 @@ -0,0 +1,11 @@ +function CropText +{ + param($text, $fromPattern, $toPattern) + + $from, $to = ([regex]::matches($text, $fromPattern)), ([regex]::matches($text, $toPattern)) + if ($from.count -gt 0 -and $to.count -gt 0) { + $text.substring($from[0].index, $to[0].index + $to[0].length - $from[0].index) + } else { + "" + } +} diff --git a/lib/serverspec/backend/powershell/support/find_group.ps1 b/lib/serverspec/backend/powershell/support/find_group.ps1 new file mode 100644 index 00000000..c8134389 --- /dev/null +++ b/lib/serverspec/backend/powershell/support/find_group.ps1 @@ -0,0 +1,8 @@ +function FindGroup +{ + param($groupName, $domain) + if ($domain -eq $null) {$selectionCriteria = " and LocalAccount = true"} + else {$selectionCriteria = " and Domain = '$domain'"} + + Get-WmiObject Win32_Group -filter "Name = '$groupName' $selectionCriteria" +} \ No newline at end of file diff --git a/lib/serverspec/backend/powershell/support/find_installed_application.ps1 b/lib/serverspec/backend/powershell/support/find_installed_application.ps1 new file mode 100644 index 00000000..ee3ce752 --- /dev/null +++ b/lib/serverspec/backend/powershell/support/find_installed_application.ps1 @@ -0,0 +1,7 @@ +function FindInstalledApplication +{ + param($appName, $appVersion) + $selectionCriteria = "(Name like '$appName' or PackageName like '$appName') and InstallState = 5" + if ($appVersion -ne $null) { $selectionCriteria += " and version = '$appVersion'"} + Get-WmiObject Win32_Product -filter $selectionCriteria +} \ No newline at end of file diff --git a/lib/serverspec/backend/powershell/support/find_service.ps1 b/lib/serverspec/backend/powershell/support/find_service.ps1 new file mode 100644 index 00000000..e779770e --- /dev/null +++ b/lib/serverspec/backend/powershell/support/find_service.ps1 @@ -0,0 +1,5 @@ +function FindService +{ + param($name) + Get-WmiObject Win32_Service | Where-Object {$_.serviceName -eq $name -or $_.displayName -eq $name} +} \ No newline at end of file diff --git a/lib/serverspec/backend/powershell/support/find_user.ps1 b/lib/serverspec/backend/powershell/support/find_user.ps1 new file mode 100644 index 00000000..b60c11fe --- /dev/null +++ b/lib/serverspec/backend/powershell/support/find_user.ps1 @@ -0,0 +1,8 @@ +function FindUser +{ + param($userName, $domain) + if ($domain -eq $null) {$selectionCriteria = " and LocalAccount = true"} + else {$selectionCriteria = " and Domain = '$domain'"} + + Get-WmiObject Win32_UserAccount -filter "Name = '$userName' $selectionCriteria" +} diff --git a/lib/serverspec/backend/powershell/support/find_usergroup.ps1 b/lib/serverspec/backend/powershell/support/find_usergroup.ps1 new file mode 100644 index 00000000..968c2f28 --- /dev/null +++ b/lib/serverspec/backend/powershell/support/find_usergroup.ps1 @@ -0,0 +1,9 @@ +function FindUserGroup +{ + param($userName, $groupName, $userDomain, $groupDomain) + $user = FindUser -userName $userName -domain $userDomain + $group = FindGroup -groupName $groupName -domain $groupDomain + if ($user -and $group) { + Get-WmiObject Win32_GroupUser -filter ("GroupComponent = 'Win32_Group.Domain=`"" + $group.domain + "`",Name=`"" + $group.name + "`"' and PartComponent = 'Win32_UserAccount.Domain=`"" + $user.domain + "`",Name=`"" + $user.name + "`"'") + } +} \ No newline at end of file diff --git a/lib/serverspec/backend/powershell/support/is_port_listening.ps1 b/lib/serverspec/backend/powershell/support/is_port_listening.ps1 new file mode 100644 index 00000000..a76634f6 --- /dev/null +++ b/lib/serverspec/backend/powershell/support/is_port_listening.ps1 @@ -0,0 +1,13 @@ +function IsPortListening +{ + param($portNumber, $protocol) + $netstatOutput = netstat -an | Out-String + $networkIPs = (Get-WmiObject Win32_NetworkAdapterConfiguration | ? {$_.IPEnabled}) | %{ $_.IPAddress[0] } + foreach ($ipaddress in $networkIPs) + { + $matchExpression = ("$ipaddress" + ":" + $portNumber) + if ($protocol) { $matchExpression = ($protocol.toUpper() + "\s+$matchExpression") } + if ($netstatOutput -match $matchExpression) { return $true } + } + $false +} \ No newline at end of file diff --git a/lib/serverspec/commands/windows.rb b/lib/serverspec/commands/windows.rb new file mode 100644 index 00000000..e599e35e --- /dev/null +++ b/lib/serverspec/commands/windows.rb @@ -0,0 +1,212 @@ +module Serverspec + module Commands + class Windows + class NotSupportedError < Exception; end + REGISTRY_KEY_TYPES = { + :type_string => 'String', + :type_binary => 'Binary', + :type_dword => 'DWord', + :type_qword => 'QWord', + :type_multistring => 'MultiString', + :type_expandstring => 'ExpandString' + } + + def method_missing method, *args + raise NotSupportedError.new "#{method} currently not supported in Windows os" if method =~ /^check_.+/ + super(method, *args) + end + + def check_file(file) + cmd = item_has_attribute file, 'Archive' + Backend::PowerShell::Command.new do + exec cmd + end + end + + def check_file_hidden(file) + cmd = item_has_attribute file, 'Hidden' + Backend::PowerShell::Command.new do + exec cmd + end + end + + def check_file_readonly(file) + cmd = item_has_attribute file, 'ReadOnly' + Backend::PowerShell::Command.new do + exec cmd + end + end + + def check_file_system(file) + cmd = item_has_attribute file, 'System' + Backend::PowerShell::Command.new do + exec cmd + end + end + + def check_directory(dir) + cmd = item_has_attribute dir, 'Directory' + Backend::PowerShell::Command.new do + exec cmd + end + end + + def check_file_contain(file, pattern) + Backend::PowerShell::Command.new do + exec "[Io.File]::ReadAllText('#{file}') -match '#{convert_regexp(pattern)}'" + end + end + + def check_file_contain_within file, pattern, from=nil, to=nil + from ||= '^' + to ||= '$' + Backend::PowerShell::Command.new do + using 'crop_text.ps1' + exec %Q[(CropText -text ([Io.File]::ReadAllText('#{file}')) -fromPattern '#{convert_regexp(from)}' -toPattern '#{convert_regexp(to)}') -match '#{pattern}'] + end + end + + def check_access_by_user(file, user, access) + case access + when 'r' + check_readable(file, user) + when 'w' + check_writable(file, user) + when 'x' + check_executable(file, user) + end + end + + def check_readable(file, by_whom) + Backend::PowerShell::Command.new do + using 'check_file_access_rules.ps1' + exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')" + end + end + + def check_writable(file, by_whom) + Backend::PowerShell::Command.new do + using 'check_file_access_rules.ps1' + exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'Write')" + end + end + + def check_executable(file, by_whom) + Backend::PowerShell::Command.new do + using 'check_file_access_rules.ps1' + exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')" + end + end + + def check_installed(package, version=nil) + version_selection = version.nil? ? "" : "-appVersion '#{version}'" + Backend::PowerShell::Command.new do + using 'find_installed_application.ps1' + exec "(FindInstalledApplication -appName '#{package}' #{version_selection}) -ne $null" + end + end + + def check_enabled(service, level=nil) + Backend::PowerShell::Command.new do + using 'find_service.ps1' + exec "(FindService -name '#{service}').StartMode -eq 'Auto'" + end + end + + def check_running(service) + Backend::PowerShell::Command.new do + using 'find_service.ps1' + exec "(FindService -name '#{service}').State -eq 'Running'" + end + end + + def check_process(process) + Backend::PowerShell::Command.new do + exec "(Get-Process '#{process}') -ne $null" + end + end + + def check_listening(port) + Backend::PowerShell::Command.new do + using 'is_port_listening.ps1' + exec "IsPortListening -portNumber #{port}" + end + end + + def check_listening_with_protocol(port, protocol) + Backend::PowerShell::Command.new do + using 'is_port_listening.ps1' + exec "IsPortListening -portNumber #{port} -protocol #{protocol}" + end + end + + def check_user(user) + user_id, domain = windows_account user + Backend::PowerShell::Command.new do + using 'find_user.ps1' + exec "(FindUser -userName '#{user_id}' #{domain.nil? ? "" : "-domain '#{domain}'"}) -ne $null" + end + end + + def check_group(group) + group_id, domain = windows_account group + Backend::PowerShell::Command.new do + using 'find_group.ps1' + exec "(FindGroup -groupName '#{group_id}' #{domain.nil? ? "" : "-domain '#{domain}'"}) -ne $null" + end + end + + def check_belonging_group(user, group) + user_id, user_domain = windows_account user + user_domain_filter = user_domain.nil? ? "" : "-userDomain '#{user_domain}'" + group_id, group_domain = windows_account group + Backend::PowerShell::Command.new do + using 'find_user.ps1' + using 'find_group.ps1' + using 'find_usergroup.ps1' + exec "(FindUserGroup -userName '#{user_id}' #{user_domain.nil? ? "" : "-userDomain '#{user_domain}'"} -groupName '#{group_id}' #{group_domain.nil? ? "" : "-groupDomain '#{group_domain}'"}) -ne $null" + end + end + + def check_registry_key(key_name, key_property = {}) + if key_property.empty? + cmd = "(Get-Item 'Registry::#{key_name}') -ne $null" + else + if key_property.key? :value + value = convert_key_property_value key_property + cmd = "(Compare-Object (Get-Item 'Registry::#{key_name}').GetValue('#{key_property[:name]}') #{value}) -eq $null" + else + cmd = "(Get-Item 'Registry::#{key_name}').GetValueKind('#{key_property[:name]}') -eq '#{REGISTRY_KEY_TYPES[key_property[:type]]}'" + end + end + Backend::PowerShell::Command.new { exec cmd } + end + + private + + def item_has_attribute item, attribute + "((Get-Item -Path '#{item}' -Force).attributes.ToString() -Split ', ') -contains '#{attribute}'" + end + + def convert_key_property_value property + case property[:type] + when :type_binary + byte_array = [property[:value]].pack('H*').bytes.to_a + "([byte[]] #{byte_array.join(',')})" + when:type_dword, :type_qword + property[:value].hex + else + string_array = property[:value].split("\n").map {|s| "'#{s}'"}.reduce {|acc, s| "#{acc},#{s}"} + "@(#{string_array})" + end + end + + def windows_account account + match = /((.+)\\)?(.+)/.match account + domain = match[2] + name = match[3] + [name, domain] + end + end + end +end diff --git a/lib/serverspec/helper.rb b/lib/serverspec/helper.rb index 2e8439c2..5ee03ab9 100644 --- a/lib/serverspec/helper.rb +++ b/lib/serverspec/helper.rb @@ -3,6 +3,8 @@ # Backend helpers require 'serverspec/helper/ssh' require 'serverspec/helper/exec' +require 'serverspec/helper/cmd' +require 'serverspec/helper/winrm' require 'serverspec/helper/puppet' # Command helpers @@ -14,6 +16,7 @@ require 'serverspec/helper/solaris11' require 'serverspec/helper/smartos' require 'serverspec/helper/darwin' +require 'serverspec/helper/windows' require 'serverspec/helper/detect_os' # Attributes helper diff --git a/lib/serverspec/helper/windows.rb b/lib/serverspec/helper/windows.rb new file mode 100644 index 00000000..5f0d7cef --- /dev/null +++ b/lib/serverspec/helper/windows.rb @@ -0,0 +1,9 @@ +module Serverspec + module Helper + module Windows + def commands + Serverspec::Commands::Windows.new + end + end + end +end diff --git a/spec/backend/powershell/script_helper_spec.rb b/spec/backend/powershell/script_helper_spec.rb new file mode 100644 index 00000000..411ef754 --- /dev/null +++ b/spec/backend/powershell/script_helper_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' + +include Serverspec::Backend::PowerShell::ScriptHelper + +describe 'build command with path' do + before :each do + RSpec.configure do |c| + c.path = 'c:/test/path/bin' + end + end + + it "should prefix the command with the path instruction" do + cmd = build_command('run_script -f param') + cmd.should eq <<-eof +$env:path = "c:/test/path/bin;$env:path" +run_script -f param +eof + end + + after :each do + RSpec.configure do |c| + c.path = nil + end + end +end + +describe 'add pre-command' do + before :each do + Serverspec.configuration.pre_command = 'test_pre_command' + end + + it "should add the test for pre_command before the command" do + cmd = add_pre_command('run_script -f param') + cmd.should eq <<-eof +if (test_pre_command) +{ +run_script -f param +} +eof + end + + context "with path" do + before :each do + RSpec.configure do |c| + c.path = 'c:/test/path/bin' + end + end + + it "should add the path instruction and the test for pre_command before the command" do + cmd = add_pre_command('run_script -f param') + cmd.should eq <<-eof +$env:path = "c:/test/path/bin;$env:path" +if (test_pre_command) +{ +run_script -f param +} +eof + end + + after :each do + RSpec.configure do |c| + c.path = nil + end + end + end + + after :each do + Serverspec.configuration.pre_command = nil + end +end + +describe "script encoding" do + it "should encode the given script" do + script = encode_script("test_powershell_script") + script.should == "dABlAHMAdABfAHAAbwB3AGUAcgBzAGgAZQBsAGwAXwBzAGMAcgBpAHAAdAA=" + end +end diff --git a/spec/support/powershell_command_runner.rb b/spec/support/powershell_command_runner.rb new file mode 100644 index 00000000..165b0813 --- /dev/null +++ b/spec/support/powershell_command_runner.rb @@ -0,0 +1,52 @@ +shared_examples "a powershell command runner" do + describe 'configurations are not set' do + context file('/some/file') do + it { should be_file } + its(:command) { should == "((Get-Item -Path '/some/file' -Force).attributes.ToString() -Split ', ') -contains 'Archive'" } + end + end + + describe 'path is set' do + let(:path) { 'c:/path/bin' } + context file('/some/file') do + it { should be_file } + its(:command) { + should == <<-eof +$env:path = "c:/path/bin;$env:path" +((Get-Item -Path '/some/file' -Force).attributes.ToString() -Split ', ') -contains 'Archive' +eof + } + end + end + + describe 'pre_command is set' do + let(:pre_command) { 'some_other_command' } + context file('/some/file') do + it { should be_file } + its(:command) { should == <<-eof +if (some_other_command) +{ +((Get-Item -Path '/some/file' -Force).attributes.ToString() -Split ', ') -contains 'Archive' +} +eof + } + end + end + + describe 'path and pre_command are set' do + let(:path) { 'c:/path/bin' } + let(:pre_command) { 'some_other_command' } + context file('/some/file') do + it { should be_file } + its(:command) { should == <<-eof +$env:path = "c:/path/bin;$env:path" +if (some_other_command) +{ +$env:path = "c:/path/bin;$env:path" +((Get-Item -Path '/some/file' -Force).attributes.ToString() -Split ', ') -contains 'Archive' +} +eof + } + end + end +end \ No newline at end of file From a05fe004ed86421a1b2658046921d22a619c60ab Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Tue, 17 Sep 2013 16:50:09 +1000 Subject: [PATCH 17/43] added windows_registry_key_type --- lib/serverspec/helper/type.rb | 1 + lib/serverspec/type/windows_registry_key.rb | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 lib/serverspec/type/windows_registry_key.rb diff --git a/lib/serverspec/helper/type.rb b/lib/serverspec/helper/type.rb index d5009179..ad204751 100644 --- a/lib/serverspec/helper/type.rb +++ b/lib/serverspec/helper/type.rb @@ -4,6 +4,7 @@ module Type types = %w( base yumrepo service package port file cron command linux_kernel_parameter iptables host routing_table default_gateway selinux user group zfs ipnat ipfilter kernel_module interface php_config + windows_registry_key ) types.each {|type| require "serverspec/type/#{type}" } diff --git a/lib/serverspec/type/windows_registry_key.rb b/lib/serverspec/type/windows_registry_key.rb new file mode 100644 index 00000000..b4a281d2 --- /dev/null +++ b/lib/serverspec/type/windows_registry_key.rb @@ -0,0 +1,21 @@ +module Serverspec + module Type + class WindowsRegistryKey < Base + def exists? + backend.check_registry_key(@name) + end + + def has_property?(property_name, property_type = :type_string) + backend.check_registry_key(@name, {:name => property_name, :type => property_type}) + end + + def has_value?(value) + backend.check_registry_key(@name, {:name => '', :type => :type_string, :value => value, }) + end + + def has_property_value?(property_name, property_type, value) + backend.check_registry_key(@name, {:name => property_name, :type => property_type, :value => value}) + end + end + end +end From eee5d9ad016af536f5be31420e07b0035795d215 Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Tue, 17 Sep 2013 16:51:58 +1000 Subject: [PATCH 18/43] adding winrm backend --- lib/serverspec/backend.rb | 5 +++++ lib/serverspec/backend/winrm.rb | 28 ++++++++++++++++++++++++++++ lib/serverspec/helper/winrm.rb | 15 +++++++++++++++ serverspec.gemspec | 1 + 4 files changed, 49 insertions(+) create mode 100644 lib/serverspec/backend/winrm.rb create mode 100644 lib/serverspec/helper/winrm.rb diff --git a/lib/serverspec/backend.rb b/lib/serverspec/backend.rb index 21c38319..97f9c2c2 100644 --- a/lib/serverspec/backend.rb +++ b/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' diff --git a/lib/serverspec/backend/winrm.rb b/lib/serverspec/backend/winrm.rb new file mode 100644 index 00000000..52c214e3 --- /dev/null +++ b/lib/serverspec/backend/winrm.rb @@ -0,0 +1,28 @@ +require 'winrm' + +module Serverspec + module Backend + class WinRM < Base + include PowerShell::ScriptHelper + + def run_command(cmd, opts={}) + script = create_script(cmd) + winrm = RSpec.configuration.winrm + + result = winrm.powershell(script) + stdout, stderr = [:stdout, :stderr].map do |s| + result[:data].select {|item| item.key? s}.map {|item| item[s]}.join + end + result[:exitcode] = 1 if result[:exitcode] == 0 and !stderr.empty? + + if @example + @example.metadata[:command] = script + @example.metadata[:stdout] = stdout + stderr + end + + { :stdout => stdout, :stderr => stderr, + :exit_status => result[:exitcode], :exit_signal => nil } + end + end + end +end diff --git a/lib/serverspec/helper/winrm.rb b/lib/serverspec/helper/winrm.rb new file mode 100644 index 00000000..d0780d89 --- /dev/null +++ b/lib/serverspec/helper/winrm.rb @@ -0,0 +1,15 @@ +module Serverspec + module Helper + module WinRM + def backend(commands_object=nil) + if ! respond_to?(:commands) + commands_object = Serverspec::Commands::Windows.new + end + instance = Serverspec::Backend::WinRM.instance + instance.set_commands(commands_object || commands) + instance + end + end + end +end + diff --git a/serverspec.gemspec b/serverspec.gemspec index da350afa..d7d2c68b 100644 --- a/serverspec.gemspec +++ b/serverspec.gemspec @@ -19,6 +19,7 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_runtime_dependency "net-ssh" + spec.add_runtime_dependency "winrm" spec.add_runtime_dependency "rspec", ">= 2.13.0" spec.add_runtime_dependency "highline" spec.add_development_dependency "bundler", "~> 1.3" From 088bf2cc731682b3e63c18bdd94a90ad5a98be65 Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Tue, 17 Sep 2013 16:52:42 +1000 Subject: [PATCH 19/43] adding specs for windows commands --- lib/serverspec.rb | 3 + spec/backend/winrm/configuration_spec.rb | 9 + spec/spec_helper.rb | 44 ++- spec/windows/file_spec.rb | 329 +++++++++++++++++++++++ 4 files changed, 359 insertions(+), 26 deletions(-) create mode 100644 spec/backend/winrm/configuration_spec.rb create mode 100644 spec/windows/file_spec.rb diff --git a/lib/serverspec.rb b/lib/serverspec.rb index 6ebfc1cd..ecb83498 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -16,6 +16,7 @@ require 'serverspec/commands/solaris11' require 'serverspec/commands/smartos' require 'serverspec/commands/darwin' +require 'serverspec/commands/windows' require 'serverspec/configuration' require 'rspec/core/formatters/base_formatter' @@ -39,10 +40,12 @@ def configuration 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.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) diff --git a/spec/backend/winrm/configuration_spec.rb b/spec/backend/winrm/configuration_spec.rb new file mode 100644 index 00000000..71bbfd12 --- /dev/null +++ b/spec/backend/winrm/configuration_spec.rb @@ -0,0 +1,9 @@ +require 'spec_helper' +require 'support/powershell_command_runner' + +include Serverspec::Helper::WinRM +include Serverspec::Helper::Windows + +describe "WinRM" do + it_behaves_like "a powershell command runner" +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 126271ba..28436355 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,10 +11,8 @@ module Serverspec module Backend - class Exec - def run_command(cmd) - cmd = build_command(cmd) - cmd = add_pre_command(cmd) + module TestCommandRunner + def do_run cmd if @example @example.metadata[:subject].set_command(cmd) end @@ -36,29 +34,23 @@ def run_command(cmd) end end end - - class Ssh - def run_command(cmd) - cmd = build_command(cmd) - cmd = add_pre_command(cmd) - if @example - @example.metadata[:subject].set_command(cmd) + [Exec, Ssh].each do |clz| + clz.class_eval do + include TestCommandRunner + def run_command(cmd) + cmd = build_command(cmd) + cmd = add_pre_command(cmd) + do_run cmd end - - if cmd =~ /invalid/ - { - :stdout => ::Serverspec.configuration.stdout, - :stderr => ::Serverspec.configuration.stderr, - :exit_status => 1, - :exit_signal => nil - } - else - { - :stdout => ::Serverspec.configuration.stdout, - :stderr => ::Serverspec.configuration.stderr, - :exit_status => 0, - :exit_signal => nil - } + end + end + [Cmd, WinRM].each do |clz| + clz.class_eval do + include TestCommandRunner + def run_command(cmd) + cmd = build_command(cmd.script) + cmd = add_pre_command(cmd) + do_run cmd end end end diff --git a/spec/windows/file_spec.rb b/spec/windows/file_spec.rb new file mode 100644 index 00000000..aaf99e57 --- /dev/null +++ b/spec/windows/file_spec.rb @@ -0,0 +1,329 @@ +require 'spec_helper' + +include Serverspec::Helper::Cmd +include Serverspec::Helper::Windows + +describe file('/some/valid/file') do + it { should be_file } + its(:command) { should == "((Get-Item -Path '/some/valid/file' -Force).attributes.ToString() -Split ', ') -contains 'Archive'" } +end + +describe file('/some/invalid/file') do + it { should_not be_file } +end + +describe file('/some/valid/folder') do + it { should be_directory } + its(:command) { should == "((Get-Item -Path '/some/valid/folder' -Force).attributes.ToString() -Split ', ') -contains 'Directory'" } +end + +describe file('/some/invalid/folder') do + it { should_not be_directory } +end + +describe file('/some/file') do + it { should contain 'search text' } + its(:command) { should == "[Io.File]::ReadAllText('/some/file') -match 'search text'" } +end + +describe file('/some/file') do + it { should contain /^search text/ } + its(:command) { should == "[Io.File]::ReadAllText('/some/file') -match '^search text'" } +end + +describe file('/some/file') do + it { should_not contain 'This is invalid text!!' } +end + +describe file('Gemfile') do + it { should contain('rspec').from(/^group :test do/).to(/^end/) } + its(:command) { should == "(CropText -text ([Io.File]::ReadAllText('Gemfile')) -fromPattern '^group :test do' -toPattern '^end') -match 'rspec'" } +end + +describe file('/some/file') do + it { should_not contain('This is invalid text!!').from(/^group :test do/).to(/^end/) } +end + +describe file('Gemfile') do + it { should contain('rspec').after(/^group :test do/) } + its(:command) { should == "(CropText -text ([Io.File]::ReadAllText('Gemfile')) -fromPattern '^group :test do' -toPattern '$') -match 'rspec'" } +end + +describe file('Gemfile') do + it { should_not contain('This is invalid text!!').after(/^group :test do/) } +end + +describe file('Gemfile') do + it { should contain('rspec').before(/end/) } + its(:command) { should == "(CropText -text ([Io.File]::ReadAllText('Gemfile')) -fromPattern '^' -toPattern 'end') -match 'rspec'" } +end + +describe file('Gemfile') do + it { should_not contain('This is invalid text!!').before(/^end/) } +end + +describe file('/some/test/file') do + it "should raise error if command is not supported" do + { + be_socket: [], + be_mode: 644, + be_owned_by: 'root', + be_grouped_into: 'root', + be_linked_to: '/some/other/file', + # be_executable: [nil, nil], + be_mounted: [], + match_md5checksum: '35435ea447c19f0ea5ef971837ab9ced', + match_sha256checksum: '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' + }.each do |method, args| + expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError + end + end +end + + +# describe file('/etc/passwd') do +# it { should be_owned_by 'root' } +# its(:command) { should eq "stat -f %Su /etc/passwd | grep -- \\^root\\$" } +# end + +# describe file('/etc/passwd') do +# it { should_not be_owned_by 'invalid-owner' } +# end + +# describe file('/etc/passwd') do +# it { should be_grouped_into 'root' } +# its(:command) { should eq "stat -f %Sg /etc/passwd | grep -- \\^root\\$" } +# end + +# describe file('/etc/passwd') do +# it { should_not be_grouped_into 'invalid-group' } +# end + +# describe file('/etc/pam.d/system-auth') do +# it { should be_linked_to '/etc/pam.d/system-auth-ac' } +# its(:command) { should eq "stat -f %Y /etc/pam.d/system-auth | grep -- /etc/pam.d/system-auth-ac" } +# end + +# describe file('dummy-link') do +# it { should_not be_linked_to '/invalid/target' } +# end + +describe file('/some/file') do + it { should be_readable } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'Everyone' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')" } +end + +describe file('/some/invalid/file') do + it { should_not be_readable } +end + +describe file('/some/file') do + it "should raise error if trying to check access by 'owner' or 'group' or 'others'" do + ['owner', 'group', 'others'].each do |access| + expect { should be_readable.by(access) }.to raise_error + end + end +end + +describe file('/some/file') do + it { should be_readable.by('test.identity') } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')" } +end + +describe file('/some/file') do + it { should be_readable.by_user('test.identity') } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')" } +end + +describe file('/some/file') do + it { should be_writable } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'Everyone' -rules @('FullControl', 'Modify', 'Write')" } +end + +describe file('/some/invalid/file') do + it { should_not be_writable } +end + +describe file('/some/file') do + it "should raise error if trying to check access by 'owner' or 'group' or 'others'" do + ['owner', 'group', 'others'].each do |access| + expect { should be_writable.by(access) }.to raise_error + end + end +end + +describe file('/some/file') do + it { should be_writable.by('test.identity') } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'Write')" } +end + +describe file('/some/file') do + it { should be_writable.by_user('test.identity') } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'Write')" } +end + +describe file('/some/file') do + it { should be_executable } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'Everyone' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')" } +end + +describe file('/some/invalid/file') do + it { should_not be_executable } +end + +describe file('/some/file') do + it "should raise error if trying to check access by 'owner' or 'group' or 'others'" do + ['owner', 'group', 'others'].each do |access| + expect { should be_executable.by(access) }.to raise_error + end + end +end + +describe file('/some/file') do + it { should be_executable.by('test.identity') } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')" } +end + +describe file('/some/file') do + it { should be_executable.by_user('test.identity') } + its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')" } +end + + +# describe file('/') do +# it { should be_mounted } +# its(:command) { should eq "mount | grep -w -- on\\ /" } +# end + +# describe file('/etc/invalid-mount') do +# it { should_not be_mounted } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should be_mounted.with( :type => 'ext4' ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should be_mounted.with( :type => 'ext4', :options => { :rw => true } ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should be_mounted.with( :type => 'ext4', :options => { :mode => 620 } ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_root' ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.with( :type => 'xfs' ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.with( :type => 'ext4', :options => { :rw => false } ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.with( :type => 'ext4', :options => { :mode => 600 } ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.with( :type => 'xfs', :device => '/dev/mapper/VolGroup-lv_root' ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_r00t' ) } +# end + +# describe file('/etc/invalid-mount') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.with( :type => 'ext4' ) } +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it do +# should be_mounted.only_with( +# :device => '/dev/mapper/VolGroup-lv_root', +# :type => 'ext4', +# :options => { +# :rw => true, +# :mode => 620, +# } +# ) +# end +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it do +# should_not be_mounted.only_with( +# :device => '/dev/mapper/VolGroup-lv_root', +# :type => 'ext4', +# :options => { +# :rw => true, +# :mode => 620, +# :bind => true, +# } +# ) +# end +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it do +# should_not be_mounted.only_with( +# :device => '/dev/mapper/VolGroup-lv_root', +# :type => 'ext4', +# :options => { +# :rw => true, +# } +# ) +# end +# end + +# describe file('/') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it do +# should_not be_mounted.only_with( +# :device => '/dev/mapper/VolGroup-lv_roooooooooot', +# :type => 'ext4', +# :options => { +# :rw => true, +# :mode => 620, +# } +# ) +# end +# end + +# describe file('/etc/invalid-mount') do +# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } +# it { should_not be_mounted.only_with( :type => 'ext4' ) } +# end + +# describe file('/etc/services') do +# it { should match_md5checksum '35435ea447c19f0ea5ef971837ab9ced' } +# its(:command) { should eq "openssl md5 /etc/services | cut -d'=' -f2 | cut -c 2- | grep -E ^35435ea447c19f0ea5ef971837ab9ced$" } +# end + +# describe file('invalid-file') do +# it { should_not match_md5checksum 'INVALIDMD5CHECKSUM' } +# end + +# describe file('/etc/services') do +# it { should match_sha256checksum '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' } +# its(:command) { should eq "openssl sha256 /etc/services | cut -d'=' -f2 | cut -c 2- | grep -E ^0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a$" } +# end + +# describe file('invalid-file') do +# it { should_not match_sha256checksum 'INVALIDSHA256CHECKSUM' } +# end From e8411b0d8651ee3cacbc2bd99b04fa1f3de6576b Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Wed, 18 Sep 2013 20:24:12 +1000 Subject: [PATCH 20/43] added specs for user, group and port types --- lib/serverspec/commands/windows.rb | 9 +- lib/serverspec/type/windows_registry_key.rb | 2 +- spec/windows/file_spec.rb | 200 ++------------------ spec/windows/group_spec.rb | 29 +++ spec/windows/port_spec.rb | 31 +++ spec/windows/user_spec.rb | 53 ++++++ 6 files changed, 134 insertions(+), 190 deletions(-) create mode 100644 spec/windows/group_spec.rb create mode 100644 spec/windows/port_spec.rb create mode 100644 spec/windows/user_spec.rb diff --git a/lib/serverspec/commands/windows.rb b/lib/serverspec/commands/windows.rb index e599e35e..fbebf127 100644 --- a/lib/serverspec/commands/windows.rb +++ b/lib/serverspec/commands/windows.rb @@ -136,7 +136,7 @@ def check_listening(port) def check_listening_with_protocol(port, protocol) Backend::PowerShell::Command.new do using 'is_port_listening.ps1' - exec "IsPortListening -portNumber #{port} -protocol #{protocol}" + exec "IsPortListening -portNumber #{port} -protocol '#{protocol}'" end end @@ -144,7 +144,7 @@ def check_user(user) user_id, domain = windows_account user Backend::PowerShell::Command.new do using 'find_user.ps1' - exec "(FindUser -userName '#{user_id}' #{domain.nil? ? "" : "-domain '#{domain}'"}) -ne $null" + exec "(FindUser -userName '#{user_id}'#{domain.nil? ? "" : " -domain '#{domain}'"}) -ne $null" end end @@ -152,19 +152,18 @@ def check_group(group) group_id, domain = windows_account group Backend::PowerShell::Command.new do using 'find_group.ps1' - exec "(FindGroup -groupName '#{group_id}' #{domain.nil? ? "" : "-domain '#{domain}'"}) -ne $null" + exec "(FindGroup -groupName '#{group_id}'#{domain.nil? ? "" : " -domain '#{domain}'"}) -ne $null" end end def check_belonging_group(user, group) user_id, user_domain = windows_account user - user_domain_filter = user_domain.nil? ? "" : "-userDomain '#{user_domain}'" group_id, group_domain = windows_account group Backend::PowerShell::Command.new do using 'find_user.ps1' using 'find_group.ps1' using 'find_usergroup.ps1' - exec "(FindUserGroup -userName '#{user_id}' #{user_domain.nil? ? "" : "-userDomain '#{user_domain}'"} -groupName '#{group_id}' #{group_domain.nil? ? "" : "-groupDomain '#{group_domain}'"}) -ne $null" + exec "(FindUserGroup -userName '#{user_id}'#{user_domain.nil? ? "" : " -userDomain '#{user_domain}'"} -groupName '#{group_id}'#{group_domain.nil? ? "" : " -groupDomain '#{group_domain}'"}) -ne $null" end end diff --git a/lib/serverspec/type/windows_registry_key.rb b/lib/serverspec/type/windows_registry_key.rb index b4a281d2..8987cb48 100644 --- a/lib/serverspec/type/windows_registry_key.rb +++ b/lib/serverspec/type/windows_registry_key.rb @@ -10,7 +10,7 @@ def has_property?(property_name, property_type = :type_string) end def has_value?(value) - backend.check_registry_key(@name, {:name => '', :type => :type_string, :value => value, }) + backend.check_registry_key(@name, {:name => '', :type => :type_string, :value => value}) end def has_property_value?(property_name, property_type, value) diff --git a/spec/windows/file_spec.rb b/spec/windows/file_spec.rb index aaf99e57..c10eda12 100644 --- a/spec/windows/file_spec.rb +++ b/spec/windows/file_spec.rb @@ -62,52 +62,6 @@ it { should_not contain('This is invalid text!!').before(/^end/) } end -describe file('/some/test/file') do - it "should raise error if command is not supported" do - { - be_socket: [], - be_mode: 644, - be_owned_by: 'root', - be_grouped_into: 'root', - be_linked_to: '/some/other/file', - # be_executable: [nil, nil], - be_mounted: [], - match_md5checksum: '35435ea447c19f0ea5ef971837ab9ced', - match_sha256checksum: '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' - }.each do |method, args| - expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError - end - end -end - - -# describe file('/etc/passwd') do -# it { should be_owned_by 'root' } -# its(:command) { should eq "stat -f %Su /etc/passwd | grep -- \\^root\\$" } -# end - -# describe file('/etc/passwd') do -# it { should_not be_owned_by 'invalid-owner' } -# end - -# describe file('/etc/passwd') do -# it { should be_grouped_into 'root' } -# its(:command) { should eq "stat -f %Sg /etc/passwd | grep -- \\^root\\$" } -# end - -# describe file('/etc/passwd') do -# it { should_not be_grouped_into 'invalid-group' } -# end - -# describe file('/etc/pam.d/system-auth') do -# it { should be_linked_to '/etc/pam.d/system-auth-ac' } -# its(:command) { should eq "stat -f %Y /etc/pam.d/system-auth | grep -- /etc/pam.d/system-auth-ac" } -# end - -# describe file('dummy-link') do -# it { should_not be_linked_to '/invalid/target' } -# end - describe file('/some/file') do it { should be_readable } its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'Everyone' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')" } @@ -189,141 +143,19 @@ its(:command) { should eq "CheckFileAccessRules -path '/some/file' -identity 'test.identity' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')" } end - -# describe file('/') do -# it { should be_mounted } -# its(:command) { should eq "mount | grep -w -- on\\ /" } -# end - -# describe file('/etc/invalid-mount') do -# it { should_not be_mounted } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should be_mounted.with( :type => 'ext4' ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should be_mounted.with( :type => 'ext4', :options => { :rw => true } ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should be_mounted.with( :type => 'ext4', :options => { :mode => 620 } ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_root' ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.with( :type => 'xfs' ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.with( :type => 'ext4', :options => { :rw => false } ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.with( :type => 'ext4', :options => { :mode => 600 } ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.with( :type => 'xfs', :device => '/dev/mapper/VolGroup-lv_root' ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_r00t' ) } -# end - -# describe file('/etc/invalid-mount') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.with( :type => 'ext4' ) } -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it do -# should be_mounted.only_with( -# :device => '/dev/mapper/VolGroup-lv_root', -# :type => 'ext4', -# :options => { -# :rw => true, -# :mode => 620, -# } -# ) -# end -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it do -# should_not be_mounted.only_with( -# :device => '/dev/mapper/VolGroup-lv_root', -# :type => 'ext4', -# :options => { -# :rw => true, -# :mode => 620, -# :bind => true, -# } -# ) -# end -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it do -# should_not be_mounted.only_with( -# :device => '/dev/mapper/VolGroup-lv_root', -# :type => 'ext4', -# :options => { -# :rw => true, -# } -# ) -# end -# end - -# describe file('/') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it do -# should_not be_mounted.only_with( -# :device => '/dev/mapper/VolGroup-lv_roooooooooot', -# :type => 'ext4', -# :options => { -# :rw => true, -# :mode => 620, -# } -# ) -# end -# end - -# describe file('/etc/invalid-mount') do -# let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } -# it { should_not be_mounted.only_with( :type => 'ext4' ) } -# end - -# describe file('/etc/services') do -# it { should match_md5checksum '35435ea447c19f0ea5ef971837ab9ced' } -# its(:command) { should eq "openssl md5 /etc/services | cut -d'=' -f2 | cut -c 2- | grep -E ^35435ea447c19f0ea5ef971837ab9ced$" } -# end - -# describe file('invalid-file') do -# it { should_not match_md5checksum 'INVALIDMD5CHECKSUM' } -# end - -# describe file('/etc/services') do -# it { should match_sha256checksum '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' } -# its(:command) { should eq "openssl sha256 /etc/services | cut -d'=' -f2 | cut -c 2- | grep -E ^0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a$" } -# end - -# describe file('invalid-file') do -# it { should_not match_sha256checksum 'INVALIDSHA256CHECKSUM' } -# end +describe file('/some/test/file') do + it "should raise error if command is not supported" do + { + be_socket: [], + be_mode: 644, + be_owned_by: 'root', + be_grouped_into: 'root', + be_linked_to: '/some/other/file', + be_mounted: [], + match_md5checksum: '35435ea447c19f0ea5ef971837ab9ced', + match_sha256checksum: '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' + }.each do |method, args| + expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError + end + end +end diff --git a/spec/windows/group_spec.rb b/spec/windows/group_spec.rb new file mode 100644 index 00000000..7a9e1e31 --- /dev/null +++ b/spec/windows/group_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +include Serverspec::Helper::Cmd +include Serverspec::Helper::Windows + +describe group('test.group') do + it { should exist } + its(:command) { should eq "(FindGroup -groupName 'test.group') -ne $null" } +end + +describe group('test.domain\test.group') do + it { should exist } + its(:command) { should eq "(FindGroup -groupName 'test.group' -domain 'test.domain') -ne $null" } +end + +describe group('invalid-group') do + it { should_not exist } +end + +describe group('test.group') do + it "should raise error if command is not supported" do + { + have_gid: [nil], + }.each do |method, args| + expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError + end + end +end + diff --git a/spec/windows/port_spec.rb b/spec/windows/port_spec.rb new file mode 100644 index 00000000..558d2f8b --- /dev/null +++ b/spec/windows/port_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +include Serverspec::Helper::Cmd +include Serverspec::Helper::Windows + +describe port(80) do + it { should be_listening } + its(:command) { should eq 'IsPortListening -portNumber 80' } +end + +describe port('invalid') do + it { should_not be_listening } +end + +describe port(80) do + it { should be_listening.with("tcp") } + its(:command) { should eq "IsPortListening -portNumber 80 -protocol 'tcp'" } +end + +describe port(123) do + it { should be_listening.with("udp") } + its(:command) { should eq "IsPortListening -portNumber 123 -protocol 'udp'" } +end + +describe port(80) do + it { + expect { + should be_listening.with('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_listening` matcher doesn\'t support/) + } +end diff --git a/spec/windows/user_spec.rb b/spec/windows/user_spec.rb new file mode 100644 index 00000000..eaa1789b --- /dev/null +++ b/spec/windows/user_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +include Serverspec::Helper::Cmd +include Serverspec::Helper::Windows + +describe user('test.user') do + it { should exist } + its(:command) { should eq "(FindUser -userName 'test.user') -ne $null" } +end + +describe user('test.domain\test.user') do + it { should exist } + its(:command) { should eq "(FindUser -userName 'test.user' -domain 'test.domain') -ne $null" } +end + +describe user('invalid-user') do + it { should_not exist } +end + +describe user('test.user') do + it { should belong_to_group 'test.group' } + its(:command) { should eq "(FindUserGroup -userName 'test.user' -groupName 'test.group') -ne $null" } +end + +describe user('test.user.domain\test.user') do + it { should belong_to_group 'test.group.domain\test.group' } + its(:command) { should eq "(FindUserGroup -userName 'test.user' -userDomain 'test.user.domain' -groupName 'test.group' -groupDomain 'test.group.domain') -ne $null" } +end + +describe user('test.user') do + it { should_not belong_to_group 'invalid-group' } +end + +describe user('test.user') do + it "should raise error if command is not supported" do + { + have_uid: [nil], + have_login_shell: [nil], + have_authorized_key: [nil], + }.each do |method, args| + expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError + end + end +end + +# describe user('root') do +# it { should have_home_directory '/root' } +# its(:command) { should eq "getent passwd root | cut -f 6 -d ':' | grep -w -- /root" } +# end + +# describe user('root') do +# it { should_not have_home_directory 'invalid-home-directory' } +# end From e0a58e9980c7bcc67dd302fd273a95e07531375c Mon Sep 17 00:00:00 2001 From: Silvio Montanari Date: Wed, 18 Sep 2013 22:31:35 +1000 Subject: [PATCH 21/43] added doc to describe windows support --- WindowsSupport.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 WindowsSupport.md diff --git a/WindowsSupport.md b/WindowsSupport.md new file mode 100644 index 00000000..3d2cdc40 --- /dev/null +++ b/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 = + pass = + endpoint = "http://: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 +``` \ No newline at end of file From 6f5ada56cdab8b922c9fb49c0211d60798f94f43 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 11:50:06 +0900 Subject: [PATCH 22/43] Rewrite safe_create_spec_helper() with ERB --- bin/serverspec-init | 54 ++++++++++++++++++++++++++++ lib/serverspec/setup.rb | 78 +++-------------------------------------- 2 files changed, 58 insertions(+), 74 deletions(-) diff --git a/bin/serverspec-init b/bin/serverspec-init index f199754f..44e2cb8e 100755 --- a/bin/serverspec-init +++ b/bin/serverspec-init @@ -5,3 +5,57 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) require 'serverspec' Serverspec::Setup.run + +__END__ +require 'serverspec' +require 'pathname' +<% if @backend_type == 'Ssh' -%> +require 'net/ssh' +<% end -%> + +include Serverspec::Helper::<%= @backend_type %> +include Serverspec::Helper::DetectOS + +RSpec.configure do |c| + if ENV['ASK_SUDO_PASSWORD'] + require 'highline/import' + c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false } + else + c.sudo_password = ENV['SUDO_PASSWORD'] + end +<% if @backend_type == 'Ssh' -%> + c.before :all do + block = self.class.metadata[:example_group_block] + if RUBY_VERSION.start_with?('1.8') + file = block.to_s.match(/.*@(.*):[0-9]+>/)[1] + else + file = block.source_location.first + end + host = File.basename(Pathname.new(file).dirname) + if c.host != host + c.ssh.close if c.ssh + c.host = host + options = Net::SSH::Config.for(c.host) + user = options[:user] || Etc.getlogin +<% if @vagrant -%> + vagrant_up = `vagrant up #{@hostname}` + config = `vagrant ssh-config #{@hostname}` + if config != '' + config.each_line do |line| + if match = /HostName (.*)/.match(line) + c.host = match[1] + elsif match = /User (.*)/.match(line) + user = match[1] + elsif match = /IdentityFile (.*)/.match(line) + options[:keys] = [match[1].gsub(/\"/,'')] + elsif match = /Port (.*)/.match(line) + options[:port] = match[1] + end + end + end +<% end -%> + c.ssh = Net::SSH.start(c.host, user, options) + end + end +<% end -%> +end diff --git a/lib/serverspec/setup.rb b/lib/serverspec/setup.rb index a17c6dd5..fd37cb19 100644 --- a/lib/serverspec/setup.rb +++ b/lib/serverspec/setup.rb @@ -1,4 +1,5 @@ require 'fileutils' +require 'erb' module Serverspec class Setup @@ -15,7 +16,7 @@ def self.run num = gets.to_i - 1 puts - @backend_type = [ 'Ssh', 'Exec' ][num] + @backend_type = [ 'Ssh', 'Exec' ][num] || 'Exec' if @backend_type == 'Ssh' print "Vagrant instance y/n: " @vagrant = gets.chomp @@ -44,7 +45,6 @@ def self.run end def self.safe_create_spec - content = <<-EOF require 'spec_helper' @@ -92,77 +92,8 @@ def self.safe_mkdir(dir) end def self.safe_create_spec_helper - content = <<-EOF -require 'serverspec' -require 'pathname' -### include requirements ### - -### include backend helper ### -include Serverspec::Helper::DetectOS - -RSpec.configure do |c| - if ENV['ASK_SUDO_PASSWORD'] - require 'highline/import' - c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false } - else - c.sudo_password = ENV['SUDO_PASSWORD'] - end - ### include backend conf ### -end -EOF - - if not @backend_type.nil? - content.gsub!(/### include backend helper ###/, "include Serverspec::Helper::#{@backend_type}") - case @backend_type - when 'Ssh' - content.gsub!(/### include requirements ###/, "require 'net/ssh'") - content.gsub!(/### include backend conf ###/, "c.before :all do - block = self.class.metadata[:example_group_block] - if RUBY_VERSION.start_with?('1.8') - file = block.to_s.match(/.*@(.*):[0-9]+>/)[1] - else - file = block.source_location.first - end - host = File.basename(Pathname.new(file).dirname) - if c.host != host - c.ssh.close if c.ssh - c.host = host - options = Net::SSH::Config.for(c.host) - user = options[:user] || Etc.getlogin - ### include vagrant conf ### - c.ssh = Net::SSH.start(c.host, user, options) - end - end") - if @vagrant - content.gsub!(/### include vagrant conf ###/," - vagrant_up = `vagrant up #{@hostname}` - config = `vagrant ssh-config #{@hostname}` - if config != '' - config.each_line do |line| - if match = /HostName (.*)/.match(line) - c.host = match[1] - elsif match = /User (.*)/.match(line) - user = match[1] - elsif match = /IdentityFile (.*)/.match(line) - options[:keys] = [match[1].gsub(/\"/,'')] - elsif match = /Port (.*)/.match(line) - options[:port] = match[1] - end - end - end - ") - else - content.gsub!(/### include vagrant conf ###/,'') - end - when 'Exec' - content.gsub!(/### include backend conf ###/, "c.before :all do - end") - when 'Puppet' - content.gsub!(/### include requirements ###/, "require 'puppet'\nrequire 'serverspec/backend/puppet' -") - end - end - + requirements = [] + content = ERB.new(DATA.read, nil, '-').result(binding) if File.exists? 'spec/spec_helper.rb' old_content = File.read('spec/spec_helper.rb') if old_content != content @@ -233,6 +164,5 @@ def self.auto_vagrant_configuration exit 1 end end - end end From cb37d3ef0ae704c56711939cecc974f0e9e47e38 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 12:02:18 +0900 Subject: [PATCH 23/43] Remove dependency of winrm because it is not needed when you don't test windows machines --- lib/serverspec/backend/winrm.rb | 2 -- serverspec.gemspec | 1 - 2 files changed, 3 deletions(-) diff --git a/lib/serverspec/backend/winrm.rb b/lib/serverspec/backend/winrm.rb index 52c214e3..1c1dff8a 100644 --- a/lib/serverspec/backend/winrm.rb +++ b/lib/serverspec/backend/winrm.rb @@ -1,5 +1,3 @@ -require 'winrm' - module Serverspec module Backend class WinRM < Base diff --git a/serverspec.gemspec b/serverspec.gemspec index d7d2c68b..da350afa 100644 --- a/serverspec.gemspec +++ b/serverspec.gemspec @@ -19,7 +19,6 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_runtime_dependency "net-ssh" - spec.add_runtime_dependency "winrm" spec.add_runtime_dependency "rspec", ">= 2.13.0" spec.add_runtime_dependency "highline" spec.add_development_dependency "bundler", "~> 1.3" From 749ba3bcde05626d07994154f759d3526a8b1cd8 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 12:11:39 +0900 Subject: [PATCH 24/43] Change to Ruby 1.8 hash style --- spec/windows/file_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/windows/file_spec.rb b/spec/windows/file_spec.rb index c10eda12..acee9799 100644 --- a/spec/windows/file_spec.rb +++ b/spec/windows/file_spec.rb @@ -146,14 +146,14 @@ describe file('/some/test/file') do it "should raise error if command is not supported" do { - be_socket: [], - be_mode: 644, - be_owned_by: 'root', - be_grouped_into: 'root', - be_linked_to: '/some/other/file', - be_mounted: [], - match_md5checksum: '35435ea447c19f0ea5ef971837ab9ced', - match_sha256checksum: '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' + :be_socket => [], + :be_mode => 644, + :be_owned_by => 'root', + :be_grouped_into => 'root', + :be_linked_to => '/some/other/file', + :be_mounted => [], + :match_md5checksum => '35435ea447c19f0ea5ef971837ab9ced', + :match_sha256checksum => '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' }.each do |method, args| expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError end From 827b1462b8c7732a5b07344cc49a29e9391488a1 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 12:15:58 +0900 Subject: [PATCH 25/43] Change to Ruby 1.8 hash style --- spec/windows/group_spec.rb | 2 +- spec/windows/user_spec.rb | 15 +++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/spec/windows/group_spec.rb b/spec/windows/group_spec.rb index 7a9e1e31..35c706ca 100644 --- a/spec/windows/group_spec.rb +++ b/spec/windows/group_spec.rb @@ -20,7 +20,7 @@ describe group('test.group') do it "should raise error if command is not supported" do { - have_gid: [nil], + :have_gid => [nil], }.each do |method, args| expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError end diff --git a/spec/windows/user_spec.rb b/spec/windows/user_spec.rb index eaa1789b..f454e0cf 100644 --- a/spec/windows/user_spec.rb +++ b/spec/windows/user_spec.rb @@ -34,20 +34,11 @@ describe user('test.user') do it "should raise error if command is not supported" do { - have_uid: [nil], - have_login_shell: [nil], - have_authorized_key: [nil], + :have_uid => [nil], + :have_login_shell => [nil], + :have_authorized_key => [nil], }.each do |method, args| expect { should self.send(method, *args) }.to raise_error Serverspec::Commands::Windows::NotSupportedError end end end - -# describe user('root') do -# it { should have_home_directory '/root' } -# its(:command) { should eq "getent passwd root | cut -f 6 -d ':' | grep -w -- /root" } -# end - -# describe user('root') do -# it { should_not have_home_directory 'invalid-home-directory' } -# end From 69891384f8f855131bd583a2f904fc69b04b7e6d Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 12:17:44 +0900 Subject: [PATCH 26/43] Add base64 requirement --- lib/serverspec/backend/powershell/script_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/serverspec/backend/powershell/script_helper.rb b/lib/serverspec/backend/powershell/script_helper.rb index 8eb3fcf3..f78a9bd8 100644 --- a/lib/serverspec/backend/powershell/script_helper.rb +++ b/lib/serverspec/backend/powershell/script_helper.rb @@ -1,3 +1,5 @@ +require 'base64' + module Serverspec module Backend module PowerShell @@ -58,4 +60,4 @@ def create_script command end end end -end \ No newline at end of file +end From 84075573e482cdf4ab239db864d71c9fec7f871f Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 12:49:50 +0900 Subject: [PATCH 27/43] Return explicitly when raise exception Does Ruby 1.8 return automatically in this case ? --- lib/serverspec/commands/windows.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/commands/windows.rb b/lib/serverspec/commands/windows.rb index fbebf127..6c909eed 100644 --- a/lib/serverspec/commands/windows.rb +++ b/lib/serverspec/commands/windows.rb @@ -12,7 +12,7 @@ class NotSupportedError < Exception; end } def method_missing method, *args - raise NotSupportedError.new "#{method} currently not supported in Windows os" if method =~ /^check_.+/ + return raise NotSupportedError.new "#{method} currently not supported in Windows os" if method =~ /^check_.+/ super(method, *args) end From 5cd77f771e5dc259003e939d76345c0d7e101e00 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 12:55:58 +0900 Subject: [PATCH 28/43] Revert "Return explicitly when raise exception" This reverts commit 84075573e482cdf4ab239db864d71c9fec7f871f. --- lib/serverspec/commands/windows.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/commands/windows.rb b/lib/serverspec/commands/windows.rb index 6c909eed..fbebf127 100644 --- a/lib/serverspec/commands/windows.rb +++ b/lib/serverspec/commands/windows.rb @@ -12,7 +12,7 @@ class NotSupportedError < Exception; end } def method_missing method, *args - return raise NotSupportedError.new "#{method} currently not supported in Windows os" if method =~ /^check_.+/ + raise NotSupportedError.new "#{method} currently not supported in Windows os" if method =~ /^check_.+/ super(method, *args) end From 35f9a89151b25b53ad333606a806c3f02777005b Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 13:28:36 +0900 Subject: [PATCH 29/43] Stringify method name With Ruby 1.8, method name is simbol and doesn't match with any strings --- lib/serverspec/commands/windows.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/commands/windows.rb b/lib/serverspec/commands/windows.rb index fbebf127..6229b88f 100644 --- a/lib/serverspec/commands/windows.rb +++ b/lib/serverspec/commands/windows.rb @@ -12,7 +12,7 @@ class NotSupportedError < Exception; end } def method_missing method, *args - raise NotSupportedError.new "#{method} currently not supported in Windows os" if method =~ /^check_.+/ + raise NotSupportedError.new "#{method} currently not supported in Windows os" if method.to_s =~ /^check_.+/ super(method, *args) end From 10ec30eb95e64df612246579862a5fc82846f30a Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 15:29:46 +0900 Subject: [PATCH 30/43] Fix for Ruby 1.8 --- lib/serverspec/backend/powershell/script_helper.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/serverspec/backend/powershell/script_helper.rb b/lib/serverspec/backend/powershell/script_helper.rb index f78a9bd8..9957b8d2 100644 --- a/lib/serverspec/backend/powershell/script_helper.rb +++ b/lib/serverspec/backend/powershell/script_helper.rb @@ -36,8 +36,14 @@ def add_pre_command(cmd) def encode_script script script_text = script.chars.to_a.join("\x00").chomp script_text << "\x00" unless script_text[-1].eql? "\x00" - script_text = script_text.encode('ASCII-8BIT') - Base64.strict_encode64(script_text) + if script_text.respond_to?(:encode) + script_text = script_text.encode('ASCII-8BIT') + end + if Base64.respond_to?(:strict_encode64) + Base64.strict_encode64(script_text) + else + [ script_text ].pack("m").strip + end end def create_script command From 1ef3747702fd42dc2561adb6d3021db7f2ed234d Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 15:58:46 +0900 Subject: [PATCH 31/43] Windows support of serverspec-init --- bin/serverspec-init | 27 +++++++++++++++-- lib/serverspec/setup.rb | 66 ++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/bin/serverspec-init b/bin/serverspec-init index 44e2cb8e..ffa55c87 100755 --- a/bin/serverspec-init +++ b/bin/serverspec-init @@ -8,14 +8,24 @@ Serverspec::Setup.run __END__ require 'serverspec' +<% if @os_type == 'UN*X' -%> require 'pathname' +<% end -%> <% if @backend_type == 'Ssh' -%> require 'net/ssh' <% end -%> +<% if @backend_type == 'WinRM' -%> +require 'winrm' +<% end -%> include Serverspec::Helper::<%= @backend_type %> +<% if @os_type == 'UN*X' -%> include Serverspec::Helper::DetectOS +<% else -%> +include Serverspec::Helper::Windows +<% end -%> +<% if @os_type == 'UN*X' -%> RSpec.configure do |c| if ENV['ASK_SUDO_PASSWORD'] require 'highline/import' @@ -23,7 +33,7 @@ RSpec.configure do |c| else c.sudo_password = ENV['SUDO_PASSWORD'] end -<% if @backend_type == 'Ssh' -%> + <%- if @backend_type == 'Ssh' -%> c.before :all do block = self.class.metadata[:example_group_block] if RUBY_VERSION.start_with?('1.8') @@ -37,7 +47,7 @@ RSpec.configure do |c| c.host = host options = Net::SSH::Config.for(c.host) user = options[:user] || Etc.getlogin -<% if @vagrant -%> + <%- if @vagrant -%> vagrant_up = `vagrant up #{@hostname}` config = `vagrant ssh-config #{@hostname}` if config != '' @@ -53,9 +63,20 @@ RSpec.configure do |c| end end end -<% end -%> + <%- end -%> c.ssh = Net::SSH.start(c.host, user, options) end end + <%- end -%> +end <% end -%> +<% if @backend_type == 'WinRM'-%> +RSpec.configure do |c| + user = + pass = + endpoint = "http://: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 +<% end -%> diff --git a/lib/serverspec/setup.rb b/lib/serverspec/setup.rb index fd37cb19..03524f7b 100644 --- a/lib/serverspec/setup.rb +++ b/lib/serverspec/setup.rb @@ -4,19 +4,15 @@ module Serverspec class Setup def self.run - prompt = <<-EOF -Select a backend type: - 1) SSH - 2) Exec (local) + ask_os_type -Select number: -EOF - print prompt.chop - num = gets.to_i - 1 - puts + if @os_type == 'UN*X' + ask_unix_backend + else + ask_windows_backend + end - @backend_type = [ 'Ssh', 'Exec' ][num] || 'Exec' if @backend_type == 'Ssh' print "Vagrant instance y/n: " @vagrant = gets.chomp @@ -38,12 +34,62 @@ def self.run else @hostname = 'localhost' end + [ 'spec', "spec/#{@hostname}" ].each { |dir| safe_mkdir(dir) } safe_create_spec safe_create_spec_helper safe_create_rakefile end + def self.ask_os_type + prompt = <<-EOF +Select OS type: + + 1) UN*X + 2) Windows + +Select number: +EOF + + print prompt.chop + num = gets.to_i - 1 + puts + + @os_type = [ 'UN*X', 'Windows' ][num] || 'UN*X' + end + + def self.ask_unix_backend + prompt = <<-EOF +Select a backend type: + + 1) SSH + 2) Exec (local) + +Select number: +EOF + print prompt.chop + num = gets.to_i - 1 + puts + + @backend_type = [ 'Ssh', 'Exec' ][num] || 'Exec' + end + + def self.ask_windows_backend + prompt = <<-EOF +Select a backend type: + + 1) WinRM + 2) Cmd (local) + +Select number: +EOF + print prompt.chop + num = gets.to_i - 1 + puts + + @backend_type = [ 'WinRM', 'Cmd' ][num] || 'Exec' + end + def self.safe_create_spec content = <<-EOF require 'spec_helper' From 619deacacb0aa81e587f10732a41dad140bb171c Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 23 Sep 2013 16:15:13 +0900 Subject: [PATCH 32/43] Remove duplicate methods --- lib/serverspec/backend/exec.rb | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/lib/serverspec/backend/exec.rb b/lib/serverspec/backend/exec.rb index 177f7353..25616489 100644 --- a/lib/serverspec/backend/exec.rb +++ b/lib/serverspec/backend/exec.rb @@ -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) @@ -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/ From b89dd708365721f9fdf087c0f2f1a259b66eacf4 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 12:03:24 +0900 Subject: [PATCH 33/43] Bump up version --- lib/serverspec/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/version.rb b/lib/serverspec/version.rb index e1f523ae..fb378baf 100644 --- a/lib/serverspec/version.rb +++ b/lib/serverspec/version.rb @@ -1,3 +1,3 @@ module Serverspec - VERSION = "0.8.1" + VERSION = "0.9.0" end From e5ecba4595596e734ef95ca34d5b15b192d85992 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 12:33:01 +0900 Subject: [PATCH 34/43] Fix bug of serverspec init gem install replace the content of executable file, so fix it. --- bin/serverspec-init | 75 -------------------------------------- lib/serverspec/setup.rb | 81 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 76 deletions(-) diff --git a/bin/serverspec-init b/bin/serverspec-init index ffa55c87..f199754f 100755 --- a/bin/serverspec-init +++ b/bin/serverspec-init @@ -5,78 +5,3 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) require 'serverspec' Serverspec::Setup.run - -__END__ -require 'serverspec' -<% if @os_type == 'UN*X' -%> -require 'pathname' -<% end -%> -<% if @backend_type == 'Ssh' -%> -require 'net/ssh' -<% end -%> -<% if @backend_type == 'WinRM' -%> -require 'winrm' -<% end -%> - -include Serverspec::Helper::<%= @backend_type %> -<% if @os_type == 'UN*X' -%> -include Serverspec::Helper::DetectOS -<% else -%> -include Serverspec::Helper::Windows -<% end -%> - -<% if @os_type == 'UN*X' -%> -RSpec.configure do |c| - if ENV['ASK_SUDO_PASSWORD'] - require 'highline/import' - c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false } - else - c.sudo_password = ENV['SUDO_PASSWORD'] - end - <%- if @backend_type == 'Ssh' -%> - c.before :all do - block = self.class.metadata[:example_group_block] - if RUBY_VERSION.start_with?('1.8') - file = block.to_s.match(/.*@(.*):[0-9]+>/)[1] - else - file = block.source_location.first - end - host = File.basename(Pathname.new(file).dirname) - if c.host != host - c.ssh.close if c.ssh - c.host = host - options = Net::SSH::Config.for(c.host) - user = options[:user] || Etc.getlogin - <%- if @vagrant -%> - vagrant_up = `vagrant up #{@hostname}` - config = `vagrant ssh-config #{@hostname}` - if config != '' - config.each_line do |line| - if match = /HostName (.*)/.match(line) - c.host = match[1] - elsif match = /User (.*)/.match(line) - user = match[1] - elsif match = /IdentityFile (.*)/.match(line) - options[:keys] = [match[1].gsub(/\"/,'')] - elsif match = /Port (.*)/.match(line) - options[:port] = match[1] - end - end - end - <%- end -%> - c.ssh = Net::SSH.start(c.host, user, options) - end - end - <%- end -%> -end -<% end -%> -<% if @backend_type == 'WinRM'-%> -RSpec.configure do |c| - user = - pass = - endpoint = "http://: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 -<% end -%> diff --git a/lib/serverspec/setup.rb b/lib/serverspec/setup.rb index 03524f7b..491d1020 100644 --- a/lib/serverspec/setup.rb +++ b/lib/serverspec/setup.rb @@ -139,7 +139,7 @@ def self.safe_mkdir(dir) def self.safe_create_spec_helper requirements = [] - content = ERB.new(DATA.read, nil, '-').result(binding) + content = ERB.new(spec_helper_template, nil, '-').result(binding) if File.exists? 'spec/spec_helper.rb' old_content = File.read('spec/spec_helper.rb') if old_content != content @@ -210,5 +210,84 @@ def self.auto_vagrant_configuration exit 1 end end + + def self.spec_helper_template + template = <<-EOF +require 'serverspec' +<% if @os_type == 'UN*X' -%> +require 'pathname' +<% end -%> +<% if @backend_type == 'Ssh' -%> +require 'net/ssh' +<% end -%> +<% if @backend_type == 'WinRM' -%> +require 'winrm' +<% end -%> + +include Serverspec::Helper::<%= @backend_type %> +<% if @os_type == 'UN*X' -%> +include Serverspec::Helper::DetectOS +<% else -%> +include Serverspec::Helper::Windows +<% end -%> + +<% if @os_type == 'UN*X' -%> +RSpec.configure do |c| + if ENV['ASK_SUDO_PASSWORD'] + require 'highline/import' + c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false } + else + c.sudo_password = ENV['SUDO_PASSWORD'] + end + <%- if @backend_type == 'Ssh' -%> + c.before :all do + block = self.class.metadata[:example_group_block] + if RUBY_VERSION.start_with?('1.8') + file = block.to_s.match(/.*@(.*):[0-9]+>/)[1] + else + file = block.source_location.first + end + host = File.basename(Pathname.new(file).dirname) + if c.host != host + c.ssh.close if c.ssh + c.host = host + options = Net::SSH::Config.for(c.host) + user = options[:user] || Etc.getlogin + <%- if @vagrant -%> + vagrant_up = `vagrant up #{@hostname}` + config = `vagrant ssh-config #{@hostname}` + if config != '' + config.each_line do |line| + if match = /HostName (.*)/.match(line) + c.host = match[1] + elsif match = /User (.*)/.match(line) + user = match[1] + elsif match = /IdentityFile (.*)/.match(line) + options[:keys] = [match[1].gsub(/\"/,'')] + elsif match = /Port (.*)/.match(line) + options[:port] = match[1] + end + end + end + <%- end -%> + c.ssh = Net::SSH.start(c.host, user, options) + end + end + <%- end -%> +end +<% end -%> +<% if @backend_type == 'WinRM'-%> +RSpec.configure do |c| + user = + pass = + endpoint = "http://: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 +<% end -%> +EOF + template + end end end From cd15036e8c77b06daa9c00430e16117e2d8a29e8 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 12:33:37 +0900 Subject: [PATCH 35/43] Bump up version --- lib/serverspec/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/version.rb b/lib/serverspec/version.rb index fb378baf..8f1d03bb 100644 --- a/lib/serverspec/version.rb +++ b/lib/serverspec/version.rb @@ -1,3 +1,3 @@ module Serverspec - VERSION = "0.9.0" + VERSION = "0.9.1" end From 6af20586885a128a7b46693454461cf9ca98b515 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 12:46:02 +0900 Subject: [PATCH 36/43] Bump up version --- lib/serverspec/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/version.rb b/lib/serverspec/version.rb index 8f1d03bb..d7bf346b 100644 --- a/lib/serverspec/version.rb +++ b/lib/serverspec/version.rb @@ -1,3 +1,3 @@ module Serverspec - VERSION = "0.9.1" + VERSION = "0.9.2" end From 17122b156f9be0306fe8a8f3d243a77affb59fee Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:14:25 +0900 Subject: [PATCH 37/43] Add freebsd to rakefile --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 669b4f5c..f7d77408 100644 --- a/Rakefile +++ b/Rakefile @@ -4,7 +4,7 @@ require 'rspec/core/rake_task' task :spec => 'spec:all' namespace :spec do - oses = %w( darwin debian gentoo redhat aix solaris solaris10 solaris11 smartos windows) + oses = %w( darwin debian gentoo redhat aix solaris solaris10 solaris11 smartos windows freebsd) task :all => [ oses.map {|os| "spec:#{os}" }, :helpers, :exec, :ssh, :cmd, :winrm, :powershell ].flatten From 9a953dc8e24a17b9e952109ababf6ffd2aa85b72 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:14:43 +0900 Subject: [PATCH 38/43] Fix arguments of the methods --- lib/serverspec/commands/freebsd.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/serverspec/commands/freebsd.rb b/lib/serverspec/commands/freebsd.rb index 7cfa97a6..ec3cb412 100644 --- a/lib/serverspec/commands/freebsd.rb +++ b/lib/serverspec/commands/freebsd.rb @@ -1,13 +1,11 @@ -require 'shellwords' - module Serverspec module Commands class FreeBSD < Base - def check_enabled(service) + def check_enabled(service, level=3) "service -e | grep -- #{escape(service)}" end - def check_installed(package) + def check_installed(package, version=nil) "pkg_version -X -s #{escape(package)}" end From 0322512a8ff2033800d381fea6b546eeefbd4e4a Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:15:03 +0900 Subject: [PATCH 39/43] Add specs for FreeBSD --- spec/freebsd/command_spec.rb | 48 ++++ spec/freebsd/cron_spec.rb | 21 ++ spec/freebsd/default_gateway_spec.rb | 16 ++ spec/freebsd/file_spec.rb | 367 +++++++++++++++++++++++++++ spec/freebsd/group_spec.rb | 21 ++ spec/freebsd/host_spec.rb | 58 +++++ spec/freebsd/package_spec.rb | 81 ++++++ spec/freebsd/php_config_spec.rb | 36 +++ spec/freebsd/port_spec.rb | 30 +++ spec/freebsd/routing_table_spec.rb | 120 +++++++++ spec/freebsd/service_spec.rb | 93 +++++++ spec/freebsd/user_spec.rb | 58 +++++ 12 files changed, 949 insertions(+) create mode 100644 spec/freebsd/command_spec.rb create mode 100644 spec/freebsd/cron_spec.rb create mode 100644 spec/freebsd/default_gateway_spec.rb create mode 100644 spec/freebsd/file_spec.rb create mode 100644 spec/freebsd/group_spec.rb create mode 100644 spec/freebsd/host_spec.rb create mode 100644 spec/freebsd/package_spec.rb create mode 100644 spec/freebsd/php_config_spec.rb create mode 100644 spec/freebsd/port_spec.rb create mode 100644 spec/freebsd/routing_table_spec.rb create mode 100644 spec/freebsd/service_spec.rb create mode 100644 spec/freebsd/user_spec.rb diff --git a/spec/freebsd/command_spec.rb b/spec/freebsd/command_spec.rb new file mode 100644 index 00000000..bece1602 --- /dev/null +++ b/spec/freebsd/command_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe command('cat /etc/resolv.conf') do + let(:stdout) { "nameserver 127.0.0.1\r\n" } + it { should return_stdout("nameserver 127.0.0.1") } + its(:command) { should eq 'cat /etc/resolv.conf' } +end + +describe 'complete matching of stdout' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "foocontent-should-be-includedbar\r\n" } + it { should_not return_stdout('content-should-be-included') } + end +end + +describe 'regexp matching of stdout' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "nameserver 127.0.0.1\r\n" } + it { should return_stdout(/127\.0\.0\.1/) } + end +end + +describe command('cat /etc/resolv.conf') do + let(:stdout) { "No such file or directory\r\n" } + it { should return_stderr("No such file or directory") } + its(:command) { should eq 'cat /etc/resolv.conf' } +end + +describe 'complete matching of stderr' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "No such file or directory\r\n" } + it { should_not return_stdout('file') } + end +end + +describe 'regexp matching of stderr' do + context command('cat /etc/resolv.conf') do + let(:stdout) { "No such file or directory\r\n" } + it { should return_stderr(/file/) } + end +end + +describe command('cat /etc/resolv.conf') do + it { should return_exit_status 0 } + its(:command) { should eq 'cat /etc/resolv.conf' } +end diff --git a/spec/freebsd/cron_spec.rb b/spec/freebsd/cron_spec.rb new file mode 100644 index 00000000..f88435a6 --- /dev/null +++ b/spec/freebsd/cron_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe cron do + it { should have_entry '* * * * * /usr/local/bin/batch.sh' } + its(:command) { should eq 'crontab -l | grep -- \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ /usr/local/bin/batch.sh' } +end + +describe cron do + it { should_not have_entry 'invalid entry' } +end + +describe cron do + it { should have_entry('* * * * * /usr/local/bin/batch.sh').with_user('root') } + its(:command) { should eq 'crontab -u root -l | grep -- \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ \\\\\\*\\ /usr/local/bin/batch.sh' } +end + +describe cron do + it { should_not have_entry('* * * * * /usr/local/bin/batch.sh').with_user('invalid-user') } +end diff --git a/spec/freebsd/default_gateway_spec.rb b/spec/freebsd/default_gateway_spec.rb new file mode 100644 index 00000000..e24c474f --- /dev/null +++ b/spec/freebsd/default_gateway_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe default_gateway do + let(:stdout) { "default via 192.168.1.1 dev eth1 \r\n" } + + its(:ipaddress) { should eq '192.168.1.1' } + its(:command) { should eq "ip route | grep -E '^default |^default '" } + + its(:interface) { should eq 'eth1' } + its(:command) { should eq "ip route | grep -E '^default |^default '" } + + its(:ipaddress) { should_not eq '192.168.1.2' } + its(:interface) { should_not eq 'eth0' } +end diff --git a/spec/freebsd/file_spec.rb b/spec/freebsd/file_spec.rb new file mode 100644 index 00000000..2ca9f78d --- /dev/null +++ b/spec/freebsd/file_spec.rb @@ -0,0 +1,367 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe file('/etc/ssh/sshd_config') do + it { should be_file } + its(:command) { should eq "test -f /etc/ssh/sshd_config" } +end + +describe file('/etc/invalid_file') do + it { should_not be_file } +end + +describe file('/etc/ssh') do + it { should be_directory } + its(:command) { should eq "test -d /etc/ssh" } +end + +describe file('/etc/invalid_directory') do + it { should_not be_directory } +end + +describe file('/var/run/unicorn.sock') do + it { should be_socket } + its(:command) { should eq "test -S /var/run/unicorn.sock" } +end + +describe file('/etc/invalid_socket') do + it { should_not be_socket } +end + +describe file('/etc/ssh/sshd_config') do + it { should contain 'This is the sshd server system-wide configuration file' } + its(:command) { should eq "grep -q -- This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config || grep -qF -- This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config" } +end + +describe file('/etc/ssh/sshd_config') do + it { should contain /^This is the sshd server system-wide configuration file/ } + its(:command) { should eq "grep -q -- \\^This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config || grep -qF -- \\^This\\ is\\ the\\ sshd\\ server\\ system-wide\\ configuration\\ file /etc/ssh/sshd_config" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain 'This is invalid text!!' } +end + +describe file('Gemfile') do + it { should contain('rspec').from(/^group :test do/).to(/^end/) } + its(:command) { should eq "sed -n /\\^group\\ :test\\ do/,/\\^end/p Gemfile | grep -q -- rspec - || sed -n /\\^group\\ :test\\ do/,/\\^end/p Gemfile | grep -qF -- rspec -" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain('This is invalid text!!').from(/^group :test do/).to(/^end/) } +end + +describe file('Gemfile') do + it { should contain('rspec').after(/^group :test do/) } + its(:command) { should eq "sed -n /\\^group\\ :test\\ do/,\\$p Gemfile | grep -q -- rspec - || sed -n /\\^group\\ :test\\ do/,\\$p Gemfile | grep -qF -- rspec -" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain('This is invalid text!!').after(/^group :test do/) } +end + +describe file('Gemfile') do + it { should contain('rspec').before(/^end/) } + its(:command) { should eq "sed -n 1,/\\^end/p Gemfile | grep -q -- rspec - || sed -n 1,/\\^end/p Gemfile | grep -qF -- rspec -" } +end + +describe file('/etc/ssh/sshd_config') do + it { should_not contain('This is invalid text!!').before(/^end/) } +end + +describe file('/etc/passwd') do + it { should be_mode 644 } + its(:command) { should eq "stat -c %a /etc/passwd | grep -- \\^644\\$" } +end + +describe file('/etc/passwd') do + it { should_not be_mode 'invalid' } +end + +describe file('/etc/passwd') do + it { should be_owned_by 'root' } + its(:command) { should eq "stat -c %U /etc/passwd | grep -- \\^root\\$" } +end + +describe file('/etc/passwd') do + it { should_not be_owned_by 'invalid-owner' } +end + +describe file('/etc/passwd') do + it { should be_grouped_into 'root' } + its(:command) { should eq "stat -c %G /etc/passwd | grep -- \\^root\\$" } +end + +describe file('/etc/passwd') do + it { should_not be_grouped_into 'invalid-group' } +end + +describe file('/etc/pam.d/system-auth') do + it { should be_linked_to '/etc/pam.d/system-auth-ac' } + its(:command) { should eq "stat -c %N /etc/pam.d/system-auth | grep -- /etc/pam.d/system-auth-ac" } +end + +describe file('dummy-link') do + it { should_not be_linked_to '/invalid/target' } +end + +describe file('/dev') do + let(:stdout) { "755\r\n" } + it { should be_readable } + its(:command) { should eq "stat -c %a /dev" } +end + +describe file('/dev') do + let(:stdout) { "333\r\n" } + it { should_not be_readable } +end + +describe file('/dev') do + let(:stdout) { "400\r\n" } + it { should be_readable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "044\r\n" } + it { should_not be_readable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "040\r\n" } + it { should be_readable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "404\r\n" } + it { should_not be_readable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "044\r\n" } + it { should be_readable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "443\r\n" } + it { should_not be_readable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "755\r\n" } + it { should be_writable } + its(:command) { should eq "stat -c %a /dev" } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable } +end + +describe file('/dev') do + let(:stdout) { "200\r\n" } + it { should be_writable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "030\r\n" } + it { should be_writable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should be_writable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "555\r\n" } + it { should_not be_writable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "755\r\n" } + it { should be_executable } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable } +end + +describe file('/dev') do + let(:stdout) { "100\r\n" } + it { should be_executable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable.by('owner') } +end + +describe file('/dev') do + let(:stdout) { "070\r\n" } + it { should be_executable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable.by('group') } +end + +describe file('/dev') do + let(:stdout) { "001\r\n" } + it { should be_executable.by('others') } +end + +describe file('/dev') do + let(:stdout) { "666\r\n" } + it { should_not be_executable.by('others') } +end + +describe file('/') do + it { should be_mounted } + its(:command) { should eq "mount | grep -w -- on\\ /" } +end + +describe file('/etc/invalid-mount') do + it { should_not be_mounted } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4', :options => { :rw => true } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4', :options => { :mode => 620 } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_root' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'xfs' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4', :options => { :rw => false } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4', :options => { :mode => 600 } ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'xfs', :device => '/dev/mapper/VolGroup-lv_root' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4', :device => '/dev/mapper/VolGroup-lv_r00t' ) } +end + +describe file('/etc/invalid-mount') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.with( :type => 'ext4' ) } +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_root', + :type => 'ext4', + :options => { + :rw => true, + :mode => 620, + } + ) + end +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should_not be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_root', + :type => 'ext4', + :options => { + :rw => true, + :mode => 620, + :bind => true, + } + ) + end +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should_not be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_root', + :type => 'ext4', + :options => { + :rw => true, + } + ) + end +end + +describe file('/') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it do + should_not be_mounted.only_with( + :device => '/dev/mapper/VolGroup-lv_roooooooooot', + :type => 'ext4', + :options => { + :rw => true, + :mode => 620, + } + ) + end +end + +describe file('/etc/invalid-mount') do + let(:stdout) { "/dev/mapper/VolGroup-lv_root on / type ext4 (rw,mode=620)\r\n" } + it { should_not be_mounted.only_with( :type => 'ext4' ) } +end + +describe file('/etc/services') do + it { should match_md5checksum '35435ea447c19f0ea5ef971837ab9ced' } + its(:command) { should eq "md5sum /etc/services | grep -iw -- \\^35435ea447c19f0ea5ef971837ab9ced" } +end + +describe file('invalid-file') do + it { should_not match_md5checksum 'INVALIDMD5CHECKSUM' } +end + +describe file('/etc/services') do + it { should match_sha256checksum '0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a' } + its(:command) { should eq "sha256sum /etc/services | grep -iw -- \\^0c3feee1353a8459f8c7d84885e6bc602ef853751ffdbce3e3b6dfa1d345fc7a" } +end + +describe file('invalid-file') do + it { should_not match_sha256checksum 'INVALIDSHA256CHECKSUM' } +end diff --git a/spec/freebsd/group_spec.rb b/spec/freebsd/group_spec.rb new file mode 100644 index 00000000..6f0010de --- /dev/null +++ b/spec/freebsd/group_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe group('root') do + it { should exist } + its(:command) { should eq "getent group | grep -wq -- root" } +end + +describe group('invalid-group') do + it { should_not exist } +end + +describe group('root') do + it { should have_gid 0 } + its(:command) { should eq "getent group | grep -w -- \\^root | cut -f 3 -d ':' | grep -w -- 0" } +end + +describe group('root') do + it { should_not have_gid 'invalid-gid' } +end diff --git a/spec/freebsd/host_spec.rb b/spec/freebsd/host_spec.rb new file mode 100644 index 00000000..febde258 --- /dev/null +++ b/spec/freebsd/host_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe host('127.0.0.1') do + it { should be_resolvable } + its(:command) { should eq "getent hosts 127.0.0.1" } +end + +describe host('invalid-name') do + it { should_not be_resolvable } +end + +describe host('127.0.0.1') do + it { should be_resolvable.by('hosts') } + its(:command) { should eq "grep -w -- 127.0.0.1 /etc/hosts" } +end + +describe host('invalid-name') do + it { should_not be_resolvable.by('hosts') } +end + +describe host('127.0.0.1') do + it { should be_resolvable.by('dns') } + its(:command) { should eq "nslookup -timeout=1 127.0.0.1" } +end + +describe host('invalid-name') do + it { should_not be_resolvable.by('dns') } +end + +describe host('127.0.0.1') do + it { should be_reachable } + its(:command) { should eq "ping -n 127.0.0.1 -w 5 -c 2" } +end + +describe host('invalid-host') do + it { should_not be_reachable } +end + +describe host('127.0.0.1') do + it { should be_reachable.with(:proto => "icmp", :timeout=> 1) } + its(:command) { should eq "ping -n 127.0.0.1 -w 1 -c 2" } +end + +describe host('127.0.0.1') do + it { should be_reachable.with(:proto => "tcp", :port => 22, :timeout=> 1) } + its(:command) { should eq "nc -vvvvzt 127.0.0.1 22 -w 1" } +end + +describe host('127.0.0.1') do + it { should be_reachable.with(:proto => "udp", :port => 53, :timeout=> 1) } + its(:command) { should eq "nc -vvvvzu 127.0.0.1 53 -w 1" } +end + +describe host('invalid-host') do + it { should_not be_reachable.with(:proto => "udp", :port => 53, :timeout=> 1) } +end diff --git a/spec/freebsd/package_spec.rb b/spec/freebsd/package_spec.rb new file mode 100644 index 00000000..164d9382 --- /dev/null +++ b/spec/freebsd/package_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe package('httpd') do + it { should be_installed } + its(:command) { should eq "pkg_version -X -s httpd" } +end + +describe package('invalid-package') do + it { should_not be_installed } +end + +describe package('httpd') do + it { should be_installed.with_version('2.2.15-28.el6') } + its(:command) { should eq "pkg_version -X -s httpd"} +end + +describe package('jekyll') do + it { should be_installed.by('gem') } + its(:command) { should eq "gem list --local | grep -w -- \\^jekyll" } +end + +describe package('invalid-gem') do + it { should_not be_installed.by('gem') } +end + +describe package('jekyll') do + it { should be_installed.by('gem').with_version('1.1.1') } + its(:command) { should eq "gem list --local | grep -w -- \\^jekyll | grep -w -- 1.1.1" } +end + +describe package('jekyll') do + it { should_not be_installed.by('gem').with_version('invalid-version') } +end + +describe package('bower') do + it { should be_installed.by('npm') } + its(:command) { should eq "npm ls bower -g" } +end + +describe package('invalid-npm-package') do + it { should_not be_installed.by('npm') } +end + +describe package('bower') do + it { should be_installed.by('npm').with_version('0.9.2') } + its(:command) { should eq "npm ls bower -g | grep -w -- 0.9.2" } +end + +describe package('bower') do + it { should_not be_installed.by('npm').with_version('invalid-version') } +end + + +describe package('mongo') do + it { should be_installed.by('pecl') } + its(:command) { should eq "pecl list | grep -w -- \\^mongo" } +end + +describe package('invalid-pecl') do + it { should_not be_installed.by('pecl') } +end + +describe package('mongo') do + it { should be_installed.by('pecl').with_version('1.4.1') } + its(:command) { should eq "pecl list | grep -w -- \\^mongo | grep -w -- 1.4.1" } +end + +describe package('mongo') do + it { should_not be_installed.by('pecl').with_version('invalid-version') } +end + +describe package('supervisor') do + it { should be_installed.by('pip').with_version('3.0') } + its(:command) { should eq "pip list | grep -w -- \\^supervisor | grep -w -- 3.0" } +end + +describe package('invalid-pip') do + it { should_not be_installed.by('pip').with_version('invalid-version') } +end diff --git a/spec/freebsd/php_config_spec.rb b/spec/freebsd/php_config_spec.rb new file mode 100644 index 00000000..382ded0b --- /dev/null +++ b/spec/freebsd/php_config_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe php_config('default_mimetype') do + let(:stdout) { 'text/html' } + its(:value) { should eq 'text/html' } + its(:command) { should eq "php -r 'echo get_cfg_var( \"default_mimetype\" );'" } +end + +describe php_config('default_mimetype') do + let(:stdout) { 'text/html' } + its(:value) { should_not eq 'text/plain' } +end + +describe php_config('session.cache_expire') do + let(:stdout) { '180' } + its(:value) { should eq 180 } + its(:command) { should eq "php -r 'echo get_cfg_var( \"session.cache_expire\" );'" } +end + +describe php_config('session.cache_expire') do + let(:stdout) { '180' } + its(:value) { should_not eq 360 } +end + +describe php_config('mbstring.http_output_conv_mimetypes') do + let(:stdout) { 'application' } + its(:value) { should match /application/ } + its(:command) { should eq "php -r 'echo get_cfg_var( \"mbstring.http_output_conv_mimetypes\" );'" } +end + +describe php_config('mbstring.http_output_conv_mimetypes') do + let(:stdout) { 'application' } + its(:value) { should_not match /html/ } +end diff --git a/spec/freebsd/port_spec.rb b/spec/freebsd/port_spec.rb new file mode 100644 index 00000000..343c2e60 --- /dev/null +++ b/spec/freebsd/port_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe port(80) do + it { should be_listening } + its(:command) { should eq 'sockstat -46l -p 80 | grep -- :80\\ ' } +end + +describe port('invalid') do + it { should_not be_listening } +end + +describe port(80) do + it { should be_listening.with("tcp") } + its(:command) { should eq 'netstat -tunl | grep -- \\^tcp\\ .\\*:80\\ ' } +end + +describe port(123) do + it { should be_listening.with("udp") } + its(:command) { should eq 'netstat -tunl | grep -- \\^udp\\ .\\*:123\\ ' } +end + +describe port(80) do + it { + expect { + should be_listening.with('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_listening` matcher doesn\'t support/) + } +end diff --git a/spec/freebsd/routing_table_spec.rb b/spec/freebsd/routing_table_spec.rb new file mode 100644 index 00000000..40c6e0f7 --- /dev/null +++ b/spec/freebsd/routing_table_spec.rb @@ -0,0 +1,120 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe routing_table do + let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it { should have_entry( :destination => '192.168.100.0/24' ) } + its(:command) { should eq "ip route | grep -E '^192.168.100.0/24 |^default '" } +end + +describe routing_table do + let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it { should_not have_entry( :destination => '192.168.100.100/24' ) } + its(:command) { should eq "ip route | grep -E '^192.168.100.100/24 |^default '" } +end + +describe routing_table do + let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it do + should have_entry( + :destination => '192.168.100.0/24', + :gateway => '192.168.100.1' + ) + end + + it do + should have_entry( + :destination => '192.168.100.0/24', + :gateway => '192.168.100.1', + :interface => 'eth1' + ) + end + + it do + should_not have_entry( + :gateway => '192.168.100.1', + :interface => 'eth1' + ) + end + + it do + should_not have_entry( + :destination => '192.168.100.0/32', + :gateway => '192.168.100.1', + :interface => 'eth1' + ) + end +end + +describe routing_table do + let(:stdout) { "192.168.200.0/24 via 192.168.200.1 dev eth0 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } + it { should have_entry( :destination => '192.168.200.0/24' ) } + it { should_not have_entry( :destination => '192.168.200.200/24' ) } + + it do + should have_entry( + :destination => '192.168.200.0/24', + :gateway => '192.168.200.1' + ) + end + + it do + should have_entry( + :destination => '192.168.200.0/24', + :gateway => '192.168.200.1', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :gateway => '192.168.200.1', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :destination => '192.168.200.0/32', + :gateway => '192.168.200.1', + :interface => 'eth0' + ) + end +end + +describe routing_table do + let(:stdout) { "default via 10.0.2.2 dev eth0 \r\n" } + it { should have_entry( :destination => 'default' ) } + it { should_not have_entry( :destination => 'defaulth' ) } + + it do + should have_entry( + :destination => 'default', + :gateway => '10.0.2.2' + ) + end + + it do + should have_entry( + :destination => 'default', + :gateway => '10.0.2.2', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :gateway => '10.0.2.2', + :interface => 'eth0' + ) + end + + it do + should_not have_entry( + :destination => 'default', + :gateway => '10.0.2.1', + :interface => 'eth0' + ) + end +end diff --git a/spec/freebsd/service_spec.rb b/spec/freebsd/service_spec.rb new file mode 100644 index 00000000..9f3a3a19 --- /dev/null +++ b/spec/freebsd/service_spec.rb @@ -0,0 +1,93 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + +describe service('sshd') do + it { should be_enabled } + its(:command) { should eq "service -e | grep -- sshd" } +end + +describe service('invalid-service') do + it { should_not be_enabled } +end + +describe service('sshd') do + it { should be_enabled.with_level(4) } + its(:command) { should eq "service -e | grep -- sshd" } +end + +describe service('invalid-service') do + it { should_not be_enabled.with_level(4) } +end + +describe service('sshd') do + it { should be_running } + its(:command) { should eq "service sshd status" } +end + +describe service('invalid-daemon') do + it { should_not be_running } +end + +describe service('sshd') do + let(:stdout) { "sshd is stopped\r\n" } + it { should be_running } +end + +describe service('sshd') do + it { should be_running.under('supervisor') } + its(:command) { should eq "supervisorctl status sshd | grep RUNNING" } +end + +describe service('invalid-daemon') do + it { should_not be_running.under('supervisor') } +end + +describe service('sshd') do + it { should be_running.under('upstart') } + its(:command) { should eq "initctl status sshd | grep running" } +end + +describe service('invalid-daemon') do + it { should_not be_running.under('upstart') } +end + +describe service('sshd') do + it { + expect { + should be_running.under('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_running` matcher doesn\'t support/) + } +end + +describe service('sshd') do + let(:stdout) { "Process 'sshd'\r\n status running\r\n monitoring status monitored" } + it { should be_monitored_by('monit') } + its(:command) { should eq "monit status" } +end + +describe service('sshd') do + let(:stdout) { "Process 'sshd'\r\n status not monitored\r\n monitoring status not monitored" } + it { should_not be_monitored_by('monit') } +end + +describe service('invalid-daemon') do + it { should_not be_monitored_by('monit') } +end + +describe service('unicorn') do + it { should be_monitored_by('god') } + its(:command) { should eq "god status unicorn" } +end + +describe service('invalid-daemon') do + it { should_not be_monitored_by('god') } +end + +describe service('sshd') do + it { + expect { + should be_monitored_by('not implemented') + }.to raise_error(ArgumentError, %r/\A`be_monitored_by` matcher doesn\'t support/) + } +end diff --git a/spec/freebsd/user_spec.rb b/spec/freebsd/user_spec.rb new file mode 100644 index 00000000..a4b1214f --- /dev/null +++ b/spec/freebsd/user_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +include Serverspec::Helper::FreeBSD + + +describe user('root') do + it { should exist } + its(:command) { should eq "id root" } +end + +describe user('invalid-user') do + it { should_not exist } +end + +describe user('root') do + it { should belong_to_group 'root' } + its(:command) { should eq "id root | awk '{print $3}' | grep -- root" } +end + +describe user('root') do + it { should_not belong_to_group 'invalid-group' } +end + +describe user('root') do + it { should have_uid 0 } + its(:command) { should eq "id root | grep -- \\^uid\\=0\\(" } +end + +describe user('root') do + it { should_not have_uid 'invalid-uid' } +end + +describe user('root') do + it { should have_login_shell '/bin/bash' } + its(:command) { should eq "getent passwd root | cut -f 7 -d ':' | grep -w -- /bin/bash" } +end + +describe user('root') do + it { should_not have_login_shell 'invalid-login-shell' } +end + +describe user('root') do + it { should have_home_directory '/root' } + its(:command) { should eq "getent passwd root | cut -f 6 -d ':' | grep -w -- /root" } +end + +describe user('root') do + it { should_not have_home_directory 'invalid-home-directory' } +end + +describe user('root') do + it { should have_authorized_key 'ssh-rsa ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH foo@bar.local' } + its(:command) { should eq "grep -w -- ssh-rsa\\ ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH ~root/.ssh/authorized_keys" } +end + +describe user('root') do + it { should_not have_authorized_key 'invalid-key' } +end From 2540b44273bca78668cfbf4fa28b662dda26f6e9 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:20:41 +0900 Subject: [PATCH 40/43] Bump up version --- lib/serverspec/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/version.rb b/lib/serverspec/version.rb index d7bf346b..6d4dfa28 100644 --- a/lib/serverspec/version.rb +++ b/lib/serverspec/version.rb @@ -1,3 +1,3 @@ module Serverspec - VERSION = "0.9.2" + VERSION = "0.9.3" end From a2af5f0343fea9ed8233808e074a2b6858c486ad Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:28:06 +0900 Subject: [PATCH 41/43] Aix -> AIX --- lib/serverspec.rb | 2 +- lib/serverspec/backend/exec.rb | 2 +- lib/serverspec/commands/aix.rb | 2 +- lib/serverspec/helper/aix.rb | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/serverspec.rb b/lib/serverspec.rb index 0b7f9599..3896f3a6 100644 --- a/lib/serverspec.rb +++ b/lib/serverspec.rb @@ -37,7 +37,7 @@ 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::AIX, :os => :aix) c.include(Serverspec::Helper::Solaris, :os => :solaris) c.include(Serverspec::Helper::Solaris10, :os => :solaris10) c.include(Serverspec::Helper::Solaris11, :os => :solaris11) diff --git a/lib/serverspec/backend/exec.rb b/lib/serverspec/backend/exec.rb index 69d7523a..a91e15ed 100644 --- a/lib/serverspec/backend/exec.rb +++ b/lib/serverspec/backend/exec.rb @@ -167,7 +167,7 @@ def check_os elsif run_command('ls /etc/gentoo-release')[:exit_status] == 0 'Gentoo' elsif run_command('uname -s')[:stdout] =~ /AIX/i - 'Aix' + 'AIX' elsif (os = run_command('uname -sr')[:stdout]) && os =~ /SunOS/i if os =~ /5.10/ 'Solaris10' diff --git a/lib/serverspec/commands/aix.rb b/lib/serverspec/commands/aix.rb index 69da0a12..efbc3a3e 100644 --- a/lib/serverspec/commands/aix.rb +++ b/lib/serverspec/commands/aix.rb @@ -2,7 +2,7 @@ module Serverspec module Commands - class Aix < Base + class AIX < Base class NotImplementedError < Exception; end def check_access_by_user(file, user, access) diff --git a/lib/serverspec/helper/aix.rb b/lib/serverspec/helper/aix.rb index 75a19d2e..71ecb163 100644 --- a/lib/serverspec/helper/aix.rb +++ b/lib/serverspec/helper/aix.rb @@ -1,8 +1,8 @@ module Serverspec module Helper - module Aix + module AIX def commands - Serverspec::Commands::Aix.new + Serverspec::Commands::AIX.new end end end From 29a4f939713d41db361b14d9a79e77b7777f5e75 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:42:55 +0900 Subject: [PATCH 42/43] Fix specs for AIX --- spec/aix/command_spec.rb | 2 +- spec/aix/commands_spec.rb | 13 ------------- spec/aix/cron_spec.rb | 2 +- spec/aix/default_gateway_spec.rb | 2 +- spec/aix/file_spec.rb | 17 ++++++----------- spec/aix/group_spec.rb | 4 ++-- spec/aix/host_spec.rb | 2 +- spec/aix/interface_spec.rb | 24 ------------------------ spec/aix/iptables_spec.rb | 21 --------------------- spec/aix/kernel_module_spec.rb | 12 ------------ spec/aix/linux_kernel_parameter_spec.rb | 2 +- spec/aix/package_spec.rb | 11 +++-------- spec/aix/php_config_spec.rb | 2 +- spec/aix/port_spec.rb | 4 ++-- spec/aix/routing_table_spec.rb | 2 +- spec/aix/selinux_spec.rb | 18 ------------------ spec/aix/service_spec.rb | 8 ++++---- spec/aix/user_spec.rb | 9 ++++----- spec/aix/yumrepo_spec.rb | 25 ------------------------- spec/aix/zfs_spec.rb | 18 ------------------ 20 files changed, 28 insertions(+), 170 deletions(-) delete mode 100644 spec/aix/commands_spec.rb delete mode 100644 spec/aix/interface_spec.rb delete mode 100644 spec/aix/iptables_spec.rb delete mode 100644 spec/aix/kernel_module_spec.rb delete mode 100644 spec/aix/selinux_spec.rb delete mode 100644 spec/aix/yumrepo_spec.rb delete mode 100644 spec/aix/zfs_spec.rb diff --git a/spec/aix/command_spec.rb b/spec/aix/command_spec.rb index 1f23b424..89ab4fed 100644 --- a/spec/aix/command_spec.rb +++ b/spec/aix/command_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe command('cat /etc/resolv.conf') do let(:stdout) { "nameserver 127.0.0.1\r\n" } diff --git a/spec/aix/commands_spec.rb b/spec/aix/commands_spec.rb deleted file mode 100644 index 7dc4aec6..00000000 --- a/spec/aix/commands_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe 'check_yumrepo' do - subject { commands.check_yumrepo('epel') } - it { should eq 'yum repolist all -C | grep ^epel' } -end - -describe 'check_yumrepo_enabled' do - subject { commands.check_yumrepo_enabled('epel') } - it { should eq 'yum repolist all -C | grep ^epel | grep enabled' } -end diff --git a/spec/aix/cron_spec.rb b/spec/aix/cron_spec.rb index ba30ec20..5fc868f0 100644 --- a/spec/aix/cron_spec.rb +++ b/spec/aix/cron_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe cron do it { should have_entry '* * * * * /usr/local/bin/batch.sh' } diff --git a/spec/aix/default_gateway_spec.rb b/spec/aix/default_gateway_spec.rb index 2250a789..0f512594 100644 --- a/spec/aix/default_gateway_spec.rb +++ b/spec/aix/default_gateway_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe default_gateway do let(:stdout) { "default via 192.168.1.1 dev eth1 \r\n" } diff --git a/spec/aix/file_spec.rb b/spec/aix/file_spec.rb index 444939b0..94e955b2 100644 --- a/spec/aix/file_spec.rb +++ b/spec/aix/file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe file('/etc/ssh/sshd_config') do it { should be_file } @@ -72,16 +72,11 @@ describe file('/etc/passwd') do it { should be_mode 644 } - its(:command) { should eq "stat -c %a /etc/passwd | grep -- \\^644\\$" } -end - -describe file('/etc/passwd') do - it { should_not be_mode 'invalid' } end describe file('/etc/passwd') do it { should be_owned_by 'root' } - its(:command) { should eq "stat -c %U /etc/passwd | grep -- \\^root\\$" } + its(:command) { should eq "ls -al /etc/passwd | awk '{print $3}' | grep -- \\^root\\$" } end describe file('/etc/passwd') do @@ -90,7 +85,7 @@ describe file('/etc/passwd') do it { should be_grouped_into 'root' } - its(:command) { should eq "stat -c %G /etc/passwd | grep -- \\^root\\$" } + its(:command) { should eq "ls -al /etc/passwd | awk '{print $4}' | grep -- \\^root\\$" } end describe file('/etc/passwd') do @@ -149,7 +144,7 @@ describe file('/tmp') do it { should be_readable.by_user('mail') } - its(:command) { should eq "runuser -s /bin/sh -c \"test -r /tmp\" mail" } + its(:command) { should eq "su -s sh -c \"test -r /tmp\" mail" } end describe file('/tmp') do @@ -199,7 +194,7 @@ describe file('/tmp') do it { should be_writable.by_user('mail') } - its(:command) { should eq "runuser -s /bin/sh -c \"test -w /tmp\" mail" } + its(:command) { should eq "su -s sh -c \"test -w /tmp\" mail" } end describe file('/tmp') do @@ -249,7 +244,7 @@ describe file('/tmp') do it { should be_executable.by_user('mail') } - its(:command) { should eq "runuser -s /bin/sh -c \"test -x /tmp\" mail" } + its(:command) { should eq "su -s sh -c \"test -x /tmp\" mail" } end describe file('/tmp') do diff --git a/spec/aix/group_spec.rb b/spec/aix/group_spec.rb index 994945b2..c05c38f9 100644 --- a/spec/aix/group_spec.rb +++ b/spec/aix/group_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe group('root') do it { should exist } @@ -13,7 +13,7 @@ describe group('root') do it { should have_gid 0 } - its(:command) { should eq "getent group | grep -w -- \\^root | cut -f 3 -d ':' | grep -w -- 0" } + its(:command) { should eq "cat etc/group | grep -w -- \\^root | cut -f 3 -d ':' | grep -w -- 0" } end describe group('root') do diff --git a/spec/aix/host_spec.rb b/spec/aix/host_spec.rb index 913aba67..c16fb6da 100644 --- a/spec/aix/host_spec.rb +++ b/spec/aix/host_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe host('127.0.0.1') do it { should be_resolvable } diff --git a/spec/aix/interface_spec.rb b/spec/aix/interface_spec.rb deleted file mode 100644 index 9118092e..00000000 --- a/spec/aix/interface_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe interface('eth0') do - let(:stdout) { '1000' } - its(:speed) { should eq 1000 } - its(:command) { should eq "ethtool eth0 | grep Speed | gawk '{print gensub(/Speed: ([0-9]+)Mb\\/s/,\"\\\\1\",\"\")}'" } -end - -describe interface('eth0') do - it { should have_ipv4_address("192.168.10.10") } - its(:command) { should eq "ip addr show eth0 | grep 'inet 192\\.168\\.10\\.10/'" } -end - -describe interface('eth0') do - it { should have_ipv4_address("192.168.10.10/24") } - its(:command) { should eq "ip addr show eth0 | grep 'inet 192\\.168\\.10\\.10/24 '" } -end - -describe interface('invalid-interface') do - let(:stdout) { '1000' } - its(:speed) { should_not eq 100 } -end diff --git a/spec/aix/iptables_spec.rb b/spec/aix/iptables_spec.rb deleted file mode 100644 index aea079be..00000000 --- a/spec/aix/iptables_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe iptables do - it { should have_rule '-P INPUT ACCEPT' } - its(:command) { should eq "iptables -S | grep -- -P\\ INPUT\\ ACCEPT" } -end - -describe iptables do - it { should_not have_rule 'invalid-rule' } -end - -describe iptables do - it { should have_rule('-P INPUT ACCEPT').with_table('mangle').with_chain('INPUT') } - its(:command) { should eq "iptables -t mangle -S INPUT | grep -- -P\\ INPUT\\ ACCEPT" } -end - -describe iptables do - it { should_not have_rule('invalid-rule').with_table('mangle').with_chain('INPUT') } -end diff --git a/spec/aix/kernel_module_spec.rb b/spec/aix/kernel_module_spec.rb deleted file mode 100644 index d9708318..00000000 --- a/spec/aix/kernel_module_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe kernel_module('lp') do - it { should be_loaded } - its(:command) { should eq "lsmod | grep ^lp" } -end - -describe kernel_module('invalid-module') do - it { should_not be_loaded } -end diff --git a/spec/aix/linux_kernel_parameter_spec.rb b/spec/aix/linux_kernel_parameter_spec.rb index b04e52a8..7e164d7a 100644 --- a/spec/aix/linux_kernel_parameter_spec.rb +++ b/spec/aix/linux_kernel_parameter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe linux_kernel_parameter('net.ipv4.tcp_syncookies') do let(:stdout) { "1\n" } diff --git a/spec/aix/package_spec.rb b/spec/aix/package_spec.rb index ee1cd44e..58973945 100644 --- a/spec/aix/package_spec.rb +++ b/spec/aix/package_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe package('httpd') do it { should be_installed } - its(:command) { should eq "rpm -q httpd" } + its(:command) { should eq "lslpp -L httpd" } end describe package('invalid-package') do @@ -17,12 +17,7 @@ describe package('httpd') do it { should be_installed.with_version('2.2.15-28.el6') } - its(:command) { should eq "rpm -q httpd | grep -w -- 2.2.15-28.el6" } -end - -describe package('httpd') do - it { should be_installed.by('rpm').with_version('2.2.15-28.el6') } - its(:command) { should eq "rpm -q httpd | grep -w -- 2.2.15-28.el6" } + its(:command) { should eq "lslpp -L httpd | awk '{print $2}' | grep -w -- 2.2.15-28.el6" } end describe package('httpd') do diff --git a/spec/aix/php_config_spec.rb b/spec/aix/php_config_spec.rb index 56b2f37f..7e6dcbc4 100644 --- a/spec/aix/php_config_spec.rb +++ b/spec/aix/php_config_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe php_config('default_mimetype') do let(:stdout) { 'text/html' } diff --git a/spec/aix/port_spec.rb b/spec/aix/port_spec.rb index f427a38f..55bccc5e 100644 --- a/spec/aix/port_spec.rb +++ b/spec/aix/port_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe port(80) do it { should be_listening } - its(:command) { should eq 'netstat -tunl | grep -- :80\\ ' } + its(:command) { should eq "netstat -an -f inet | awk '{print $4}' | grep -- *.80 " } end describe port('invalid') do diff --git a/spec/aix/routing_table_spec.rb b/spec/aix/routing_table_spec.rb index 6c69863d..6c2713df 100644 --- a/spec/aix/routing_table_spec.rb +++ b/spec/aix/routing_table_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe routing_table do let(:stdout) { "192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.10 \r\ndefault via 192.168.100.1 dev eth0 \r\n" } diff --git a/spec/aix/selinux_spec.rb b/spec/aix/selinux_spec.rb deleted file mode 100644 index 72809877..00000000 --- a/spec/aix/selinux_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe selinux do - it { should be_enforcing } - its(:command) { should eq "getenforce | grep -i -- enforcing && grep -i -- ^SELINUX=enforcing$ /etc/selinux/config" } -end - -describe selinux do - it { should be_permissive } - its(:command) { should eq "getenforce | grep -i -- permissive && grep -i -- ^SELINUX=permissive$ /etc/selinux/config" } -end - -describe selinux do - it { should be_disabled } - its(:command) { should eq "test ! -f /etc/selinux/config || (getenforce | grep -i -- disabled && grep -i -- ^SELINUX=disabled$ /etc/selinux/config)" } -end diff --git a/spec/aix/service_spec.rb b/spec/aix/service_spec.rb index 925ee788..384cd9cd 100644 --- a/spec/aix/service_spec.rb +++ b/spec/aix/service_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' -include Serverspec::Helper::RedHat +include Serverspec::Helper::AIX describe service('sshd') do it { should be_enabled } - its(:command) { should eq "chkconfig --list sshd | grep 3:on" } + its(:command) { should eq "lssrc -s sshd | grep active" } end describe service('invalid-service') do @@ -13,7 +13,7 @@ describe service('sshd') do it { should be_enabled.with_level(4) } - its(:command) { should eq "chkconfig --list sshd | grep 4:on" } + its(:command) { should eq "lssrc -s sshd | grep active" } end describe service('invalid-service') do @@ -22,7 +22,7 @@ describe service('sshd') do it { should be_running } - its(:command) { should eq "service sshd status" } + its(:command) { should eq "ps -ef | grep -v grep | grep sshd" } end describe service('invalid-daemon') do diff --git a/spec/aix/user_spec.rb b/spec/aix/user_spec.rb index 0049a3fe..2e1c3565 100644 --- a/spec/aix/user_spec.rb +++ b/spec/aix/user_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -include Serverspec::Helper::RedHat - +include Serverspec::Helper::AIX describe user('root') do it { should exist } @@ -14,7 +13,7 @@ describe user('root') do it { should belong_to_group 'root' } - its(:command) { should eq "id root | awk '{print $3}' | grep -- root" } + its(:command) { should eq "lsuser -a groups root | awk -F'=' '{print $2}'| sed -e 's/,/ /g' |grep -w -- root" } end describe user('root') do @@ -32,7 +31,7 @@ describe user('root') do it { should have_login_shell '/bin/bash' } - its(:command) { should eq "getent passwd root | cut -f 7 -d ':' | grep -w -- /bin/bash" } + its(:command) { should eq "lsuser -a shell root |awk -F'=' '{print $2}' | grep -w -- /bin/bash" } end describe user('root') do @@ -41,7 +40,7 @@ describe user('root') do it { should have_home_directory '/root' } - its(:command) { should eq "getent passwd root | cut -f 6 -d ':' | grep -w -- /root" } + its(:command) { should eq "lsuser -a home root | awk -F'=' '{print $2}' | grep -w -- /root" } end describe user('root') do diff --git a/spec/aix/yumrepo_spec.rb b/spec/aix/yumrepo_spec.rb deleted file mode 100644 index 894fdd84..00000000 --- a/spec/aix/yumrepo_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe 'Serverspec yumrepo matchers of Red Hat family' do - describe 'exist' do - describe yumrepo('epel') do - it { should exist } - end - - describe yumrepo('invalid-repository') do - it { should_not exist } - end - end - - describe 'be_enabled' do - describe yumrepo('epel') do - it { should be_enabled } - end - - describe yumrepo('invalid-repository') do - it { should_not be_enabled } - end - end -end diff --git a/spec/aix/zfs_spec.rb b/spec/aix/zfs_spec.rb deleted file mode 100644 index 349736a4..00000000 --- a/spec/aix/zfs_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -include Serverspec::Helper::RedHat - -describe zfs('rpool') do - it { should exist } - its(:command) { should eq "zfs list -H rpool" } -end - -describe zfs('rpool') do - it { should have_property 'mountpoint' => '/rpool' } - its(:command) { should eq "zfs list -H -o mountpoint rpool | grep -- \\^/rpool\\$" } -end - -describe zfs('rpool') do - it { should have_property 'mountpoint' => '/rpool', 'compression' => 'off' } - its(:command) { should eq "zfs list -H -o compression rpool | grep -- \\^off\\$ && zfs list -H -o mountpoint rpool | grep -- \\^/rpool\\$" } -end From 038ad41b3cc1f1eac999ba298a8decdeef48271e Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Tue, 24 Sep 2013 13:49:22 +0900 Subject: [PATCH 43/43] Bump up version --- lib/serverspec/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serverspec/version.rb b/lib/serverspec/version.rb index 6d4dfa28..d489485b 100644 --- a/lib/serverspec/version.rb +++ b/lib/serverspec/version.rb @@ -1,3 +1,3 @@ module Serverspec - VERSION = "0.9.3" + VERSION = "0.9.4" end