summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2019-12-06 14:05:21 -0800
committerGitHub <noreply@github.com>2019-12-06 14:05:21 -0800
commit1d9343d1761a5a57a63ac0b325dd3efda9b2c577 (patch)
tree6b3f5cd56bad0b3982c1a3e932aeee46d95b0985
parente243f2f3d1aa14b81f927300c2555dedc1372b82 (diff)
parentfe528cbb0f5fda0466a36c9a94bbf112ad82c278 (diff)
downloadohai-1d9343d1761a5a57a63ac0b325dd3efda9b2c577.tar.gz
Merge pull request #1267 from jaymzh/windows_fs2
[filesystem] Convert windows to filesystem2
-rw-r--r--lib/ohai/plugins/filesystem.rb166
-rw-r--r--lib/ohai/plugins/windows/filesystem.rb147
-rw-r--r--spec/unit/plugins/windows/filesystem_spec.rb146
3 files changed, 283 insertions, 176 deletions
diff --git a/lib/ohai/plugins/filesystem.rb b/lib/ohai/plugins/filesystem.rb
index 32ddb607..e2671635 100644
--- a/lib/ohai/plugins/filesystem.rb
+++ b/lib/ohai/plugins/filesystem.rb
@@ -107,6 +107,14 @@ Ohai.plugin(:Filesystem) do
view
end
+ def generate_deprecated_windows_view(fs)
+ view = generate_mountpoint_view(fs)
+ view.each do |mp, entry|
+ view[mp].delete("devices")
+ end
+ view
+ end
+
def generate_deprecated_solaris_view(fs, old_zfs)
view = generate_deprecated_view(fs)
old_zfs.each do |fsname, attributes|
@@ -153,6 +161,143 @@ Ohai.plugin(:Filesystem) do
logger.warn("Plugin Filesystem: #{bin} binary is not available. Some data will not be available.")
end
+ ### Windows specific methods BEGINS
+ # Volume encryption or decryption status
+ #
+ # @see https://docs.microsoft.com/en-us/windows/desktop/SecProv/getconversionstatus-win32-encryptablevolume#parameters
+ #
+ CONVERSION_STATUS ||= %w{
+ FullyDecrypted FullyEncrypted EncryptionInProgress
+ DecryptionInProgress EncryptionPaused DecryptionPaused
+ }.freeze
+
+ # Returns a Mash loaded with logical details
+ #
+ # Uses Win32_LogicalDisk and logical_properties to return encryption details of volumes.
+ #
+ # Returns an empty Mash in case of any WMI exception.
+ #
+ # @see https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-logicaldisk
+ #
+ # @return [Mash]
+ #
+ def logical_info
+ wmi = WmiLite::Wmi.new("Root\\CIMV2")
+
+ # Note: we should really be parsing Win32_Volume and Win32_Mapped drive.
+ disks = wmi.instances_of("Win32_LogicalDisk")
+ logical_properties(disks)
+ rescue WmiLite::WmiException
+ Ohai::Log.debug("Unable to access Win32_LogicalDisk. Skipping logical details")
+ Mash.new
+ end
+
+ # Returns a Mash loaded with encryption details
+ #
+ # Uses Win32_EncryptableVolume and encryption_properties to return encryption details of volumes.
+ #
+ # Returns an empty Mash in case of any WMI exception.
+ #
+ # @note We are fetching Encryption Status only as of now
+ #
+ # @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa376483(v=vs.85).aspx
+ #
+ # @return [Mash]
+ #
+ def encryptable_info
+ wmi = WmiLite::Wmi.new("Root\\CIMV2\\Security\\MicrosoftVolumeEncryption")
+ disks = wmi.instances_of("Win32_EncryptableVolume")
+ encryption_properties(disks)
+ rescue WmiLite::WmiException
+ Ohai::Log.debug("Unable to access Win32_EncryptableVolume. Skipping encryptable details")
+ Mash.new
+ end
+
+ # Refines and calculates logical properties out of given instances.
+ #
+ # Note that :device here is the same as Volume name and there for compatibility with other OSes.
+ #
+ # @param [WmiLite::Wmi::Instance] disks
+ #
+ # @return [Mash] Each drive containing following properties:
+ #
+ # * :kb_size (Integer)
+ # * :kb_available (Integer)
+ # * :kb_used (Integer)
+ # * :percent_used (Integer)
+ # * :mount (String)
+ # * :fs_type (String)
+ # * :volume_name (String)
+ # * :device (String)
+ #
+ def logical_properties(disks)
+ properties = Mash.new
+ disks.each do |disk|
+ property = Mash.new
+ # In windows the closet thing we have to a device is the volume_name
+ # and the "mountpoint" is the drive letter...
+ device = disk["volume_name"].to_s.downcase
+ mount = disk["deviceid"]
+ property[:kb_size] = disk["size"] ? disk["size"].to_i / 1000 : 0
+ property[:kb_available] = disk["freespace"].to_i / 1000
+ property[:kb_used] = property[:kb_size] - property[:kb_available]
+ property[:percent_used] = (property[:kb_size] == 0 ? 0 : (property[:kb_used] * 100 / property[:kb_size]))
+ property[:mount] = mount
+ property[:fs_type] = disk["filesystem"].to_s.downcase
+ property[:volume_name] = device
+ property[:device] = device
+
+ key = "#{device},#{mount}"
+ properties[key] = property
+ end
+ properties
+ end
+
+ # Refines and calculates encryption properties out of given instances
+ #
+ # @param [WmiLite::Wmi::Instance] disks
+ #
+ # @return [Mash] Each drive containing following properties:
+ #
+ # * :encryption_status (String)
+ #
+ def encryption_properties(disks)
+ properties = Mash.new
+ disks.each do |disk|
+ property = Mash.new
+ property[:encryption_status] = disk["conversionstatus"] ? CONVERSION_STATUS[disk["conversionstatus"]] : ""
+ key = disk["driveletter"]
+ properties[key] = property
+ end
+ properties
+ end
+
+ # Merges all the various properties of filesystems
+ #
+ # @param [Array<Mash>] disks_info
+ # Array of the Mashes containing disk properties
+ #
+ # @return [Mash]
+ #
+ def merge_info(logical_info, encryption_info)
+ fs = Mash.new
+
+ encryption_keys_used = Set.new
+ logical_info.each do |key, info|
+ if encryption_info[info["mount"]]
+ encryption_keys_used.add(info["mount"])
+ fs[key] = info.merge(encryption_info[info["mount"]])
+ else
+ fs[key] = info.dup
+ end
+ end
+ left_enc = encryption_info.reject { |x| encryption_keys_used.include?(x) }
+ left_enc.each do |key, info|
+ fs[",#{key}"] = info
+ end
+ fs
+ end
+
collect_data(:linux) do
fs = Mash.new
@@ -599,4 +744,25 @@ Ohai.plugin(:Filesystem) do
filesystem generate_deprecated_view(fs)
filesystem2 fs_data
end
+
+ collect_data(:windows) do
+ require "wmi-lite/wmi"
+ require "ohai/mash"
+
+ fs = merge_info(logical_info, encryptable_info)
+
+ by_pair = fs
+ by_device = generate_device_view(fs)
+ by_mountpoint = generate_mountpoint_view(fs)
+
+ fs_data = Mash.new
+ fs_data["by_device"] = by_device
+ fs_data["by_mountpoint"] = by_mountpoint
+ fs_data["by_pair"] = by_pair
+
+ # Set the filesystem data - Windows didn't do the conversion when everyone
+ # else did, so 15 will have both be the new API and 16 will drop the old API
+ filesystem generate_deprecated_windows_view(fs)
+ filesystem2 fs_data
+ end
end
diff --git a/lib/ohai/plugins/windows/filesystem.rb b/lib/ohai/plugins/windows/filesystem.rb
deleted file mode 100644
index e637cf54..00000000
--- a/lib/ohai/plugins/windows/filesystem.rb
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-# Author:: James Gartrell (<jgartrel@gmail.com>)
-# Copyright:: Copyright (c) 2009-2016 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-Ohai.plugin(:Filesystem) do
- provides "filesystem"
-
- # Volume encryption or decryption status
- #
- # @see https://docs.microsoft.com/en-us/windows/desktop/SecProv/getconversionstatus-win32-encryptablevolume#parameters
- #
- CONVERSION_STATUS ||= %w{FullyDecrypted FullyEncrypted EncryptionInProgress
- DecryptionInProgress EncryptionPaused DecryptionPaused}.freeze
-
- # Returns a Mash loaded with logical details
- #
- # Uses Win32_LogicalDisk and logical_properties to return encryption details of volumes.
- #
- # Returns an empty Mash in case of any WMI exception.
- #
- # @see https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-logicaldisk
- #
- # @return [Mash]
- #
- def logical_info
- wmi = WmiLite::Wmi.new("Root\\CIMV2")
-
- # Note: we should really be parsing Win32_Volume and Win32_Mapped drive.
- disks = wmi.instances_of("Win32_LogicalDisk")
- logical_properties(disks)
- rescue WmiLite::WmiException
- Ohai::Log.debug("Unable to access Win32_LogicalDisk. Skipping logical details")
- Mash.new
- end
-
- # Returns a Mash loaded with encryption details
- #
- # Uses Win32_EncryptableVolume and encryption_properties to return encryption details of volumes.
- #
- # Returns an empty Mash in case of any WMI exception.
- #
- # @note We are fetching Encryption Status only as of now
- #
- # @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa376483(v=vs.85).aspx
- #
- # @return [Mash]
- #
- def encryptable_info
- wmi = WmiLite::Wmi.new("Root\\CIMV2\\Security\\MicrosoftVolumeEncryption")
- disks = wmi.instances_of("Win32_EncryptableVolume")
- encryption_properties(disks)
- rescue WmiLite::WmiException
- Ohai::Log.debug("Unable to access Win32_EncryptableVolume. Skipping encryptable details")
- Mash.new
- end
-
- # Refines and calculates logical properties out of given instances
- #
- # @param [WmiLite::Wmi::Instance] disks
- #
- # @return [Mash] Each drive containing following properties:
- #
- # * :kb_size (Integer)
- # * :kb_available (Integer)
- # * :kb_used (Integer)
- # * :percent_used (Integer)
- # * :mount (String)
- # * :fs_type (String)
- # * :volume_name (String)
- #
- def logical_properties(disks)
- properties = Mash.new
- disks.each do |disk|
- property = Mash.new
- drive = disk["deviceid"]
- property[:kb_size] = disk["size"].to_i / 1000
- property[:kb_available] = disk["freespace"].to_i / 1000
- property[:kb_used] = property[:kb_size] - property[:kb_available]
- property[:percent_used] = (property[:kb_size] == 0 ? 0 : (property[:kb_used] * 100 / property[:kb_size]))
- property[:mount] = disk["name"]
- property[:fs_type] = disk["filesystem"].to_s.downcase
- property[:volume_name] = disk["volumename"].to_s.downcase
- properties[drive] = property
- end
- properties
- end
-
- # Refines and calculates encryption properties out of given instances
- #
- # @param [WmiLite::Wmi::Instance] disks
- #
- # @return [Mash] Each drive containing following properties:
- #
- # * :encryption_status (String)
- #
- def encryption_properties(disks)
- properties = Mash.new
- disks.each do |disk|
- drive = disk["driveletter"]
- property = Mash.new
- property[:encryption_status] = disk["conversionstatus"] ? CONVERSION_STATUS[disk["conversionstatus"]] : ""
- properties[drive] = property
- end
- properties
- end
-
- # Merges all the various properties of filesystems
- #
- # @param [Array<Mash>] disks_info
- # Array of the Mashes containing disk properties
- #
- # @return [Mash]
- #
- def merge_info(disks_info)
- fs = Mash.new
- disks_info.each do |info|
- info.each do |disk, data|
- if fs[disk]
- fs[disk].merge!(data)
- else
- fs[disk] = data.dup
- end
- end
- end
- fs
- end
-
- collect_data(:windows) do
- require "wmi-lite/wmi"
- filesystem merge_info([logical_info,
- encryptable_info])
- end
-end
diff --git a/spec/unit/plugins/windows/filesystem_spec.rb b/spec/unit/plugins/windows/filesystem_spec.rb
index 0d6c0632..62996897 100644
--- a/spec/unit/plugins/windows/filesystem_spec.rb
+++ b/spec/unit/plugins/windows/filesystem_spec.rb
@@ -20,7 +20,7 @@ require "spec_helper"
require "wmi-lite/wmi"
describe Ohai::System, "Windows Filesystem Plugin", :windows_only do
- let(:plugin) { get_plugin("windows/filesystem") }
+ let(:plugin) { get_plugin("filesystem") }
let(:success) { true }
@@ -70,9 +70,97 @@ describe Ohai::System, "Windows Filesystem Plugin", :windows_only do
allow(plugin).to receive(:collect_os).and_return(:windows)
end
+ describe "the plugin" do
+ context "when there are no volume names" do
+ before do
+ allow(plugin).to receive(:logical_info).and_return(plugin.logical_properties(logical_disks_instances))
+ allow(plugin).to receive(:encryptable_info).and_return(plugin.encryption_properties(encryptable_volume_instances))
+ plugin.run
+ end
+
+ it "returns space information" do
+ {
+ "kb_size" => 10000,
+ "kb_available" => 100,
+ "kb_used" => 9900,
+ "percent_used" => 99,
+ }.each do |k, v|
+ expect(plugin[:filesystem]["C:"][k]).to eq(v)
+ expect(plugin[:filesystem]["D:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"][",C:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"][",D:"][k]).to eq(v)
+ end
+ end
+
+ it "returns disk information" do
+ {
+ "fs_type" => "ntfs",
+ "volume_name" => "",
+ "encryption_status" => "FullyDecrypted",
+ }.each do |k, v|
+ expect(plugin[:filesystem]["C:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"][",C:"][k]).to eq(v)
+ end
+
+ {
+ "fs_type" => "fat32",
+ "volume_name" => "",
+ "encryption_status" => "EncryptionInProgress",
+ }.each do |k, v|
+ expect(plugin[:filesystem]["D:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"][",D:"][k]).to eq(v)
+ end
+ end
+ end
+
+ context "when there are volume names" do
+ before do
+ ldi = logical_disks_instances
+ ldi.each_with_index { |d, i| d["volume_name"] = "Volume #{i}" }
+ allow(plugin).to receive(:logical_info).and_return(plugin.logical_properties(ldi))
+ allow(plugin).to receive(:encryptable_info).and_return(plugin.encryption_properties(encryptable_volume_instances))
+ plugin.run
+ end
+
+ it "returns space information" do
+ {
+ "kb_size" => 10000,
+ "kb_available" => 100,
+ "kb_used" => 9900,
+ "percent_used" => 99,
+ }.each do |k, v|
+ expect(plugin[:filesystem]["C:"][k]).to eq(v)
+ expect(plugin[:filesystem]["D:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"]["volume 0,C:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"]["volume 1,D:"][k]).to eq(v)
+ end
+ end
+
+ it "returns disk information" do
+ {
+ "fs_type" => "ntfs",
+ "volume_name" => "volume 0",
+ "encryption_status" => "FullyDecrypted",
+ }.each do |k, v|
+ expect(plugin[:filesystem]["C:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"]["volume 0,C:"][k]).to eq(v)
+ end
+
+ {
+ "fs_type" => "fat32",
+ "volume_name" => "volume 1",
+ "encryption_status" => "EncryptionInProgress",
+ }.each do |k, v|
+ expect(plugin[:filesystem]["D:"][k]).to eq(v)
+ expect(plugin[:filesystem2]["by_pair"]["volume 1,D:"][k]).to eq(v)
+ end
+ end
+ end
+ end
+
describe "#logical_properties" do
let(:disks) { logical_disks_instances }
- let(:logical_props) { %i{kb_size kb_available kb_used percent_used mount fs_type volume_name} }
+ let(:logical_props) { %i{kb_size kb_available kb_used percent_used mount fs_type volume_name device} }
it "Returns a mash" do
expect(plugin.logical_properties(disks)).to be_a(Mash)
@@ -85,23 +173,23 @@ describe Ohai::System, "Windows Filesystem Plugin", :windows_only do
it "Returns properties without values when there is no disk information" do
data = plugin.logical_properties([{}])
- expect(data[nil].symbolize_keys.keys).to eq(logical_props)
- expect(data[nil]["kb_used"]).to eq(0)
- expect(data[nil]["fs_type"]).to be_empty
+ expect(data[","].symbolize_keys.keys).to eq(logical_props)
+ expect(data[","]["kb_used"]).to eq(0)
+ expect(data[","]["fs_type"]).to be_empty
end
it "Refines required logical properties out of given instance" do
data = plugin.logical_properties(disks)
- expect(data["C:"].symbolize_keys.keys).to eq(logical_props)
- expect(data["D:"].symbolize_keys.keys).to eq(logical_props)
+ expect(data[",C:"].symbolize_keys.keys).to eq(logical_props)
+ expect(data[",D:"].symbolize_keys.keys).to eq(logical_props)
end
it "Calculates logical properties out of given instance" do
data = plugin.logical_properties(disks)
- expect(data["C:"]["kb_used"]).to eq(data["D:"]["kb_used"]).and eq(9900)
- expect(data["C:"]["percent_used"]).to eq(data["D:"]["percent_used"]).and eq(99)
- expect(data["C:"]["fs_type"]).to eq("ntfs")
- expect(data["D:"]["fs_type"]).to eq("fat32")
+ expect(data[",C:"]["kb_used"]).to eq(data[",D:"]["kb_used"]).and eq(9900)
+ expect(data[",C:"]["percent_used"]).to eq(data[",D:"]["percent_used"]).and eq(99)
+ expect(data[",C:"]["fs_type"]).to eq("ntfs")
+ expect(data[",D:"]["fs_type"]).to eq("fat32")
end
end
@@ -194,33 +282,33 @@ describe Ohai::System, "Windows Filesystem Plugin", :windows_only do
end
describe "#merge_info" do
- let(:info1) do
- { "drive1" => { "x" => 10, "y" => "test1" },
- "drive2" => { "x" => 20, "z" => "test2" } }
+ let(:logical_info) do
+ { "dev1,drive1" => { "mount" => "drive1", "x" => 10, "y" => "test1" },
+ "dev2,drive2" => { "mount" => "drive2", "x" => 20, "z" => "test2" },
+ "dev2,drive3" => { "mount" => "drive3", "x" => 20, "z" => "test3" } }
end
- let(:info2) do
+ let(:encryption_info) do
{ "drive1" => { "k" => 10, "l" => "test1" },
"drive2" => { "l" => 20, "m" => "test2" } }
end
- let(:info3) { { "drive1" => { "o" => 10, "p" => "test1" } } }
- let(:info4) { { "drive2" => { "q" => 10, "r" => "test1" } } }
-
- it "Returns an empty mash when no info is passed" do
- expect(plugin.merge_info([])).to be_a(Mash)
- expect(plugin.merge_info([])).to be_empty
- end
+ let(:logical_info2) { { ",drive1" => { "mount" => "drive1", "o" => 10, "p" => "test1" } } }
+ let(:encryption_info2) { { "drive2" => { "q" => 10, "r" => "test1" } } }
it "Merges all the various properties of filesystems" do
- expect(plugin.merge_info([info1, info2, info3, info4]))
- .to eq("drive1" => { "x" => 10, "y" => "test1", "k" => 10, "l" => "test1", "o" => 10, "p" => "test1" },
- "drive2" => { "x" => 20, "z" => "test2", "l" => 20, "m" => "test2", "q" => 10, "r" => "test1" })
+ expect(plugin.merge_info(logical_info, encryption_info)).to eq(
+ "dev1,drive1" => { "mount" => "drive1", "x" => 10, "y" => "test1", "k" => 10, "l" => "test1" },
+ "dev2,drive2" => { "mount" => "drive2", "x" => 20, "z" => "test2", "l" => 20, "m" => "test2" },
+ "dev2,drive3" => { "mount" => "drive3", "x" => 20, "z" => "test3" }
+ )
end
it "Does not affect any core information after processing" do
- expect(plugin.merge_info([info3, info4])).to eq("drive1" => { "o" => 10, "p" => "test1" },
- "drive2" => { "q" => 10, "r" => "test1" })
- expect(info3).to eq("drive1" => { "o" => 10, "p" => "test1" })
- expect(info4).to eq("drive2" => { "q" => 10, "r" => "test1" })
+ expect(plugin.merge_info(logical_info2, encryption_info2)).to eq(
+ ",drive1" => { "mount" => "drive1", "o" => 10, "p" => "test1" },
+ ",drive2" => { "q" => 10, "r" => "test1" }
+ )
+ expect(logical_info2).to eq(",drive1" => { "mount" => "drive1", "o" => 10, "p" => "test1" })
+ expect(encryption_info2).to eq("drive2" => { "q" => 10, "r" => "test1" })
end
end
end