serverspec 0.2.22 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/serverspec.rb CHANGED
@@ -8,6 +8,7 @@ require 'serverspec/setup'
8
8
  require 'serverspec/filter'
9
9
  require 'serverspec/subject'
10
10
  require 'serverspec/commands/base'
11
+ require 'serverspec/commands/linux'
11
12
  require 'serverspec/commands/redhat'
12
13
  require 'serverspec/commands/debian'
13
14
  require 'serverspec/commands/gentoo'
@@ -30,3 +31,24 @@ RSpec.configure do |c|
30
31
  end
31
32
  end
32
33
  end
34
+
35
+ module RSpec
36
+ module Matchers
37
+ module DSL
38
+ class Matcher
39
+ def failure_message_for_should(&block)
40
+ if block.to_s =~ /serverspec\/matchers\/.+\.rb/
41
+ @custom = true
42
+ end
43
+ if @custom
44
+ cache_or_call_cached(:failure_message_for_should, &block)
45
+ else
46
+ message = "#{example.metadata[:command]}\n"
47
+ message += "#{example.metadata[:stdout]}"
48
+ message
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,3 @@
1
- require 'open3'
2
-
3
1
  module Serverspec
4
2
  module Backend
5
3
  class Exec
@@ -12,17 +10,17 @@ module Serverspec
12
10
  end
13
11
 
14
12
  def run_command(cmd, opts={})
13
+ stdout = `#{cmd} 2>&1`
15
14
  # In ruby 1.9, it is possible to use Open3.capture3, but not in 1.8
16
15
  #stdout, stderr, status = Open3.capture3(cmd)
17
- # So get exit status with `command`
18
- `#{cmd} 2>&1`
19
- ret = { :exit_status => $?, :exit_signal => nil }
20
-
21
- # Get stdout and stderr
22
- stdin, stdout, stderr = Open3.popen3(cmd)
23
- ret[:stdout] = stdout.read
24
- ret[:stderr] = stderr.read
25
- ret
16
+
17
+ if ! @example.nil?
18
+ @example.metadata[:command] = cmd
19
+ @example.metadata[:stdout] = stdout
20
+ end
21
+
22
+ { :stdout => stdout, :stderr => nil,
23
+ :exit_status => $?, :exit_signal => nil }
26
24
  end
27
25
 
28
26
  def check_zero(cmd, *args)
@@ -33,11 +31,12 @@ module Serverspec
33
31
  # Default action is to call check_zero with args
34
32
  def method_missing(meth, *args, &block)
35
33
  # Remove example object from *args
36
- args.shift
34
+ @example = args.shift
37
35
  check_zero(meth, *args)
38
36
  end
39
37
 
40
38
  def check_installed_by_gem(example, package, version)
39
+ @example = example
41
40
  ret = run_command(commands.check_installed_by_gem(package))
42
41
  res = ret[:exit_status] == 0
43
42
  if res && version
@@ -47,6 +46,7 @@ module Serverspec
47
46
  end
48
47
 
49
48
  def check_running(example, process)
49
+ @example = example
50
50
  ret = run_command(commands.check_running(process))
51
51
  if ret[:exit_status] == 1 || ret[:stdout] =~ /stopped/
52
52
  ret = run_command(commands.check_process(process))
@@ -55,11 +55,13 @@ module Serverspec
55
55
  end
56
56
 
57
57
  def check_running_under_supervisor(example, process)
58
+ @example = example
58
59
  ret = run_command(commands.check_running_under_supervisor(process))
59
60
  ret[:exit_status] == 0 && ret[:stdout] =~ /RUNNING/
60
61
  end
61
62
 
62
63
  def check_readable(example, file, by_whom)
64
+ @example = example
63
65
  mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
64
66
  mode = mode.split('')
65
67
  mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
@@ -76,6 +78,7 @@ module Serverspec
76
78
  end
77
79
 
78
80
  def check_writable(example, file, by_whom)
81
+ @example = example
79
82
  mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
80
83
  mode = mode.split('')
81
84
  mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
@@ -92,6 +95,7 @@ module Serverspec
92
95
  end
93
96
 
94
97
  def check_executable(example, file, by_whom)
