-
Notifications
You must be signed in to change notification settings - Fork 453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a plugin for Windows mimicing the Unix dmi plugin #1445
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
82de207
Expand windows dmi.
phiggins 64b4979
Do some key munging so stuff resembles other stuff.
phiggins 4bba1b9
Preserve original key names rather than reconstructing them.
phiggins 5788971
Add regression tests for Windows dmi plugin.
phiggins 4132387
Make the existing SystemEnclosure plugin depend on the new Windows DM…
phiggins 3789de2
Remove comments with reference info.
phiggins 3c88a66
Fix chefstyle violations.
phiggins 7a5f1ea
Add some comments.
phiggins 196c618
Add rubular link for de-camelcase regex.
phiggins f1ff813
Simplify a small part of test setup.
phiggins aeb0375
Properly handle multiple things being returned from Windows API.
phiggins f6a02a4
Fix chefstyle violations.
phiggins e000b3d
Fix copyright messages.
phiggins 3c48e7a
Filter out unnedded properties.
phiggins e40757d
Rename some keys from their Windows versions to Unix equivalents.
phiggins aace5bb
Fix chefstyle violations.
phiggins f85082c
Fix typo in comment.
phiggins c756955
Add some comments explaining test setup.
phiggins File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# | ||
# Author:: Pete Higgins (pete@peterhiggins.org) | ||
# Copyright:: Copyright (c) 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(:DMI) do | ||
provides "dmi" | ||
|
||
# Map the linux component types to their rough Windows API equivalents | ||
DMI_TO_WIN32OLE = { | ||
chassis: "SystemEnclosure", | ||
phiggins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
processor: "Processor", | ||
bios: "Bios", | ||
system: "ComputerSystemProduct", | ||
base_board: "BaseBoard", | ||
}.freeze | ||
|
||
# This regex is in 3 parts for the different supported patterns in camel | ||
# case names coming from the Windows API: | ||
# * Typical camelcase, eg Depth, PartNumber, NumberOfPowerCords | ||
# * Acronyms preceding camelcase, eg SMBIOSAssetTag | ||
# * Acronyms that occur at the end of the name, eg SKU, DeviceID | ||
# | ||
# This cannot handle some property names, eg SMBIOSBIOSVersion. | ||
# https://rubular.com/r/FBNtXod4wkZGAG | ||
SPLIT_REGEX = /[A-Z][a-z0-9]+|[A-Z]{2,}(?=[A-Z][a-z0-9])|[A-Z]{2,}/.freeze | ||
|
||
WINDOWS_TO_UNIX_KEYS = [ | ||
%w{vendor manufacturer}, | ||
%w{identifying_number serial_number}, | ||
%w{name family}, | ||
].freeze | ||
|
||
collect_data(:windows) do | ||
require "ohai/common/dmi" | ||
require "wmi-lite/wmi" | ||
wmi = WmiLite::Wmi.new | ||
|
||
dmi Mash.new | ||
|
||
# The Windows API returns property names in camel case, eg "SerialNumber", | ||
# while `dmi` returns them as space separated strings, eg "Serial Number". | ||
# `Ohai::Common::DMI.convenience_keys` expects property names in `dmi`'s | ||
# format, so build two parallel hashes with the keys as they come from the | ||
# Windows API and in a faked-out `dmi` version. After the call to | ||
# `Ohai::Common::DMI.convenience_keys` replace the faked-out `dmi` | ||
# collection with the one with the original property names. | ||
DMI_TO_WIN32OLE.each do |dmi_key, ole_key| | ||
wmi_objects = wmi.instances_of("Win32_#{ole_key}").map(&:wmi_ole_object) | ||
|
||
split_name_properties = [] | ||
properties = [] | ||
|
||
wmi_objects.each do |wmi_object| | ||
split_name_properties << Mash.new | ||
properties << Mash.new | ||
|
||
wmi_object.properties_.each do |property| | ||
property_name = property.name | ||
value = wmi_object.invoke(property_name) | ||
|
||
split_name = property_name.scan(SPLIT_REGEX).join(" ") | ||
split_name_properties.last[split_name] = value | ||
properties.last[property_name] = value | ||
end | ||
end | ||
|
||
dmi[dmi_key] = Mash.new(all_records: split_name_properties, _all_records: properties) | ||
end | ||
|
||
Ohai::Common::DMI.convenience_keys(dmi) | ||
|
||
dmi.each_value do |records| | ||
records[:all_records] = records.delete(:_all_records) | ||
|
||
WINDOWS_TO_UNIX_KEYS.each do |windows_key, unix_key| | ||
records[unix_key] = records.delete(windows_key) if records.key?(windows_key) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,13 +18,11 @@ | |
|
||
Ohai.plugin :SystemEnclosure do | ||
provides "system_enclosure" | ||
depends "dmi" | ||
|
||
collect_data(:windows) do | ||
require "wmi-lite/wmi" | ||
system_enclosure Mash.new | ||
wmi = WmiLite::Wmi.new | ||
wmi_object = wmi.first_of("Win32_SystemEnclosure").wmi_ole_object | ||
system_enclosure[:manufacturer] = wmi_object.invoke("manufacturer") | ||
system_enclosure[:serialnumber] = wmi_object.invoke("serialnumber") | ||
system_enclosure[:manufacturer] = get_attribute(:dmi, :chassis, :manufacturer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should cut an issue in cookstyle to get people using node['system_enclosure']['manufacturer'] onto the DMI equiv in the future. That way we can eventually remove this plugin namespace |
||
system_enclosure[:serialnumber] = get_attribute(:dmi, :chassis, :serial_number) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
# | ||
# Author:: Pete Higgins (pete@peterhiggins.org) | ||
# Copyright:: Copyright (c) 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. | ||
# | ||
|
||
require "spec_helper" | ||
|
||
describe Ohai::System, "DMI", :windows_only do | ||
let(:plugin) { get_plugin("windows/dmi") } | ||
|
||
before do | ||
require "wmi-lite/wmi" | ||
|
||
empty_wmi_object = WmiLite::Wmi::Instance.new(double(properties_: [])) | ||
%w{Processor Bios ComputerSystemProduct BaseBoard}.each do |type| | ||
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_#{type}").and_return([empty_wmi_object]) | ||
end | ||
end | ||
|
||
context "when property names are different types of camel casing" do | ||
# Each test case has 3 elements: | ||
# * The name of the property as it comes from the Windows APIs | ||
# * The transformed snake-case version of the property name | ||
# * A unique dummy value per test case | ||
CASES = [ | ||
%w{Depth depth aaa}, | ||
%w{PartNumber part_number bbb}, | ||
%w{NumberOfPowerCords number_of_power_cords ccc}, | ||
%w{SKU sku ddd}, | ||
%w{SMBIOSAssetTag smbios_asset_tag eee}, | ||
%w{DeviceID device_id fff}, | ||
%w{L2CacheSize l2_cache_size ggg}, | ||
].freeze | ||
|
||
before do | ||
properties = CASES.map { |name, _, _| double(name: name) } | ||
wmi_ole_object = double properties_: properties | ||
|
||
CASES.each do |name, _, value| | ||
allow(wmi_ole_object).to receive(:invoke).with(name).and_return(value) | ||
end | ||
|
||
wmi_object = WmiLite::Wmi::Instance.new(wmi_ole_object) | ||
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_SystemEnclosure").and_return([wmi_object]) | ||
|
||
plugin.run | ||
end | ||
|
||
CASES.each do |name, transformed_name, value| | ||
it "adds #{name} to :all_records" do | ||
expect(plugin[:dmi][:chassis][:all_records].first[name]).to eq(value) | ||
end | ||
|
||
it "adds #{transformed_name} to the root" do | ||
expect(plugin[:dmi][:chassis][transformed_name]).to eq(value) | ||
end | ||
end | ||
end | ||
|
||
context "when multiple objects of one type are returned from the Windows API" do | ||
before do | ||
properties = [ | ||
double(name: "UniqueProperty"), | ||
double(name: "SharedProperty"), | ||
] | ||
|
||
wmi_ole_objects = %w{tacos nachos}.map do |value| | ||
object = double properties_: properties | ||
allow(object).to receive(:invoke).with("UniqueProperty").and_return(value) | ||
allow(object).to receive(:invoke).with("SharedProperty").and_return("Taco Bell") | ||
object | ||
end | ||
|
||
wmi_objects = wmi_ole_objects.map { |o| WmiLite::Wmi::Instance.new(o) } | ||
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_SystemEnclosure").and_return(wmi_objects) | ||
|
||
plugin.run | ||
end | ||
|
||
it "adds unique values to :all_records" do | ||
values = plugin[:dmi][:chassis][:all_records].map { |r| r["UniqueProperty"] } | ||
expect(values).to eq(%w{tacos nachos}) | ||
end | ||
|
||
it "adds shared values to the root with snake case key" do | ||
expect(plugin[:dmi][:chassis]["shared_property"]).to eq("Taco Bell") | ||
end | ||
end | ||
|
||
context "with extra information that should be filtered out" do | ||
# Each test case has 3 elements: | ||
# * The name of the property as it comes from the Windows APIs | ||
# * The transformed snake-case version of the property name | ||
# * A unique dummy value per test case | ||
FILTERED_KEYS = [ | ||
%w{Caption caption aaa}, | ||
%w{CreationClassName creation_class_name bbb}, | ||
%w{SystemCreationClassName system_creation_class_name ccc}, | ||
].freeze | ||
|
||
before do | ||
properties = FILTERED_KEYS.map { |name, _, _| double(name: name) } | ||
wmi_ole_object = double properties_: properties | ||
|
||
FILTERED_KEYS.each do |name, _, value| | ||
allow(wmi_ole_object).to receive(:invoke).with(name).and_return(value) | ||
end | ||
|
||
wmi_object = WmiLite::Wmi::Instance.new(wmi_ole_object) | ||
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_SystemEnclosure").and_return([wmi_object]) | ||
|
||
plugin.run | ||
end | ||
|
||
FILTERED_KEYS.each do |name, transformed_name, value| | ||
it "adds #{name} to :all_records" do | ||
expect(plugin[:dmi][:chassis][:all_records].first[name]).to eq(value) | ||
end | ||
|
||
it "does not add #{transformed_name} to the root" do | ||
expect(plugin[:dmi][:chassis]).not_to have_key(transformed_name) | ||
end | ||
end | ||
end | ||
|
||
context "with information that should be made to match other platforms" do | ||
# Each test case has 4 elements: | ||
# * The name of the property as it comes from the Windows APIs | ||
# * The transformed snake-case version of the property name | ||
# * The Unix equivalent of the property name | ||
# * A unique dummy value per test case | ||
RENAMED_KEYS = [ | ||
%w{Vendor vendor manufacturer aaa}, | ||
%w{IdentifyingNumber identifying_number serial_number bbb}, | ||
%w{Name name family ccc}, | ||
].freeze | ||
|
||
before do | ||
properties = RENAMED_KEYS.map { |name, _, _, _| double(name: name) } | ||
wmi_ole_object = double properties_: properties | ||
|
||
RENAMED_KEYS.each do |name, _, _, value| | ||
allow(wmi_ole_object).to receive(:invoke).with(name).and_return(value) | ||
end | ||
|
||
wmi_object = WmiLite::Wmi::Instance.new(wmi_ole_object) | ||
expect_any_instance_of(WmiLite::Wmi).to receive(:instances_of).with("Win32_SystemEnclosure").and_return([wmi_object]) | ||
|
||
plugin.run | ||
end | ||
|
||
RENAMED_KEYS.each do |name, transformed_name, renamed_name, value| | ||
it "adds #{name} to :all_records" do | ||
expect(plugin[:dmi][:chassis][:all_records].first[name]).to eq(value) | ||
end | ||
|
||
it "adds #{renamed_name} to the root" do | ||
expect(plugin[:dmi][:chassis][renamed_name]).to eq(value) | ||
end | ||
|
||
it "does not add #{transformed_name} to the root" do | ||
expect(plugin[:dmi][:chassis]).not_to have_key(transformed_name) | ||
end | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Windows API returns values other than strings, which seemed to break an expectation of the values coming from the existing dmi plugin. There is a call to
value.strip
a few lines down so it seemed like a test for String was more in line with the intent here.