Skip to content

Commit 4fa1e66

Browse files
author
Gerard Hickey
committed
Facter modlue for gathering memory/firmware facts
1 parent 6927e44 commit 4fa1e66

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Gathers hardware-related facts from the underlying system pertaining
2+
# to the system memory. Information gathered here is exposed directly as
3+
# Facter facts for the purpose of node registration.
4+
#
5+
#
6+
7+
# add the '/usr/local/lib/ruby' directory to the LOAD_PATH
8+
# (this is where the hanlon_microkernel module files are placed by
9+
# our Dockerfile)
10+
$LOAD_PATH.unshift('/usr/local/lib/ruby')
11+
12+
require 'facter'
13+
14+
15+
# Takes the output of a lshw command and converts it to a Hash of name/value
16+
# pairs (where the names are the properties, as Symbols, and the values are
17+
# Hash maps containing the values for those properties). Note: the values
18+
# themselves may map via their key values to a deeper Array/Hash map;
19+
# containment is implied by the level of indentation of the lines that start
20+
# with an asterisk (once any leading spaces are stripped off) and the type of
21+
# value (either an Array of maps or a Hash map) is implied by the structure of
22+
# that line (lines that3 look like "*-key:N", where N is an integer imply Array
23+
# of Hash maps should be constructed under a key derived from key name, while
24+
# those without the integer value imply a single Hash map is contained under
25+
# that key)
26+
#
27+
# @param command_output [String] the raw output from lshw command
28+
# @param delimiter [String] the delimiter that should be used to separate the
29+
# name/value pairs in the raw lshw command output
30+
# @return [Hash<String, Array<String>>] a Hash map containing the names of the
31+
# properties as keys and a Hash map containing the values for those
32+
# properties.
33+
def def_to_hash(definition, delimiter=':')
34+
# first, iterate through the output and determine the containment implied by the indentation
35+
# of each of the sections in the output. As an example, the output of the "lshw -c memory"
36+
# command looks like the following:
37+
#
38+
# *-firmware
39+
# description: BIOS
40+
# ...
41+
# *-memory
42+
# description: System Memory
43+
# ...
44+
# size: 36GiB
45+
# *-bank:0
46+
# description: DIMM Synchronous 1333 MHz (0.8 ns)
47+
# ...
48+
# *-bank:N
49+
# *-cache:0
50+
# ...
51+
# which implies a structure like the following
52+
# { "firmware" => { "description" => "BIOS" ... }
53+
# "memory" => { "description" => "System Memory" ... bank_array => [ { "description" => "DIMM..." }
54+
# ...
55+
# { "description" => "DIMM..." } ] }
56+
# "cache_array" => [ { "description" => "L1 cache" ... }
57+
# ...
58+
# { "description" => "L3 cache" ... }
59+
# ]
60+
# }
61+
result = {}
62+
63+
unless definition.empty?
64+
if definition =~ /\s\*-\w+/
65+
# definition has sub-definitions in it
66+
definition =~ /^(\s+)\*-\w/
67+
indent = $1
68+
69+
# break into sub-definitions. first one may be only values
70+
parts = definition.split(/^\s{#{indent.length}}\*-/)
71+
72+
# process the first part. returns hash or nothing
73+
result.merge!(def_to_hash(parts.shift))
74+
75+
parts.each do |subdef|
76+
lines = subdef.split(/\n/)
77+
unless lines.empty?
78+
# first line is the title with optional instance
79+
title, instance = lines.shift.split(':')
80+
81+
# check for array of titles or start an array of titles
82+
if result.has_key? "#{title}_array"
83+
result["#{title}_array"] << def_to_hash(lines.join("\n"))
84+
elsif result.has_key? title
85+
result["#{title}_array"] = [ result[title] ]
86+
result.delete title
87+
result["#{title}_array"] << def_to_hash(lines.join("\n"))
88+
else
89+
result[title] = def_to_hash(lines.join("\n"))
90+
end
91+
end
92+
end
93+
else
94+
# no sub-definitions, just process the attributes
95+
result.merge! Hash[
96+
definition.split(/\n/).collect do |l|
97+
l =~ /^\s*([^#{delimiter}]+)#{delimiter}\s+(.*)\s*$/; v=$2; [$1.gsub(/\s/, '_'), v]
98+
end
99+
]
100+
end
101+
end
102+
103+
result
104+
end
105+
106+
107+
108+
virtual_type = Facter.value('virtual')
109+
lshw_cmd = (virtual_type && virtual_type == 'kvm') ? 'lshw -disable dmi' : 'lshw'
110+
lshw_c_memory_str = %x[sudo #{lshw_cmd} -c memory 2> /dev/null]
111+
112+
# process the results from lshw -c memory
113+
memory = def_to_hash(lshw_c_memory_str)
114+
115+
# Create the facts for the firmware info
116+
%w{description vendor physical_id version date size capabilities capacity}.each do |fact|
117+
Facter.add("mk_hw_fw_#{fact}") do
118+
setcode { memory['firmware'][fact] }
119+
end
120+
end
121+
122+
# Create the facts for the memory info
123+
%w{description physical_id slot size }.each do |fact|
124+
Facter.add("mk_hw_mem_#{fact}") do
125+
setcode { memory['memory'][fact] }
126+
end
127+
end
128+
129+
slot_info = memory['memory']['bank_array'].select {|entry| entry['size']}
130+
Facter.add("mk_hw_mem_slot_info") do
131+
setcode { slot_info }
132+
end
133+
134+
135+
# # next, the memory information (including firmware, system memory, and caches)
136+
# lshw_c_memory_str = %x[sudo #{lshw_cmd} -c memory 2> /dev/null]
137+
# hash_map = lshw_output_to_hash(lshw_c_memory_str, ":")
138+
# add_hash_to_facts!(hash_map, facts_map, mk_fct_excl_pattern, "mk_hw_mem", /cache_array/)
139+
# # and add a set of facts from this memory information as top-level facts in the
140+
# # facts_map so that we can use them later to tag nodes
141+
# fields_to_include = ["description", "vendor", "physical_id", "version",
142+
# "date", "size", "capabilities", "capacity"]
143+
# add_flattened_hash_to_facts!(hash_map["firmware"], facts_map,
144+
# "mk_hw_fw", fields_to_include)
145+
# fields_to_include = ["description", "physical_id", "slot", "size"]
146+
# add_flattened_hash_to_facts!(hash_map["memory"], facts_map,
147+
# "mk_hw_mem", fields_to_include)
148+
# # grab the same meta-data from the slots that aren't empty from the "bank_array"
149+
# # field of our hash_map
150+
# non_empty_slot_info = hash_map["bank_array"].select{ |slot_entry| slot_entry['size'] }
151+
# add_flattened_array_to_facts!(non_empty_slot_info, facts_map,
152+
# "mk_hw_mem_slot", fields_to_include)
153+
154+

0 commit comments

Comments
 (0)