98
+ @example = example
95
99
  mode = sprintf('%04s',run_command(commands.get_mode(file))[:stdout].strip)
96
100
  mode = mode.split('')
97
101
  mode_octal = mode[0].to_i * 512 + mode[1].to_i * 64 + mode[2].to_i * 8 + mode[3].to_i * 1
@@ -108,6 +112,7 @@ module Serverspec
108
112
  end
109
113
 
110
114
  def check_mounted(example, path, expected_attr, only_with)
115
+ @example = example
111
116
  ret = run_command(commands.check_mounted(path))
112
117
  if expected_attr.nil? || ret[:exit_status] != 0
113
118
  return ret[:exit_status] == 0
@@ -5,7 +5,12 @@ module Serverspec
5
5
  class Ssh < Exec
6
6
  def run_command(cmd, opt={})
7
7
  cmd = "sudo #{cmd}" if not RSpec.configuration.ssh.options[:user] == 'root'
8
- ssh_exec!(cmd)
8
+ ret = ssh_exec!(cmd)
9
+ if ! @example.nil?
10
+ @example.metadata[:command] = cmd
11
+ @example.metadata[:stdout] = ret[:stdout]
12
+ end
13
+ ret
9
14
  end
10
15
 
11
16
  private
@@ -1,48 +1,55 @@
1
+ require 'shellwords'
2
+
1
3
  module Serverspec
2
4
  module Commands
3
5
  class Base
4
6
  class NotImplementedError < Exception; end
5
7
 
8
+ def escape target
9
+ Shellwords.shellescape(target.to_s())
10
+ end
11
+
6
12
  def check_enabled service
7
13
  raise NotImplementedError.new
8
14
  end
9
15
 
10
16
  def check_mounted path
11
- "mount | grep -w 'on #{path}'"
17
+ regexp = "on #{path}"
18
+ "mount | grep -w -- #{escape(regexp)}"
12
19
  end
13
20
 
14
21
  def check_reachable host, port, proto, timeout
15
22
  if port.nil?
16
- "ping -n #{host} -w #{timeout} -c 2"
23
+ "ping -n #{escape(host)} -w #{escape(timeout)} -c 2"
17
24
  else
18
- "nc -vvvvz#{proto[0].chr} #{host} #{port} -w #{timeout}"
25
+ "nc -vvvvz#{escape(proto[0].chr)} #{escape(host)} #{escape(port)} -w #{escape(timeout)}"
19
26
  end
20
27
  end
21
28
 
22
29
  def check_resolvable name, type
23
30
  if type == "dns"
24
- "nslookup -timeout=1 #{name}"
31
+ "nslookup -timeout=1 #{escape(name)}"
25
32
  elsif type == "hosts"
26
- "grep -w #{name} /etc/hosts"
33
+ "grep -w -- #{escape(name)} /etc/hosts"
27
34
  else
28
- "getent hosts #{name}"
35
+ "getent hosts #{escape(name)}"
29
36
  end
30
37
  end
31
38
 
32
39
  def check_file file
33
- "test -f #{file}"
40
+ "test -f #{escape(file)}"
34
41
  end
35
42
 
36
43
  def check_directory directory
37
- "test -d #{directory}"
44
+ "test -d #{escape(directory)}"
38
45
  end
39
46
 
40
47
  def check_user user
41
- "id #{user}"
48
+ "id #{escape(user)}"
42
49
  end
43
50
 
44
51
  def check_group group
45
- "getent group | grep -wq #{group}"
52
+ "getent group | grep -wq -- #{escape(group)}"
46
53
  end
47
54
 
48
55
  def check_installed package
@@ -50,90 +57,91 @@ module Serverspec
50
57
  end
51
58
 
52
59
  def check_listening port
53
- "netstat -tunl | grep ':#{port} '"
60
+ regexp = ":#{port} "
61
+ "netstat -tunl | grep -- #{escape(regexp)}"
54
62
  end
55
63
 
56
64
  def check_running service
57
- "service #{service} status"
65
+ "service #{escape(service)} status"
58
66
  end
59
67
 
60
68
  def check_running_under_supervisor service
61
- "supervisorctl status #{service}"
69
+ "supervisorctl status #{escape(service)}"
62
70
  end
