specinfra 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +10 -0
  3. data/lib/specinfra.rb +24 -2
  4. data/lib/specinfra/backend.rb +7 -0
  5. data/lib/specinfra/backend/base.rb +31 -0
  6. data/lib/specinfra/backend/cmd.rb +39 -0
  7. data/lib/specinfra/backend/exec.rb +218 -0
  8. data/lib/specinfra/backend/powershell/command.rb +40 -0
  9. data/lib/specinfra/backend/powershell/script_helper.rb +85 -0
  10. data/lib/specinfra/backend/powershell/support/check_file_access_rules.ps1 +8 -0
  11. data/lib/specinfra/backend/powershell/support/crop_text.ps1 +11 -0
  12. data/lib/specinfra/backend/powershell/support/find_group.ps1 +8 -0
  13. data/lib/specinfra/backend/powershell/support/find_installed_application.ps1 +7 -0
  14. data/lib/specinfra/backend/powershell/support/find_service.ps1 +5 -0
  15. data/lib/specinfra/backend/powershell/support/find_user.ps1 +8 -0
  16. data/lib/specinfra/backend/powershell/support/find_usergroup.ps1 +9 -0
  17. data/lib/specinfra/backend/powershell/support/is_port_listening.ps1 +13 -0
  18. data/lib/specinfra/backend/ssh.rb +93 -0
  19. data/lib/specinfra/backend/winrm.rb +26 -0
  20. data/lib/specinfra/configuration.rb +12 -0
  21. data/lib/specinfra/helper.rb +7 -0
  22. data/lib/specinfra/helper/backend.rb +18 -0
  23. data/lib/specinfra/helper/configuration.rb +37 -0
  24. data/lib/specinfra/helper/detect_os.rb +18 -0
  25. data/lib/specinfra/helper/os.rb +27 -0
  26. data/lib/specinfra/helper/properties.rb +14 -0
  27. data/lib/specinfra/properties.rb +17 -0
  28. data/lib/specinfra/version.rb +1 -1
  29. data/spec/helpers/properties_spec.rb +11 -0
  30. data/spec/spec_helper.rb +4 -0
  31. metadata +31 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 858dd119eb2a4777139bf69b7fa5b8f79b2e33a1
4
- data.tar.gz: f46f73e18a687301dfcc5e483477fa810a0c6bbd
3
+ metadata.gz: 5e123d78d06d4075c043995799a8c0e9f2c3593d
4
+ data.tar.gz: 9a4ce0fdd1c2ff46c42d8323d3a2d31ffc4185e3
5
5
  SHA512:
6
- metadata.gz: 3d2a716331eb898b298fe517cd70b8538dd506267c8c13a590507c7aa351f1bb12e56de8fa09c6cf6f0944056581389104870adea1cbebb7cdffeaffabb816d8
7
- data.tar.gz: 7000c61a15d2051f3d51b700fded57049c3b6af480c89bdac5ca873fc6434bb966316a314688c448fcdabc6e905539cdb55b785b78052776ff677c8e6bdc766e
6
+ metadata.gz: 7440fae579eef9fa415ade153a00dbd556ef529fd4f8bd4f3cc0404ec8d2486e403e4dfcdffe0779e425d73f9e885f3eb14f64008e57445663dc32f6c151ddfa
7
+ data.tar.gz: 7320a36b630ee5ed5317a12546f94b54b79c0697e4b42e04dd5663ea34a8b815ec1847d53572133c4f5a7f5d4d94ff7531e27e81a15b7c02356235ccd607df44
data/Rakefile CHANGED
@@ -1 +1,11 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :spec => 'spec:all'
5
+
6
+ namespace :spec do
7
+ RSpec::Core::RakeTask.new(:all) do |t|
8
+ t.pattern = "spec/**/*_spec.rb"
9
+ end
10
+ end
11
+
data/lib/specinfra.rb CHANGED
@@ -1,5 +1,27 @@
1
1
  require "specinfra/version"
2
+ require "specinfra/helper"
3
+ require "specinfra/backend"
4
+ require "specinfra/configuration"
2
5
 
