From 19ed6be39f3b7ae45f0d0f37effe59db2fcfcede Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 31 Dec 2015 01:01:11 +0100 Subject: [PATCH 01/13] more fine-grained utils parser --- lib/resources/etc_group.rb | 2 +- lib/resources/passwd.rb | 2 +- lib/resources/user.rb | 5 +++-- lib/utils/parser.rb | 4 +++- lib/utils/simpleconfig.rb | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/resources/etc_group.rb b/lib/resources/etc_group.rb index 4871884f8..10f6ac588 100644 --- a/lib/resources/etc_group.rb +++ b/lib/resources/etc_group.rb @@ -26,7 +26,7 @@ require 'utils/parser' class EtcGroup < Inspec.resource(1) include Converter - include ContentParser + include CommentParser name 'etc_group' desc 'Use the etc_group InSpec audit resource to test groups that are defined on Linux and UNIX platforms. The /etc/group file stores details about each group---group name, password, group identifier, along with a comma-separate list of users that belong to the group.' diff --git a/lib/resources/passwd.rb b/lib/resources/passwd.rb index be67646a0..aa66863d0 100644 --- a/lib/resources/passwd.rb +++ b/lib/resources/passwd.rb @@ -37,7 +37,7 @@ class Passwd < Inspec.resource(1) end " - include ContentParser + include PasswdParser attr_reader :uid attr_reader :parsed diff --git a/lib/resources/user.rb b/lib/resources/user.rb index 0947deac3..c7c3a2cbb 100644 --- a/lib/resources/user.rb +++ b/lib/resources/user.rb @@ -230,7 +230,8 @@ class UnixUser < UserInfo end class LinuxUser < UnixUser - include ContentParser + include PasswdParser + include CommentParser def meta_info(username) cmd = inspec.command("getent passwd #{username}") @@ -295,7 +296,7 @@ end # - chpass(1) A flexible tool for changing user database information. # - passwd(1) The command-line tool to change user passwords. class FreeBSDUser < UnixUser - include ContentParser + include PasswdParser def meta_info(username) cmd = inspec.command("pw usershow #{username} -7") diff --git a/lib/utils/parser.rb b/lib/utils/parser.rb index d786fa738..4add759aa 100644 --- a/lib/utils/parser.rb +++ b/lib/utils/parser.rb @@ -2,7 +2,7 @@ # author: Christoph Hartmann # author: Dominik Richter -module ContentParser +module PasswdParser # Parse /etc/passwd files. # # @param [String] content the raw content of /etc/passwd @@ -29,7 +29,9 @@ module ContentParser 'shell' => x.at(6), } end +end +module CommentParser # Parse a line with a command. For example: `a = b # comment`. # Retrieves the actual content. # diff --git a/lib/utils/simpleconfig.rb b/lib/utils/simpleconfig.rb index 9eddbfc8b..23d5339c8 100644 --- a/lib/utils/simpleconfig.rb +++ b/lib/utils/simpleconfig.rb @@ -7,7 +7,7 @@ require 'utils/parser' class SimpleConfig - include ContentParser + include CommentParser attr_reader :params, :groups def initialize(raw_data, opts = {}) From c7b7eccb5d4b6464a3462b35d2643f500eef0880 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sat, 2 Jan 2016 23:58:28 +0100 Subject: [PATCH 02/13] update unit test for new parser --- .../utils/{content_parser_test.rb => passwd_parser_test.rb} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/unit/utils/{content_parser_test.rb => passwd_parser_test.rb} (87%) diff --git a/test/unit/utils/content_parser_test.rb b/test/unit/utils/passwd_parser_test.rb similarity index 87% rename from test/unit/utils/content_parser_test.rb rename to test/unit/utils/passwd_parser_test.rb index 61c6a021d..a3ea211aa 100644 --- a/test/unit/utils/content_parser_test.rb +++ b/test/unit/utils/passwd_parser_test.rb @@ -2,8 +2,8 @@ # author: Dominik Richter # author: Christoph Hartmann -describe ContentParser do - let (:parser) { Class.new() { include ContentParser }.new } +describe PasswdParser do + let (:parser) { Class.new() { include PasswdParser }.new } describe '#parse_passwd' do it 'parses nil content' do From 772df929f66e3d4e2a844b60bc2bbe9571fda6c3 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 31 Dec 2015 01:08:57 +0100 Subject: [PATCH 03/13] implement `be_mounted.with` for file resources --- lib/matchers/matchers.rb | 30 ++++++++++++++++++++++++++++++ lib/resources/file.rb | 23 +++++++++++++++++++++-- lib/utils/hash.rb | 30 +++++++++++++++++++++++++++++- lib/utils/parser.rb | 31 +++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/lib/matchers/matchers.rb b/lib/matchers/matchers.rb index 7414d7c3b..3a898b003 100644 --- a/lib/matchers/matchers.rb +++ b/lib/matchers/matchers.rb @@ -271,3 +271,33 @@ RSpec::Matchers.define :cmp do |expected| "\nexpected: value != #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n" end end + +# user resource matcher for serverspec compatibility +# This matcher will be deprecated in future +RSpec::Matchers.define :be_mounted do + match do |path| + if !@options.nil? + path.mounted?(@options, @identical) + else + path.mounted? + end + end + + chain :with do |attr| + @options = attr + @identical = false + end + + chain :only_with do |attr| + @options = attr + @identical = true + end + + failure_message do |path| + if !@options.nil? + "\n#{path} is not mounted with the options\n expected: #{@options}\n got: #{path.mount_options}\n" + else + "\n#{path} is not mounted\n" + end + end +end diff --git a/lib/resources/file.rb b/lib/resources/file.rb index 28cb0cb02..e73528513 100644 --- a/lib/resources/file.rb +++ b/lib/resources/file.rb @@ -18,8 +18,9 @@ module Inspec::Resources its('mode') { should eq 0644 } end " + include MountParser - attr_reader :file, :path + attr_reader :file, :path, :mount_options def initialize(path) @path = path @file = inspec.backend.file(@path) @@ -28,7 +29,7 @@ module Inspec::Resources %w{ type exist? file? block_device? character_device? socket? directory? symlink? pipe? mode mode? owner owned_by? group grouped_into? link_target - link_path linked_to? content mtime size selinux_label mounted? immutable? + link_path linked_to? content mtime size selinux_label immutable? product_version file_version version? md5sum sha256sum }.each do |m| define_method m.to_sym do |*args| @@ -58,6 +59,24 @@ module Inspec::Resources file_permission_granted?('x', by_usergroup, by_specific_user) end + def mounted?(expected_options = nil, identical = false) + mounted = file.mounted + + # return if no additional parameters have been provided + return file.mounted? if expected_options.nil? + + # parse content if we are on linux + @mount_options ||= parse_mount_options(mounted.stdout, true) + + if identical + # check if the options should be identical + @mount_options == expected_options + else + # otherwise compare the selected values + @mount_options.contains(expected_options) + end + end + def to_s "File #{path}" end diff --git a/lib/utils/hash.rb b/lib/utils/hash.rb index 532837833..1f01b022a 100644 --- a/lib/utils/hash.rb +++ b/lib/utils/hash.rb @@ -1,13 +1,41 @@ # encoding: utf-8 -# Inspired by: http://stackoverflow.com/a/9381776 # author: Dominik Richter # author: Christoph Hartmann class ::Hash + # Inspired by: http://stackoverflow.com/a/9381776 def deep_merge(second) merger = proc { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2 } merge(second, &merger) end + + # converts a deep hash into a flat hash + # hash = { + # 'a' => 1, + # 'b' => {'c' => 2}, + # } + # hash.smash # => {"a"=>1, "b-c"=>2} + def smash(prefix = nil) + inject({}) do |acc, (key, value)| + index = prefix.to_s + key.to_s + if value.is_a?(Hash) + acc.merge(value.smash(index + '-')) + else + acc.merge(index => value) + end + end + end + + # deep check if all values are contained + def contains(contains) + hash = smash + contains = contains.smash + + contains.each do |key, val| + return false if hash[key] != val + end + true + end end diff --git a/lib/utils/parser.rb b/lib/utils/parser.rb index 4add759aa..a02791552 100644 --- a/lib/utils/parser.rb +++ b/lib/utils/parser.rb @@ -61,3 +61,34 @@ module CommentParser [line, idx_nl] end end + +module MountParser + # this parses the output of mount command (only tested on linux) + # this method expects only one line of the mount output + def parse_mount_options(mount_line, compatibility = false) + mount = mount_line.scan(/\S+/) + + # parse device and type + mount_options = { device: mount[0], type: mount[4] } + + if compatibility == false + # parse options as array + mount_options[:options] = mount[5].gsub(/\(|\)/, '').split(',') + else + # parse options as serverspec uses it, tbis is deprecated + mount_options[:options] = {} + mount[5].gsub(/\(|\)/, '').split(',').each do |option| + name, val = option.split('=') + if val.nil? + val = true + else + # parse numbers + val = val.to_i if val.match(/^\d+$/) + end + mount_options[:options][name.to_sym] = val + end + end + + mount_options + end +end From a5acb03e49bd142b5cd40f8ed43afe1a1bbd807f Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 31 Dec 2015 01:10:06 +0100 Subject: [PATCH 04/13] add `mount` resource --- lib/inspec/resource.rb | 1 + lib/resources/mount.rb | 45 +++++++++++++++++++++++++++++++ test/helper.rb | 3 ++- test/unit/mock/cmd/mount | 1 + test/unit/resources/file_test.rb | 4 +++ test/unit/resources/mount_test.rb | 16 +++++++++++ 6 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 lib/resources/mount.rb create mode 100644 test/unit/mock/cmd/mount create mode 100644 test/unit/resources/mount_test.rb diff --git a/lib/inspec/resource.rb b/lib/inspec/resource.rb index be2a4a8d4..723c85a87 100644 --- a/lib/inspec/resource.rb +++ b/lib/inspec/resource.rb @@ -44,6 +44,7 @@ require 'resources/kernel_module' require 'resources/kernel_parameter' require 'resources/limits_conf' require 'resources/login_def' +require 'resources/mount' require 'resources/mysql' require 'resources/mysql_conf' require 'resources/mysql_session' diff --git a/lib/resources/mount.rb b/lib/resources/mount.rb new file mode 100644 index 000000000..f9e8191c6 --- /dev/null +++ b/lib/resources/mount.rb @@ -0,0 +1,45 @@ +# encoding: utf-8 +# author: Christoph Hartmann +# author: Dominik Richter + +require 'utils/simpleconfig' + +class Mount < Inspec.resource(1) + name 'mount' + desc 'Use the mount InSpec audit resource to test if mount points.' + example " + describe mount('/') do + it { should be_mounted } + its('device') { should eq '/dev/mapper/VolGroup-lv_root' } + its('type') { should eq 'ext4' } + its('options') { should eq ['rw', 'mode=620'] } + end + " + include MountParser + + attr_reader :file + + def initialize(path) + @path = path + @file = inspec.backend.file(@path) + end + + def mounted? + file.mounted? + end + + def method_missing(name) + return nil if !file.mounted? + + mounted = file.mounted + + # parse content if we are on linux + @mount_options ||= parse_mount_options(mounted.stdout) + + @mount_options[name] + end + + def to_s + "Mount #{@path}" + end +end diff --git a/test/helper.rb b/test/helper.rb index c4ee1e98b..ef885a57d 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -196,7 +196,8 @@ class MockLoader # apache_conf 'find /etc/apache2/ports.conf -maxdepth 1 -type f' => cmd.call('find-apache2-ports-conf'), 'find /etc/apache2/conf-enabled/*.conf -maxdepth 1 -type f' => cmd.call('find-apache2-conf-enabled'), - + # mount + "mount | grep -- ' on /'" => cmd.call("mount"), } @backend diff --git a/test/unit/mock/cmd/mount b/test/unit/mock/cmd/mount new file mode 100644 index 000000000..abd2b379d --- /dev/null +++ b/test/unit/mock/cmd/mount @@ -0,0 +1 @@ +/dev/xvda1 on / type ext4 (rw,discard) diff --git a/test/unit/resources/file_test.rb b/test/unit/resources/file_test.rb index b3efebb9a..59c53efc5 100644 --- a/test/unit/resources/file_test.rb +++ b/test/unit/resources/file_test.rb @@ -1,3 +1,7 @@ +# encoding: utf-8 +# author: Christoph Hartmann +# author: Dominik Richter + require 'helper' require 'inspec/resource' diff --git a/test/unit/resources/mount_test.rb b/test/unit/resources/mount_test.rb new file mode 100644 index 000000000..85dda3630 --- /dev/null +++ b/test/unit/resources/mount_test.rb @@ -0,0 +1,16 @@ +# encoding: utf-8 +# author: Christoph Hartmann +# author: Dominik Richter + +require 'helper' +require 'inspec/resource' + +describe Inspec::Resources::File do + let(:resource) { load_resource('mount', '/') } + + it 'parses the mount data properly' do + resource.send(:device).must_equal('/dev/xvda1') + resource.send(:type).must_equal('ext4') + resource.send(:options).must_equal(['rw','discard']) + end +end From 50d2ef4db54e87b7d93a268c5bf85e4392458134 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 31 Dec 2015 01:10:39 +0100 Subject: [PATCH 05/13] add integration tests for mountpoints --- .../cookbooks/os_prepare/recipes/default.rb | 1 + .../cookbooks/os_prepare/recipes/mount.rb | 29 +++++++++++++++ .../test/integration/default/file_spec.rb | 36 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 test/integration/cookbooks/os_prepare/recipes/mount.rb diff --git a/test/integration/cookbooks/os_prepare/recipes/default.rb b/test/integration/cookbooks/os_prepare/recipes/default.rb index 18ffdb723..a1afa035c 100644 --- a/test/integration/cookbooks/os_prepare/recipes/default.rb +++ b/test/integration/cookbooks/os_prepare/recipes/default.rb @@ -6,6 +6,7 @@ include_recipe('os_prepare::apt') include_recipe('os_prepare::file') +include_recipe('os_prepare::mount') include_recipe('os_prepare::json_yaml_csv_ini') include_recipe('os_prepare::package') include_recipe('os_prepare::registry_key') diff --git a/test/integration/cookbooks/os_prepare/recipes/mount.rb b/test/integration/cookbooks/os_prepare/recipes/mount.rb new file mode 100644 index 000000000..37c5bbe5d --- /dev/null +++ b/test/integration/cookbooks/os_prepare/recipes/mount.rb @@ -0,0 +1,29 @@ +# encoding: utf-8 +# author: Christoph Hartmann +# author: Dominik Richter +# +# file mount tests + +# download alpine linux for file mount tests +remote_file '/root/alpine-3.3.0-x86_64.iso' do + source 'http://wiki.alpinelinux.org/cgi-bin/dl.cgi/v3.3/releases/x86_64/alpine-3.3.0-x86_64.iso' + owner 'root' + group 'root' + mode '0755' + action :create +end + +# create mount directory +directory '/mnt/iso-disk' do + owner 'root' + group 'root' + mode '0755' + action :create +end + +# mount -o loop /root/alpine-3.3.0-x86_64.iso /mnt/iso-disk +mount '/mnt/iso-disk' do + device '/root/alpine-3.3.0-x86_64.iso' + options 'loop' + action [:mount, :enable] +end diff --git a/test/integration/test/integration/default/file_spec.rb b/test/integration/test/integration/default/file_spec.rb index f4fc26f40..4f1a423ec 100644 --- a/test/integration/test/integration/default/file_spec.rb +++ b/test/integration/test/integration/default/file_spec.rb @@ -108,4 +108,40 @@ if os.unix? its('type') { should eq :directory } end + # for server spec compatibility + # Do not use `.with` or `.only_with`, this syntax is deprecated and will be removed + # in InSpec version 1 + describe file('/mnt/iso-disk') do + it { should be_mounted } + it { should be_mounted.with( :type => 'iso9660' ) } + it { should be_mounted.with( :type => 'iso9660', :options => { :ro => true } ) } + it { should be_mounted.with( :type => 'iso9660', :device => '/root/alpine-3.3.0-x86_64.iso' ) } + it { should_not be_mounted.with( :type => 'ext4' ) } + it { should_not be_mounted.with( :type => 'xfs' ) } + end + + # compare with exact match + describe file('/mnt/iso-disk') do + it { should be_mounted.only_with( { + :device=>"/root/alpine-3.3.0-x86_64.iso", + :type=>"iso9660", + :options=>{ + :ro=>true} + }) + } + end + + # instead of `.with` or `.only_with` we recommend to use the `mount` resource + describe mount '/mnt/iso-disk' do + it { should be_mounted } + its('device') { should eq '/root/alpine-3.3.0-x86_64.iso' } + its('type') { should eq 'iso9660' } + its('options') { should eq ['ro'] } + end + +elsif os.windows? + describe file('C:\\Windows') do + it { should exist } + it { should be_directory } + end end From 7e7cf5a724f3a237905060f4e08ad4dc36895e7f Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 31 Dec 2015 01:11:06 +0100 Subject: [PATCH 06/13] add documentation for `mount` resource --- docs/resources.rst | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/resources.rst b/docs/resources.rst index 3af44ec12..f5237b2c4 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -26,6 +26,7 @@ The following InSpec audit resources are available: * `kernel_parameter`_ * `limits_conf`_ * `login_defs`_ +* `mount`_ * `mysql_conf`_ * `mysql_session`_ * `npm`_ @@ -2116,6 +2117,84 @@ The following examples show how to use this InSpec audit resource. its('PASS_MAX_DAYS') { should eq '90' } end + +mount +===================================================== +Use the ``mount`` |inspec resource| to test the mountpoints on |linux| systems. + +**Stability: Experimental** + +Syntax +----------------------------------------------------- +An ``mount`` |inspec resource| block declares the synchronization settings that should be tested: + +.. code-block:: ruby + + describe mount('path') do + it { should MATCHER 'value' } + end + +where + +* ``('path')`` is the path to the mounted directory +* ``MATCHER`` is a valid matcher for this |inspec resource| +* ``'value'`` is the value to be tested + +Matchers +----------------------------------------------------- +This |inspec resource| has the following matchers: + +be_mounted ++++++++++++++++++++++++++++++++++++++++++++++++++++++ +The ``be_mounted`` matcher tests if the file is accessible from the file system: + +.. code-block:: ruby + + it { should be_mounted } + +device ++++++++++++++++++++++++++++++++++++++++++++++++++++++ +The ``device`` matcher tests the device from the fstab table: + +.. code-block:: ruby + + its('device') { should eq '/dev/mapper/VolGroup-lv_root' } + +type ++++++++++++++++++++++++++++++++++++++++++++++++++++++ +The ``type`` matcher tests the filesystem type: + +.. code-block:: ruby + + its('type') { should eq 'ext4' } + + +options ++++++++++++++++++++++++++++++++++++++++++++++++++++++ +The ``options`` matcher tests the mount options for the filesystem from the fstab table: + +.. code-block:: ruby + + its('options') { should eq ['rw', 'mode=620'] } + + +Examples +----------------------------------------------------- +The following examples show how to use this InSpec audit resource. + +**Test a the mount point on '/'** + +.. code-block:: ruby + + describe mount('/') do + it { should be_mounted } + its('device') { should eq '/dev/mapper/VolGroup-lv_root' } + its('type') { should eq 'ext4' } + its('options') { should eq ['rw', 'mode=620'] } + end + + + mysql_conf ===================================================== Use the ``mysql_conf`` |inspec resource| to test the contents of the configuration file for |mysql|, typically located at ``/etc/mysql/my.cnf`` or ``/etc/my.cnf``. From 9930773f37a6873307984725c2778df771e61e20 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sat, 2 Jan 2016 22:57:52 +0100 Subject: [PATCH 07/13] restrict mount functionality to linux --- lib/resources/file.rb | 3 +++ lib/resources/mount.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/lib/resources/file.rb b/lib/resources/file.rb index e73528513..09d6bc88c 100644 --- a/lib/resources/file.rb +++ b/lib/resources/file.rb @@ -65,6 +65,9 @@ module Inspec::Resources # return if no additional parameters have been provided return file.mounted? if expected_options.nil? + # we cannot read mount data on non-Linux systems + return nil if !inspec.os.linux? + # parse content if we are on linux @mount_options ||= parse_mount_options(mounted.stdout, true) diff --git a/lib/resources/mount.rb b/lib/resources/mount.rb index f9e8191c6..de59b7c4b 100644 --- a/lib/resources/mount.rb +++ b/lib/resources/mount.rb @@ -21,6 +21,7 @@ class Mount < Inspec.resource(1) def initialize(path) @path = path + return skip_resource 'The `mount` resource is not supported on your OS yet.' if !inspec.os.linux? @file = inspec.backend.file(@path) end From e1402a16d94e8a8eff62ac23c089c8ffd5488ffe Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sat, 2 Jan 2016 23:59:22 +0100 Subject: [PATCH 08/13] split integration tests for mount --- test/integration/test/integration/default/file_spec.rb | 9 +-------- test/integration/test/integration/default/mount_spec.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 test/integration/test/integration/default/mount_spec.rb diff --git a/test/integration/test/integration/default/file_spec.rb b/test/integration/test/integration/default/file_spec.rb index 4f1a423ec..a049e62b3 100644 --- a/test/integration/test/integration/default/file_spec.rb +++ b/test/integration/test/integration/default/file_spec.rb @@ -121,6 +121,7 @@ if os.unix? end # compare with exact match + # also see mount_spec.rb describe file('/mnt/iso-disk') do it { should be_mounted.only_with( { :device=>"/root/alpine-3.3.0-x86_64.iso", @@ -131,14 +132,6 @@ if os.unix? } end - # instead of `.with` or `.only_with` we recommend to use the `mount` resource - describe mount '/mnt/iso-disk' do - it { should be_mounted } - its('device') { should eq '/root/alpine-3.3.0-x86_64.iso' } - its('type') { should eq 'iso9660' } - its('options') { should eq ['ro'] } - end - elsif os.windows? describe file('C:\\Windows') do it { should exist } diff --git a/test/integration/test/integration/default/mount_spec.rb b/test/integration/test/integration/default/mount_spec.rb new file mode 100644 index 000000000..628c1dc99 --- /dev/null +++ b/test/integration/test/integration/default/mount_spec.rb @@ -0,0 +1,9 @@ +# encoding: utf-8 + +# instead of `.with` or `.only_with` we recommend to use the `mount` resource +describe mount '/mnt/iso-disk' do + it { should be_mounted } + its('device') { should eq '/root/alpine-3.3.0-x86_64.iso' } + its('type') { should eq 'iso9660' } + its('options') { should eq ['ro'] } +end From a72ba94f103620542ec7fb143da08057c96f2fe8 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sun, 3 Jan 2016 00:01:26 +0100 Subject: [PATCH 09/13] handle mount results with multiple entries --- lib/resources/mount.rb | 19 +++++++++++++++++-- test/helper.rb | 1 + .../test/integration/default/mount_spec.rb | 1 + test/unit/mock/cmd/mount-multiple | 2 ++ test/unit/resources/mount_test.rb | 18 ++++++++++++++---- 5 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 test/unit/mock/cmd/mount-multiple diff --git a/lib/resources/mount.rb b/lib/resources/mount.rb index de59b7c4b..c54004ce2 100644 --- a/lib/resources/mount.rb +++ b/lib/resources/mount.rb @@ -10,6 +10,7 @@ class Mount < Inspec.resource(1) example " describe mount('/') do it { should be_mounted } + its(:count) { should eq 1 } its('device') { should eq '/dev/mapper/VolGroup-lv_root' } its('type') { should eq 'ext4' } its('options') { should eq ['rw', 'mode=620'] } @@ -29,14 +30,28 @@ class Mount < Inspec.resource(1) file.mounted? end + def count + mounted = file.mounted + + if !mounted.nil? && !mounted.stdout.nil? && !mounted.stdout.lines.nil? + mounted.stdout.lines.count + else + nil + end + end + def method_missing(name) return nil if !file.mounted? mounted = file.mounted + return nil if mounted.nil? || mounted.stdout.nil? + + line = mounted.stdout + # if we got multiple lines, only use the last entry + line = mounted.stdout.lines.last if mounted.stdout.lines.count > 1 # parse content if we are on linux - @mount_options ||= parse_mount_options(mounted.stdout) - + @mount_options ||= parse_mount_options(line) @mount_options[name] end diff --git a/test/helper.rb b/test/helper.rb index ef885a57d..60d8ab84b 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -198,6 +198,7 @@ class MockLoader 'find /etc/apache2/conf-enabled/*.conf -maxdepth 1 -type f' => cmd.call('find-apache2-conf-enabled'), # mount "mount | grep -- ' on /'" => cmd.call("mount"), + "mount | grep -- ' on /mnt/iso-disk'" => cmd.call("mount-multiple"), } @backend diff --git a/test/integration/test/integration/default/mount_spec.rb b/test/integration/test/integration/default/mount_spec.rb index 628c1dc99..353ed81d0 100644 --- a/test/integration/test/integration/default/mount_spec.rb +++ b/test/integration/test/integration/default/mount_spec.rb @@ -3,6 +3,7 @@ # instead of `.with` or `.only_with` we recommend to use the `mount` resource describe mount '/mnt/iso-disk' do it { should be_mounted } + its('count') { should eq 1 } its('device') { should eq '/root/alpine-3.3.0-x86_64.iso' } its('type') { should eq 'iso9660' } its('options') { should eq ['ro'] } diff --git a/test/unit/mock/cmd/mount-multiple b/test/unit/mock/cmd/mount-multiple new file mode 100644 index 000000000..64b4974f9 --- /dev/null +++ b/test/unit/mock/cmd/mount-multiple @@ -0,0 +1,2 @@ +/root/alpine-3.3.0-x86_64.iso on /mnt/iso-disk type iso9660 (ro) +/root/alpine-3.3.0-x86_64_2.iso on /mnt/iso-disk type iso9660 (ro) diff --git a/test/unit/resources/mount_test.rb b/test/unit/resources/mount_test.rb index 85dda3630..f04be55a3 100644 --- a/test/unit/resources/mount_test.rb +++ b/test/unit/resources/mount_test.rb @@ -6,11 +6,21 @@ require 'helper' require 'inspec/resource' describe Inspec::Resources::File do - let(:resource) { load_resource('mount', '/') } + let(:root_resource) { load_resource('mount', '/') } it 'parses the mount data properly' do - resource.send(:device).must_equal('/dev/xvda1') - resource.send(:type).must_equal('ext4') - resource.send(:options).must_equal(['rw','discard']) + root_resource.send(:device).must_equal('/dev/xvda1') + root_resource.send(:type).must_equal('ext4') + root_resource.send(:options).must_equal(['rw','discard']) + root_resource.send(:count).must_equal(1) + end + + let(:iso_resource) { load_resource('mount', '/mnt/iso-disk') } + + it 'parses the mount data properly' do + iso_resource.send(:device).must_equal('/root/alpine-3.3.0-x86_64_2.iso') + iso_resource.send(:type).must_equal('iso9660') + iso_resource.send(:options).must_equal(['ro']) + iso_resource.send(:count).must_equal(2) end end From e1d7d30919a5f7c20a9e57ccb173b5ed900d8106 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sun, 3 Jan 2016 00:01:54 +0100 Subject: [PATCH 10/13] add deprecation warning for serverspec users --- lib/resources/file.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/resources/file.rb b/lib/resources/file.rb index 09d6bc88c..17dd2e211 100644 --- a/lib/resources/file.rb +++ b/lib/resources/file.rb @@ -65,6 +65,9 @@ module Inspec::Resources # return if no additional parameters have been provided return file.mounted? if expected_options.nil? + # deprecation warning, this functionality will be removed in future version + warn "[DEPRECATION] `be_mounted.with and be_mounted.only_with` are deprecated. Please use `mount('#{path}')` instead." + # we cannot read mount data on non-Linux systems return nil if !inspec.os.linux? From 0ca7e47ac76c48f6b32a51bc45cd0f315dd73101 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sun, 3 Jan 2016 00:16:27 +0100 Subject: [PATCH 11/13] update train dependency to 0.9.3 --- inspec.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspec.gemspec b/inspec.gemspec index e8597b46b..9b223ecf8 100644 --- a/inspec.gemspec +++ b/inspec.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] - spec.add_dependency 'r-train', '~> 0.9' + spec.add_dependency 'r-train', '~> 0.9', '>= 0.9.3' spec.add_dependency 'thor', '~> 0.19' spec.add_dependency 'json', '~> 1.8' spec.add_dependency 'rainbow', '~> 2' From 89532782047092ccfe210c33afbdb114b937b940 Mon Sep 17 00:00:00 2001 From: Dominik Richter Date: Sun, 3 Jan 2016 09:33:20 +0100 Subject: [PATCH 12/13] unfortunately Enumerator#last is not supported --- lib/resources/mount.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resources/mount.rb b/lib/resources/mount.rb index c54004ce2..44519ac50 100644 --- a/lib/resources/mount.rb +++ b/lib/resources/mount.rb @@ -48,7 +48,7 @@ class Mount < Inspec.resource(1) line = mounted.stdout # if we got multiple lines, only use the last entry - line = mounted.stdout.lines.last if mounted.stdout.lines.count > 1 + line = mounted.stdout.lines.to_a.last if mounted.stdout.lines.count > 1 # parse content if we are on linux @mount_options ||= parse_mount_options(line) From 26c0cd0871753dd02c78ca4fbad22d3db3c8e13b Mon Sep 17 00:00:00 2001 From: Dominik Richter Date: Sun, 3 Jan 2016 09:49:40 +0100 Subject: [PATCH 13/13] lint --- lib/resources/file.rb | 2 +- lib/resources/mount.rb | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/resources/file.rb b/lib/resources/file.rb index 17dd2e211..0e7687acc 100644 --- a/lib/resources/file.rb +++ b/lib/resources/file.rb @@ -5,7 +5,7 @@ # license: All rights reserved module Inspec::Resources - class File < Inspec.resource(1) + class File < Inspec.resource(1) # rubocop:disable Metrics/ClassLength name 'file' desc 'Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, named pipes, sockets, character devices, block devices, and doors.' example " diff --git a/lib/resources/mount.rb b/lib/resources/mount.rb index 44519ac50..8be324ad5 100644 --- a/lib/resources/mount.rb +++ b/lib/resources/mount.rb @@ -32,12 +32,8 @@ class Mount < Inspec.resource(1) def count mounted = file.mounted - - if !mounted.nil? && !mounted.stdout.nil? && !mounted.stdout.lines.nil? - mounted.stdout.lines.count - else - nil - end + return nil if mounted.nil? || mounted.stdout.nil? + mounted.stdout.lines.count end def method_missing(name)