63
71
 
64
72
  def check_process process
65
- "ps aux | grep -w #{process} | grep -qv grep"
73
+ "ps aux | grep -w -- #{escape(process)} | grep -qv grep"
66
74
  end
67
75
 
68
76
  def check_file_contain file, expected_pattern
69
- "grep -q '#{expected_pattern}' #{file}"
77
+ "grep -q -- #{escape(expected_pattern)} #{escape(file)}"
70
78
  end
71
79
 
72
80
  def check_file_contain_within file, expected_pattern, from=nil, to=nil
73
81
  from ||= '1'
74
82
  to ||= '$'
75
83
  checker = check_file_contain("-", expected_pattern)
76
- "sed -n '#{from},#{to}p' #{file} | #{checker}"
84
+ "sed -n #{escape(from)},#{escape(to)}p #{escape(file)} | #{checker}"
77
85
  end
78
86
 
79
87
  def check_mode file, mode
80
- "stat -c %a #{file} | grep '^#{mode}$'"
88
+ regexp = "^#{mode}$"
89
+ "stat -c %a #{escape(file)} | grep -- #{escape(regexp)}"
81
90
  end
82
91
 
83
92
  def check_owner file, owner
84
- "stat -c %U #{file} | grep '^#{owner}$'"
93
+ regexp = "^#{owner}$"
94
+ "stat -c %U #{escape(file)} | grep -- #{escape(regexp)}"
85
95
  end
86
96
 
87
97
  def check_grouped file, group
88
- "stat -c %G #{file} | grep '^#{group}$'"
98
+ regexp = "^#{group}$"
99
+ "stat -c %G #{escape(file)} | grep -- #{escape(regexp)}"
89
100
  end
90
101
 
91
102
  def check_cron_entry user, entry
92
103
  entry_escaped = entry.gsub(/\*/, '\\*')
93
- "crontab -u #{user} -l | grep \"#{entry_escaped}\""
104
+ "crontab -u #{escape(user)} -l | grep -- #{escape(entry_escaped)}"
94
105
  end
95
106
 
96
107
  def check_link link, target
97
- "stat -c %N #{link} | grep #{target}"
108
+ "stat -c %N #{escape(link)} | grep -- #{escape(target)}"
98
109
  end
99
110
 
100
111
  def check_installed_by_gem name
101
- "gem list --local | grep '^#{name} '"
112
+ gem_name = "^#{name} "
113
+ "gem list --local | grep -- #{escape(gem_name)}"
102
114
  end
103
115
 
104
116
  def check_belonging_group user, group
105
- "id #{user} | awk '{print $3}' | grep #{group}"
117
+ "id #{escape(user)} | awk '{print $3}' | grep -- #{escape(group)}"
106
118
  end
107
119
 
108
120
  def check_gid group, gid
109
- "getent group | grep -w ^#{group} | cut -f 3 -d ':' | grep -w #{gid}"
121
+ regexp = "^#{group}"
122
+ "getent group | grep -w -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}"
110
123
  end
111
124
 
112
125
  def check_uid user, uid
113
- "id #{user} | grep '^uid=#{uid}('"
126
+ regexp = "^uid=#{uid}("
127
+ "id #{escape(user)} | grep -- #{escape(regexp)}"
114
128
  end
115
129
 
116
130
  def check_login_shell user, path_to_shell
117
- "getent passwd #{user} | cut -f 7 -d ':' | grep -w #{path_to_shell}"
131
+ "getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}"
118
132
  end
119
133
 
120
134
  def check_home_directory user, path_to_home
121
- "getent passwd #{user} | cut -f 6 -d ':' | grep -w #{path_to_home}"
135
+ "getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}"
122
136
  end
123
137
 
124
138
  def check_authorized_key user, key
125
139
  key.sub!(/\s+\S*$/, '') if key.match(/^\S+\s+\S+\s+\S*$/)
126
- "grep -w '#{key}' ~#{user}/.ssh/authorized_keys"
140
+ "grep -w -- #{escape(key)} ~#{escape(user)}/.ssh/authorized_keys"
127
141
  end
128
142
 
129
143
  def check_iptables_rule rule, table=nil, chain=nil