3
- module Specinfra
4
- # Your code goes here...
6
+ include SpecInfra
7
+
8
+ module SpecInfra
9
+ class << self
10
+ def configuration
11
+ SpecInfra::Configuration
12
+ end
13
+ end
14
+ end
15
+
16
+ RSpec.configure do |c|
17
+ c.include(SpecInfra::Helper::Configuration)
18
+ c.add_setting :os, :default => nil
19
+ c.add_setting :host, :default => nil
20
+ c.add_setting :ssh, :default => nil
21
+ c.add_setting :sudo_password, :default => nil
22
+ c.add_setting :winrm, :default => nil
23
+ SpecInfra.configuration.defaults.each { |k, v| c.add_setting k, :default => v }
24
+ c.before :each do
25
+ backend.set_example(example) if defined?(SPEC_TYPE)
26
+ end
5
27
  end
@@ -0,0 +1,7 @@
1
+ require 'specinfra/backend/base'
2
+ require 'specinfra/backend/exec'
3
+ require 'specinfra/backend/ssh'
4
+ require 'specinfra/backend/powershell/script_helper'
5
+ require 'specinfra/backend/powershell/command'
6
+ require 'specinfra/backend/cmd'
7
+ require 'specinfra/backend/winrm'
@@ -0,0 +1,31 @@
1
+ require 'singleton'
2
+
3
+ module SpecInfra
4
+ module Backend
5
+ class Base
6
+ include Singleton
7
+
8
+ def set_commands(c)
9
+ @commands = c
10
+ end
11
+
12
+ def set_example(e)
13
+ @example = e
14
+ end
15
+
16
+ def commands
17
+ @commands
18
+ end
19
+
20
+ def check_zero(cmd, *args)
21
+ ret = run_command(commands.send(cmd, *args))
22
+ ret[:exit_status] == 0
23
+ end
24
+
25
+ # Default action is to call check_zero with args
26
+ def method_missing(meth, *args, &block)
27
+ check_zero(meth, *args)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ require 'open3'
2
+
3
+ module SpecInfra
4
+ module Backend
5
+ class Cmd < Base
6
+ include PowerShell::ScriptHelper
7
+
8
+ def run_command(cmd, opts={})
9
+ script = create_script(cmd)
10
+ result = execute_script %Q{powershell -encodedCommand #{encode_script(script)}}
11
+
12
+ if @example
13
+ @example.metadata[:command] = script
14
+ @example.metadata[:stdout] = result[:stdout] + result[:stderr]
15
+ end
16
+ { :stdout => result[:stdout], :stderr => result[:stderr],
17
+ :exit_status => result[:status], :exit_signal => nil }
18
+ end
19
+
20
+ def execute_script script
21
+ if Open3.respond_to? :capture3
22
+ stdout, stderr, status = Open3.capture3(script)
23
+ # powershell still exits with 0 even if there are syntax errors, although it spits the error out into stderr
24
+ # so we have to resort to return an error exit code if there is anything in the standard error
25
+ status = 1 if status == 0 and !stderr.empty?
26
+ { :stdout => stdout, :stderr => stderr, :status => status }
27
+ else
28
+ stdout = `#{script} 2>&1`
29
+ { :stdout => stdout, :stderr => nil, :status => $? }
30
+ end
31
+ end
32
+
33
+ def check_os
34
+ # Dirty hack for specs
35
+ 'Windows'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,218 @@
1
+ require 'singleton'
2
+
3
+ module SpecInfra
4
+ module Backend
5
+ class Exec < Base
6
+
7
+ def run_command(cmd, opts={})
8
+ cmd = build_command(cmd)
9
+ cmd = add_pre_command(cmd)
10
+ stdout = run_with_no_ruby_environment do
11
+ `#{build_command(cmd)} 2>&1`
12
+ end
13
+ # In ruby 1.9, it is possible to use Open3.capture3, but not in 1.8
14
+ #stdout, stderr, status = Open3.capture3(cmd)
15
+
16
+ if @example
17
+ @example.metadata[:command] = cmd
18
+ @example.metadata[:stdout] = stdout
19
+ end
20
+
21
+ { :stdout => stdout, :stderr => nil,
22
+ :exit_status => $?.exitstatus, :exit_signal => nil }
23
+ end
24
+
25
+ def run_with_no_ruby_environment
26
+ keys = %w[BUNDLER_EDITOR BUNDLE_BIN_PATH BUNDLE_GEMFILE
27
+ RUBYOPT GEM_HOME GEM_PATH GEM_CACHE]
28
+
29
+ keys.each { |key| ENV["_SPECINFRA_#{key}"] = ENV[key] ; ENV.delete(key) }
30
+ yield
31
+ ensure
32
+ keys.each { |key| ENV[key] = ENV.delete("_SPECINFRA_#{key}") }
33
+ end
34
+
35
+ def build_command(cmd)
36
+ path = SpecInfra.configuration.path || RSpec.configuration.path
37
+ if path
38
+ cmd = "env PATH=#{path}:$PATH #{cmd}"
39
+ cmd.gsub!(/(\&\&\s*!?\(?\s*)/, "\\1env PATH=#{path}:$PATH ")
40
+ cmd.gsub!(/(\|\|\s*!?\(?\s*)/, "\\1env PATH=#{path}:$PATH ")
41
+ end
42
+ cmd
43
+ end
44
+
45
+ def add_pre_command(cmd)
46
+ path = SpecInfra.configuration.path || RSpec.configuration.path
47
+ if SpecInfra.configuration.pre_command
48
+ cmd = "#{SpecInfra.configuration.pre_command} && #{cmd}"
49
+ cmd = "env PATH=#{path}:$PATH #{cmd}" if path
50
+ end
51
+ cmd
52
+ end
53
+
54
+ def check_running(process)
55
+ ret = run_command(commands.check_running(process))
56
+
57
+ # In Ubuntu, some services are under upstart and "service foo status" returns
58
+ # exit status 0 even though they are stopped.
59
+ # So return false if stdout contains "stopped/waiting".
60
+ return false if ret[:stdout] =~ /stopped\/waiting/
61
+
62
+ # If the service is not registered, check by ps command
63
+ if ret[:exit_status] == 1
64
+ ret = run_command(commands.check_process(process))
65
+ end
66
+
67
+ ret[:exit_status] == 0
68
+ end
69
+
70
+ def check_monitored_by_monit(process)
71
+ ret = run_command(commands.check_monitored_by_monit(process))
72
+ return false unless ret[:stdout] != nil && ret[:exit_status] == 0
73
+
74
+ retlines = ret[:stdout].split(/[\r\n]+/).map(&:strip)
75
+ proc_index = retlines.index("Process '#{process}'")
76
+ return false unless proc_index
77
+
78
+ retlines[proc_index+2].match(/\Amonitoring status\s+monitored\Z/i) != nil
79
+ end
80
+
81
+ def check_readable(file, by_whom)
82
+ mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
83
+ mode = mode.split('')
84
+ mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
85
+ case by_whom
86
+ when nil
87
+ mode_octal & 0444 != 0
88
+ when 'owner'
89
+ mode_octal & 0400 != 0
90
+ when 'group'
91
+ mode_octal & 0040 != 0
92
+ when 'others'
93
+ mode_octal & 0004 != 0
94
+ end
95
+ end
96
+
97
+ def check_writable(file, by_whom)
98
+ mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
99
+ mode = mode.split('')
100
+ mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
101
+ case by_whom
102
+ when nil
103
+ mode_octal & 0222 != 0
104
+ when 'owner'
105
+ mode_octal & 0200 != 0
106
+ when 'group'
107
+ mode_octal & 0020 != 0
108
+ when 'others'
109
+ mode_octal & 0002 != 0
110
+ end
111
+ end
112
+
113
+ def check_executable(file, by_whom)
114
+ mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
115
+ mode = mode.split('')
116
+ mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
117
+ case by_whom
118
+ when nil
119
+ mode_octal & 0111 != 0
120
+ when 'owner'
121
+ mode_octal & 0100 != 0
122
+ when 'group'
123
+ mode_octal & 0010 != 0
124
+ when 'others'
125
+ mode_octal & 0001 != 0
126
+ end
127
+ end
128
+
129
+ def check_mounted(path, expected_attr, only_with)
130
+ ret = run_command(commands.check_mounted(path))
131
+ if expected_attr.nil? || ret[:exit_status] != 0
132
+ return ret[:exit_status] == 0
133
+ end
134
+
135
+ mount = ret[:stdout].scan(/\S+/)
136
+ actual_attr = { :device => mount[0], :type => mount[4] }
137
+ mount[5].gsub(/\(|\)/, '').split(',').each do |option|
138
+ name, val = option.split('=')
139
+ if val.nil?
140
+ actual_attr[name.to_sym] = true
141
+ else
142
+ val = val.to_i if val.match(/^\d+$/)
143
+ actual_attr[name.to_sym] = val
144
+ end
145
+ end
146
+
147
+ if ! expected_attr[:options].nil?
148
+ expected_attr.merge!(expected_attr[:options])
149
+ expected_attr.delete(:options)
150
+ end
151
+
152
+ if only_with
153
+ actual_attr == expected_attr
154
+ else
155
+ expected_attr.each do |key, val|
156
+ return false if actual_attr[key] != val
157
+ end
158
+ true
159
+ end
160
+ end
161
+
162
+ def check_routing_table(expected_attr)
163
+ return false if ! expected_attr[:destination]
164
+ ret = run_command(commands.check_routing_table(expected_attr[:destination]))
165
+ return false if ret[:exit_status] != 0
166
+
167
+ ret[:stdout] =~ /^(\S+)(?: via (\S+))? dev (\S+).+\r\n(?:default via (\S+))?/
168
+ actual_attr = {
169
+ :destination => $1,
170
+ :gateway => $2 ? $2 : $4,
171
+ :interface => expected_attr[:interface] ? $3 : nil
172
+ }
173
+
174
+ expected_attr.each do |key, val|
175
+ return false if actual_attr[key] != val
176
+ end
177
+ true
178
+ end
179
+
180
+ def check_os
181
+ return RSpec.configuration.os if RSpec.configuration.os
182
+ if run_command('ls /etc/redhat-release')[:exit_status] == 0
183
+ line = run_command('cat /etc/redhat-release')[:stdout]
184
+ if line =~ /release (\d[\d.]*)/
185
+ release = $1
186
+ end
187
+ { :family => 'RedHat', :release => release }
188
+ elsif run_command('ls /etc/system-release')[:exit_status] == 0
189
+ { :family => 'RedHat', :release => nil } # Amazon Linux
190
+ elsif run_command('ls /etc/debian_version')[:exit_status] == 0
191
+ { :family => 'Debian', :release => nil }
192
+ elsif run_command('ls /etc/gentoo-release')[:exit_status] == 0
193
+ { :family => 'Gentoo', :release => nil }
194
+ elsif run_command('ls /usr/lib/setup/Plamo-*')[:exit_status] == 0
195
+ { :family => 'Plamo', :release => nil }
196
+ elsif run_command('uname -s')[:stdout] =~ /AIX/i
197
+ { :family => 'AIX', :release => nil }
198
+ elsif (os = run_command('uname -sr')[:stdout]) && os =~ /SunOS/i
199
+ if os =~ /5.10/
200
+ { :family => 'Solaris10', :release => nil }
201
+ elsif run_command('grep -q "Oracle Solaris 11" /etc/release')[:exit_status] == 0
202
+ { :family => 'Solaris11', :release => nil }
203
+ elsif run_command('grep -q SmartOS /etc/release')[:exit_status] == 0
204
+ { :family => 'SmartOS', :release => nil }
205
+ else
206
+ { :family => 'Solaris', :release => nil }
207
+ end
208
+ elsif run_command('uname -s')[:stdout] =~ /Darwin/i
209
+ { :family => 'Darwin', :release => nil }
210
+ elsif run_command('uname -s')[:stdout] =~ /FreeBSD/i
211
+ { :family => 'FreeBSD', :release => nil }
212
+ else
213
+ { :family => 'Base', :release => nil }
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,40 @@
1
+ module SpecInfra
2
+ module Backend
3
+ module PowerShell
4
+ class Command
5
+ attr_reader :import_functions, :script
6
+ def initialize &block
7
+ @import_functions = []
8
+ @script = ""
9
+ instance_eval &block if block_given?
10
+ end
11
+
12
+ def using *functions
13
+ functions.each { |f| import_functions << f }
14
+ end
15
+
16
+ def exec code
17
+ @script = code
18
+ end
19
+
20
+ def convert_regexp(target)
21
+ case target
22
+ when Regexp
23
+ target.source
24
+ else
25
+ target.to_s.gsub '/', ''
26
+ end
27
+ end
28
+
29
+ def get_identity id
30
+ raise "You must provide a specific Windows user/group" if id =~ /(owner|group|others)/
31
+ identity = id || 'Everyone'
32
+ end
33
+
34
+ def to_s
35
+ @script
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,85 @@
1
+ require 'base64'
2
+
3
+ module SpecInfra
4
+ module Backend
5
+ module PowerShell
6
+ module ScriptHelper
7
+ def build_command(cmd)
8
+ path = SpecInfra.configuration.path || RSpec.configuration.path
9
+ if path
10
+ cmd.strip!
11
+ cmd =
12
+ <<-EOF
13
+ $env:path = "#{path};$env:path"
14
+ #{cmd}
15
+ EOF
16
+ end
17
+ cmd
18
+ end
19
+
20
+ def add_pre_command(cmd)
21
+ path = SpecInfra.configuration.path || RSpec.configuration.path
22
+ if SpecInfra.configuration.pre_command
23
+ cmd.strip!
24
+ cmd =
25
+ <<-EOF
26
+ if (#{SpecInfra.configuration.pre_command})
27
+ {
28
+ #{cmd}
29
+ }
30
+ EOF
31
+ cmd = "$env:path = \"#{path};$env:path\"\n#{cmd}" if path
32
+ end
33
+ cmd
34
+ end
35
+
36
+ def encode_script script
37
+ script_text = script.chars.to_a.join("\x00").chomp
38
+ script_text << "\x00" unless script_text[-1].eql? "\x00"
39
+ if script_text.respond_to?(:encode)
40
+ script_text = script_text.encode('ASCII-8BIT')
41
+ end
42
+ if Base64.respond_to?(:strict_encode64)
43
+ Base64.strict_encode64(script_text)
44
+ else
45
+ [ script_text ].pack("m").strip
46
+ end
47
+ end
48
+
49
+ def create_script command
50
+ if command.is_a? Command
51
+ ps_functions = command.import_functions.map { |f| File.read(File.join(File.dirname(__FILE__), 'support', f)) }
52
+ script = build_command(command.script)
53
+ script = add_pre_command(script)
54
+ <<-EOF
55
+ $exitCode = 1
56
+ try {
57
+ #{ps_functions.join("\n")}
58
+ $success = (#{script})
59
+ if ($success -is [Boolean] -and $success) { $exitCode = 0 }
60
+ } catch {
61
+ Write-Output $_.Exception.Message
62
+ }
63
+ Write-Output "Exiting with code: $exitCode"
64
+ exit $exitCode
65
+ EOF
66
+ else
67
+ script = build_command(command.to_s)
68
+ add_pre_command(script)
69
+ end
70
+ end
71
+
72
+ def check_running(process)
73
+ ret = run_command(commands.check_running(process))
74
+
75
+ # If the service is not registered, check the process
76
+ if ret[:exit_status] == 1
77
+ ret = run_command(commands.check_process(process))
78
+ end
79
+
80
+ ret[:exit_status] == 0
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,8 @@
1
+ function CheckFileAccessRules
2
+ {
3
+ param($path, $identity, $rules)
4
+
5
+ $accessRules = @((Get-Acl $path).access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq $identity })
6
+ $match = @($accessRules | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? {$rules -contains $_}) -ne $null})
7
+ $match.count -gt 0
8
+ }
@@ -0,0 +1,11 @@
1
+ function CropText
2
+ {
3
+ param($text, $fromPattern, $toPattern)
4
+
5
+ $from, $to = ([regex]::matches($text, $fromPattern)), ([regex]::matches($text, $toPattern))
6
+ if ($from.count -gt 0 -and $to.count -gt 0) {
7
+ $text.substring($from[0].index, $to[0].index + $to[0].length - $from[0].index)
8
+ } else {
9
+ ""
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ function FindGroup
2
+ {
3
+ param($groupName, $domain)
4
+ if ($domain -eq $null) {$selectionCriteria = " and LocalAccount = true"}
5
+ else {$selectionCriteria = " and Domain = '$domain'"}
6
+
7
+ Get-WmiObject Win32_Group -filter "Name = '$groupName' $selectionCriteria"
8
+ }
@@ -0,0 +1,7 @@
1
+ function FindInstalledApplication
2
+ {
3
+ param($appName, $appVersion)
4
+ $selectionCriteria = "(Name like '$appName' or PackageName like '$appName') and InstallState = 5"
5
+ if ($appVersion -ne $null) { $selectionCriteria += " and version = '$appVersion'"}
6
+ Get-WmiObject Win32_Product -filter $selectionCriteria
7
+ }
@@ -0,0 +1,5 @@
1
+ function FindService
2
+ {
3
+ param($name)
4
+ Get-WmiObject Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name}
5
+ }
@@ -0,0 +1,8 @@
1
+ function FindUser
2
+ {
3
+ param($userName, $domain)
4
+ if ($domain -eq $null) {$selectionCriteria = " and LocalAccount = true"}
5
+ else {$selectionCriteria = " and Domain = '$domain'"}
6
+
7
+ Get-WmiObject Win32_UserAccount -filter "Name = '$userName' $selectionCriteria"
8
+ }
@@ -0,0 +1,9 @@
1
+ function FindUserGroup
2
+ {
3
+ param($userName, $groupName, $userDomain, $groupDomain)
4
+ $user = FindUser -userName $userName -domain $userDomain
5
+ $group = FindGroup -groupName $groupName -domain $groupDomain
6
+ if ($user -and $group) {
7
+ Get-WmiObject Win32_GroupUser -filter ("GroupComponent = 'Win32_Group.Domain=`"" + $group.domain + "`",Name=`"" + $group.name + "`"' and PartComponent = 'Win32_UserAccount.Domain=`"" + $user.domain + "`",Name=`"" + $user.name + "`"'")
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ function IsPortListening
2
+ {
3
+ param($portNumber, $protocol)
4
+ $netstatOutput = netstat -an | Out-String
5
+ $networkIPs = (Get-WmiObject Win32_NetworkAdapterConfiguration | ? {$_.IPEnabled}) | %{ $_.IPAddress[0] }
6
+ foreach ($ipaddress in $networkIPs)
7
+ {
8
+ $matchExpression = ("$ipaddress" + ":" + $portNumber)
9
+ if ($protocol) { $matchExpression = ($protocol.toUpper() + "\s+$matchExpression") }
10
+ if ($netstatOutput -match $matchExpression) { return $true }
11
+ }
12
+ $false
13
+ }
@@ -0,0 +1,93 @@
1
+ require 'specinfra/backend/exec'
2
+
3
+ module SpecInfra
4
+ module Backend
5
+ class Ssh < Exec
6
+ def run_command(cmd, opt={})
7
+ cmd = build_command(cmd)
8
+ cmd = add_pre_command(cmd)
9
+ ret = ssh_exec!(cmd)
10
+
11
+ ret[:stdout].gsub!(/\r\n/, "\n")
12
+
13
+ if @example
14
+ @example.metadata[:command] = cmd
15
+ @example.metadata[:stdout] = ret[:stdout]
16
+ end
17
+
18
+ ret
19
+ end
20
+
21
+ def build_command(cmd)
22
+ cmd = super(cmd)
23
+ if RSpec.configuration.ssh.options[:user] != 'root'
24
+ cmd = "#{sudo} #{cmd}"
25
+ cmd.gsub!(/(\&\&\s*!?\(?\s*)/, "\\1#{sudo} ")
26
+ cmd.gsub!(/(\|\|\s*!?\(?\s*)/, "\\1#{sudo} ")
27
+ end
28
+ cmd
29
+ end
30
+
31
+ def add_pre_command(cmd)
32
+ cmd = super(cmd)
33
+ user = RSpec.configuration.ssh.options[:user]
34
+ pre_command = SpecInfra.configuration.pre_command
35
+ if pre_command && user != 'root'
36
+ cmd = "#{sudo} #{cmd}"
37
+ end
38
+ cmd
39
+ end
40
+
41
+ private
42
+ def ssh_exec!(command)
43
+ stdout_data = ''
44
+ stderr_data = ''
45
+ exit_status = nil
46
+ exit_signal = nil
47
+ pass_prompt = RSpec.configuration.pass_prompt || /^\[sudo\] password for/
48
+
49
+ ssh = RSpec.configuration.ssh
50
+ ssh.open_channel do |channel|
51
+ channel.request_pty do |ch, success|
52
+ abort "Could not obtain pty " if !success
53
+ end
54
+ channel.exec("#{command}") do |ch, success|
55
+ abort "FAILED: couldn't execute command (ssh.channel.exec)" if !success
56
+ channel.on_data do |ch, data|
57
+ if data.match pass_prompt
58
+ abort "Please set sudo password by using SUDO_PASSWORD or ASK_SUDO_PASSWORD environment variable" if RSpec.configuration.sudo_password.nil?
59
+ channel.send_data "#{RSpec.configuration.sudo_password}\n"
60
+ else
61
+ stdout_data += data
62
+ end
63
+ end
64
+
65
+ channel.on_extended_data do |ch, type, data|
66
+ stderr_data += data
67
+ end
68
+
69
+ channel.on_request("exit-status") do |ch, data|
70
+ exit_status = data.read_long
71
+ end
72
+
73
+ channel.on_request("exit-signal") do |ch, data|
74
+ exit_signal = data.read_long
75
+ end
76
+ end
77
+ end
78
+ ssh.loop
79
+ { :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal }
80
+ end
81
+
82
+ def sudo
83
+ sudo_path = SpecInfra.configuration.sudo_path || RSpec.configuration.sudo_path
84
+ if sudo_path
85
+ "#{sudo_path}/sudo"
86
+ else
87
+ 'sudo'
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,26 @@
1
+ module SpecInfra
2
+ module Backend
3
+ class WinRM < Base
4
+ include PowerShell::ScriptHelper
5
+
6
+ def run_command(cmd, opts={})
7
+ script = create_script(cmd)
8
+ winrm = RSpec.configuration.winrm
9
+
10
+ result = winrm.powershell(script)
11
+ stdout, stderr = [:stdout, :stderr].map do |s|
12
+ result[:data].select {|item| item.key? s}.map {|item| item[s]}.join
13
+ end
14
+ result[:exitcode] = 1 if result[:exitcode] == 0 and !stderr.empty?
15
+
16
+ if @example
17
+ @example.metadata[:command] = script
18
+ @example.metadata[:stdout] = stdout + stderr
19
+ end
20
+
21
+ { :stdout => stdout, :stderr => stderr,
22
+ :exit_status => result[:exitcode], :exit_signal => nil }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ module SpecInfra
2
+ module Configuration
3
+ class << self
4
+ VALID_OPTIONS_KEYS = [:path, :pre_command, :stdout, :stderr, :sudo_path, :pass_prompt].freeze
5
+ attr_accessor(*VALID_OPTIONS_KEYS)
6
+
7
+ def defaults
8
+ VALID_OPTIONS_KEYS.inject({}) { |o, k| o.merge!(k => send(k)) }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'specinfra/helper/os'
2
+ require 'specinfra/helper/detect_os'
3
+ require 'specinfra/helper/backend'
4
+ require 'specinfra/helper/configuration'
5
+
6
+ require 'specinfra/helper/properties'
7
+ include SpecInfra::Helper::Properties
@@ -0,0 +1,18 @@
1
+ module SpecInfra
2
+ module Helper
3
+ ['Exec', 'Ssh', 'Cmd', 'WinRM'].each do |backend|
4
+ eval <<-EOF
5
+ module #{backend}
6
+ def backend(commands_object=nil)
7
+ if ! respond_to?(:commands)
8
+ commands_object = self.class.const_get(SPEC_TYPE).const_get('Commands').const_get('Base').new
9
+ end
10
+ instance = self.class.const_get('SpecInfra').const_get('Backend').const_get('#{backend}').instance
11
+ instance.set_commands(commands_object || commands)
12
+ instance
13
+ end
14
+ end
15
+ EOF
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ module SpecInfra
2
+ module Helper
3
+ module Configuration
4
+ def subject
5
+ example.metadata[:subject] = described_class
6
+ build_configurations
7
+ super
8
+ end
9
+
10
+ # You can create a set of configurations provided to all specs in your spec_helper:
11
+ #
12
+ # RSpec.configure { |c| c.pre_command = "source ~/.zshrc" }
13
+ #
14
+ # Any configurations you provide with `let(:option_name)` in a spec will
15
+ # automatically be merged on top of the configurations.
16
+ #
17
+ # @example
18
+ #
19
+ # describe 'Gem' do
20
+ # let(:pre_command) { "source ~/.zshrc" }
21
+ #
22
+ # %w(pry awesome_print bundler).each do |p|
23
+ # describe package(p) do
24
+ # it { should be_installed.by('gem') }
25
+ # end
26
+ # end
27
+ # end
28
+ def build_configurations
29
+ SpecInfra::Configuration.defaults.keys.each do |c|
30
+ value = self.respond_to?(c.to_sym) ?
31
+ self.send(c) : RSpec.configuration.send(c)
32
+ SpecInfra::Configuration.send(:"#{c}=", value)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ module SpecInfra
2
+ module Helper
3
+ module DetectOS
4
+ def commands
5
+ property[:os_by_host] = {} if ! property[:os_by_host]
6
+ host = RSpec.configuration.ssh ? RSpec.configuration.ssh.host : 'localhost'
7
+
8
+ if property[:os_by_host][host]
9
+ os = property[:os_by_host][host]
10
+ else
11
+ os = backend(self.class.const_get(SPEC_TYPE).const_get('Commands').const_get('Base')).check_os
12
+ property[:os_by_host][host] = os
13
+ end
14
+ self.class.const_get(SPEC_TYPE).const_get('Commands').const_get(os[:family]).new
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ module SpecInfra
2
+ module Helper
3
+ [
4
+ 'Base',
5
+ 'AIX',
6
+ 'Darwin',
7
+ 'Debian',
8
+ 'FreeBSD',
9
+ 'Gentoo',
10
+ 'Plamo',
11
+ 'RedHat',
12
+ 'SmartOS',
13
+ 'Solaris',
14
+ 'Solaris10',
15
+ 'Solaris11',
16
+ 'Windows',
17
+ ].each do |os|
18
+ eval <<-EOF
19
+ module #{os}
20
+ def commands
21
+ self.class.const_get(SPEC_TYPE).const_get('Commands').const_get('#{os}').new
22
+ end
23
+ end
24
+ EOF
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ require 'specinfra/properties'
2
+
3
+ module SpecInfra
4
+ module Helper
5
+ module Properties
6
+ def property
7
+ SpecInfra::Properties.instance.properties
8
+ end
9
+ def set_property(prop)
10
+ SpecInfra::Properties.instance.properties(prop)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'singleton'
2
+
3
+ module SpecInfra
4
+ class Properties
5
+ include Singleton
6
+ def initialize
7
+ @prop = {}
8
+ end
9
+ def properties(prop=nil)
10
+ if ! prop.nil?
11
+ @prop = prop
12
+ end
13
+ @prop
14
+ end
15
+ end
16
+ end
17
+
@@ -1,3 +1,3 @@
1
1
  module Specinfra
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ include SpecInfra::Helper::Properties
4
+
5
+ describe 'Properties Helper' do
6
+ before :all do
7
+ set_property :role => 'proxy'
8
+ end
9
+ subject { property }
10
+ it { should include :role => 'proxy' }
11
+ end
@@ -0,0 +1,4 @@
1
+ require 'specinfra'
2
+
3
+ include SpecInfra::Helper::Exec
4
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specinfra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gosuke Miyashita
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-27 00:00:00.000000000 Z
11
+ date: 2013-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -51,7 +51,33 @@ files:
51
51
  - README.md
52
52
  - Rakefile
53
53
  - lib/specinfra.rb
54
+ - lib/specinfra/backend.rb
55
+ - lib/specinfra/backend/base.rb
56
+ - lib/specinfra/backend/cmd.rb
57
+ - lib/specinfra/backend/exec.rb
58
+ - lib/specinfra/backend/powershell/command.rb
59
+ - lib/specinfra/backend/powershell/script_helper.rb
60
+ - lib/specinfra/backend/powershell/support/check_file_access_rules.ps1
61
+ - lib/specinfra/backend/powershell/support/crop_text.ps1
62
+ - lib/specinfra/backend/powershell/support/find_group.ps1
63
+ - lib/specinfra/backend/powershell/support/find_installed_application.ps1
64
+ - lib/specinfra/backend/powershell/support/find_service.ps1
65
+ - lib/specinfra/backend/powershell/support/find_user.ps1
66
+ - lib/specinfra/backend/powershell/support/find_usergroup.ps1
67
+ - lib/specinfra/backend/powershell/support/is_port_listening.ps1
68
+ - lib/specinfra/backend/ssh.rb
69
+ - lib/specinfra/backend/winrm.rb
70
+ - lib/specinfra/configuration.rb
71
+ - lib/specinfra/helper.rb
72
+ - lib/specinfra/helper/backend.rb
73
+ - lib/specinfra/helper/configuration.rb
74
+ - lib/specinfra/helper/detect_os.rb
75
+ - lib/specinfra/helper/os.rb
76
+ - lib/specinfra/helper/properties.rb
77
+ - lib/specinfra/properties.rb
54
78
  - lib/specinfra/version.rb
79
+ - spec/helpers/properties_spec.rb
80
+ - spec/spec_helper.rb
55
81
  - specinfra.gemspec
56
82
  homepage: ''
57
83
  licenses:
@@ -77,4 +103,6 @@ rubygems_version: 2.0.3
77
103
  signing_key:
78
104
  specification_version: 4
79
105
  summary: Common layer for serverspec and configspec
80
- test_files: []
106
+ test_files:
107
+ - spec/helpers/properties_spec.rb
108
+ - spec/spec_helper.rb