serverspec 0.2.22 → 0.2.23

Sign up to get free protection for your applications and to get access to all the features.
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