130
- cmd = "iptables"
131
- cmd += " -t #{table}" if table
132
- cmd += " -S"
133
- cmd += " #{chain}" if chain
134
- rule.gsub!(/\-/, '\\-')
135
- cmd += " | grep '#{rule}'"
136
- cmd
144
+ raise NotImplementedError.new
137
145
  end
138
146
 
139
147
  def check_zfs zfs, property=nil, value=nil
@@ -141,7 +149,7 @@ module Serverspec
141
149
  end
142
150
 
143
151
  def get_mode(file)
144
- "stat -c %a #{file}"
152
+ "stat -c %a #{escape(file)}"
145
153
  end
146
154
 
147
155
  def check_ipfilter_rule rule
@@ -161,7 +169,7 @@ module Serverspec
161
169
  end
162
170
 
163
171
  def check_selinux mode
164
- "/usr/sbin/getenforce | grep -i '#{mode}'"
172
+ raise NotImplementedError.new
165
173
  end
166
174
  end
167
175
  end
@@ -1,12 +1,12 @@
1
1
  module Serverspec
2
2
  module Commands
3
- class Debian < Base
3
+ class Debian < Linux
4
4
  def check_enabled service
5
- "ls /etc/rc3.d/ | grep #{service}"
5
+ "ls /etc/rc3.d/ | grep -- #{escape(service)}"
6
6
  end
7
7
 
8
8
  def check_installed package
9
- "dpkg -s #{package}"
9
+ "dpkg -s #{escape(package)}"
10
10
  end
11
11
  end
12
12
  end
@@ -1,16 +1,17 @@
1
1
  module Serverspec
2
2
  module Commands
3
- class Gentoo < Base
3
+ class Gentoo < Linux
4
4
  def check_enabled service
5
- "/sbin/rc-update show | grep '^\\s*#{service}\\s*|\\s*\\(boot\\|default\\)'"
5
+ regexp = "^\\s*#{service}\\s*|\\s*\\(boot\\|default\\)"
6
+ "/sbin/rc-update show | grep -- #{escape(regexp)}"
6
7
  end
7
8
 
8
9
  def check_installed package
9
- "/usr/bin/eix #{package} --installed"
10
+ "/usr/bin/eix #{escape(package)} --installed"
10
11
  end
11
12
 
12
13
  def check_running service
13
- "/etc/init.d/#{service} status"
14
+ "/etc/init.d/#{escape(service)} status"
14
15
  end
15
16
  end
16
17
  end
@@ -0,0 +1,22 @@
1
+ require 'shellwords'
2
+
3
+ module Serverspec
4
+ module Commands
5
+ class Linux < Base
6
+ class NotImplementedError < Exception; end
7
+
8
+ def check_iptables_rule rule, table=nil, chain=nil
9
+ cmd = "iptables"
10
+ cmd += " -t #{escape(table)}" if table
11
+ cmd += " -S"
12
+ cmd += " #{escape(chain)}" if chain
13
+ cmd += " | grep -- #{escape(rule)}"
14
+ cmd
15
+ end
16
+
17
+ def check_selinux mode
18
+ "/usr/sbin/getenforce | grep -i -- #{escape(mode)}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,12 +1,12 @@
1
1
  module Serverspec
2
2
  module Commands
3
- class RedHat < Base
3
+ class RedHat < Linux
4
4
  def check_enabled service
5
- "chkconfig --list #{service} | grep 3:on"
5
+ "chkconfig --list #{escape(service)} | grep 3:on"
6
6
  end
7
7
 
8
8
  def check_installed package
9
- "rpm -q #{package}"
9
+ "rpm -q #{escape(package)}"
10
10
  end
11
11
  end
12
12
  end
@@ -2,54 +2,59 @@ module Serverspec
2
2
  module Commands
3
3
  class Solaris < Base
4
4
  def check_enabled service
5
- "svcs -l #{service} 2> /dev/null | grep 'enabled true'"
5
+ "svcs -l #{escape(service)} 2> /dev/null | grep 'enabled true'"
6
6
  end
7
7
 
8
8
  def check_installed package
9
- "pkg list -H #{package} 2> /dev/null"
9
+ "pkg list -H #{escape(package)} 2> /dev/null"
10
10
  end
11
11
 
12
12
  def check_listening port
13
- "netstat -an 2> /dev/null | egrep 'LISTEN|Idle' | grep '\.#{port} '"
13
+ regexp = "\.#{port} "
14
+ "netstat -an 2> /dev/null | egrep 'LISTEN|Idle' | grep -- #{escape(regexp)}"
14
15
  end
15
16
 
16
17
  def check_running service
17
- "svcs -l #{service} status 2> /dev/null |grep 'state online'"
18
+ "svcs -l #{escape(service)} status 2> /dev/null |grep 'state online'"
18
19
  end
19
20
 
20
21
  def check_cron_entry user, entry
21
22
  entry_escaped = entry.gsub(/\*/, '\\*')
22
- "crontab -l #{user} | grep '#{entry_escaped}'"
23
+ "crontab -l #{escape(user)} | grep -- #{escape(entry_escaped)}"
23
24
  end
24
25
 
25
26
  def check_zfs zfs, property=nil
26
27
  if property.nil?
27
- "/sbin/zfs list -H #{zfs}"
28
+ "/sbin/zfs list -H #{escape(zfs)}"
28
29
  else
29
30
  commands = []
30
31
  property.sort.each do |key, value|
31
- commands << "/sbin/zfs list -H -o #{key} #{zfs} | grep ^#{value}$"
32
+ regexp = "^#{value}$"
33
+ commands << "/sbin/zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}"
32
34
  end
33
35
  commands.join(' && ')
34
36
  end
35
37
  end
36
38
 
37
39
  def check_ipfilter_rule rule
38
- "/sbin/ipfstat -io 2> /dev/null | grep '#{rule}'"
40
+ "/sbin/ipfstat -io 2> /dev/null | grep -- #{escape(rule)}"
39
41
  end
40
42
 
41
43
  def check_ipnat_rule rule
42
- "/sbin/ipnat -l 2> /dev/null | grep '^#{rule}$'"
44
+ regexp = "^#{rule}$"
45
+ "/sbin/ipnat -l 2> /dev/null | grep -- #{escape(regexp)}"
43
46
  end
44
47
 
45
48
  def check_svcprop svc, property, value
46
- "svcprop -p #{property} #{svc} | grep ^#{value}$"
49
+ regexp = "^#{value}$"
50
+ "svcprop -p #{escape(property)} #{escape(svc)} | grep -- #{escape(regexp)}"
47
51
  end
48
52
 
49
53
  def check_svcprops svc, property
50
54
  commands = []
51
55
  property.sort.each do |key, value|
52
- commands << "svcprop -p #{key} #{svc} | grep ^#{value}$"
56
+ regexp = "^#{value}$"
57
+ commands << "svcprop -p #{escape(key)} #{escape(svc)} | grep -- #{escape(regexp)}"
53
58
  end
54
59
  commands.join(' && ')
55
60
  end
@@ -58,23 +63,24 @@ module Serverspec
58
63
  from ||= '1'
59
64
  to ||= '$'
60
65
  checker = check_file_contain("/dev/stdin", expected_pattern)
61
- "sed -n '#{from},#{to}p' #{file} | #{checker}"
66
+ "sed -n #{escape(from)},#{escape(to)}p #{escape(file)} | #{checker}"
62
67
  end
63
68
 
64
69
  def check_belonging_group user, group
65
- "id -Gn #{user} | grep #{group}"
70
+ "id -Gn #{escape(user)} | grep -- #{escape(group)}"
66
71
  end
67
72
 
68
73
  def check_gid group, gid
69
- "getent group | grep ^#{group}: | cut -f 3 -d ':' | grep -w #{gid}"
74
+ regexp = "^#{group}:"
75
+ "getent group | grep -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}"
70
76
  end
71
77
 
72
78
  def check_home_directory user, path_to_home
73
- "getent passwd #{user} | cut -f 6 -d ':' | grep -w #{path_to_home}"
79
+ "getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}"
74
80
  end
75
81
 
76
82
  def check_login_shell user, path_to_shell
77
- "getent passwd #{user} | cut -f 7 -d ':' | grep -w #{path_to_shell}"
83
+ "getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}"
78
84
  end
79
85
  end
80
86
  end