summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Rakefile1
-rw-r--r--lib/ohai/mixin/command.rb50
-rw-r--r--lib/ohai/mixin/string.rb29
-rw-r--r--lib/ohai/plugins/erlang.rb22
-rw-r--r--lib/ohai/plugins/java.rb10
-rw-r--r--lib/ohai/plugins/kernel.rb17
-rw-r--r--lib/ohai/plugins/os.rb7
-rw-r--r--lib/ohai/plugins/python.rb14
-rw-r--r--lib/ohai/plugins/windows/filesystem.rb44
-rw-r--r--lib/ohai/plugins/windows/hostname.rb25
-rw-r--r--lib/ohai/plugins/windows/kernel.rb75
-rw-r--r--lib/ohai/plugins/windows/network.rb114
-rw-r--r--lib/ohai/plugins/windows/platform.rb26
-rw-r--r--lib/ohai/system.rb1
14 files changed, 382 insertions, 53 deletions
diff --git a/Rakefile b/Rakefile
index a45efb32..4a3e5136 100644
--- a/Rakefile
+++ b/Rakefile
@@ -24,6 +24,7 @@ spec = Gem::Specification.new do |s|
s.add_dependency "json"
s.add_dependency "extlib"
+ s.add_dependency "systemu"
s.bindir = "bin"
s.executables = %w(ohai)
diff --git a/lib/ohai/mixin/command.rb b/lib/ohai/mixin/command.rb
index 77de69f7..4f909cba 100644
--- a/lib/ohai/mixin/command.rb
+++ b/lib/ohai/mixin/command.rb
@@ -25,6 +25,7 @@ require 'ohai/log'
require 'tmpdir'
require 'fcntl'
require 'etc'
+require 'systemu'
module Ohai
module Mixin
@@ -40,24 +41,7 @@ module Ohai
stdout_string = nil
stderr_string = nil
-
- exec_processing_block = lambda do |pid, stdin, stdout, stderr|
- stdin.close
-
- stdout_string = stdout.gets(nil)
- if stdout_string
- Ohai::Log.debug("---- Begin #{args[:command]} STDOUT ----")
- Ohai::Log.debug(stdout_string.strip)
- Ohai::Log.debug("---- End #{args[:command]} STDOUT ----")
- end
- stderr_string = stderr.gets(nil)
- if stderr_string
- Ohai::Log.debug("---- Begin #{args[:command]} STDERR ----")
- Ohai::Log.debug(stderr_string.strip)
- Ohai::Log.debug("---- End #{args[:command]} STDERR ----")
- end
- end
-
+
args[:cwd] ||= Dir.tmpdir
unless File.directory?(args[:cwd])
raise Ohai::Exception::Exec, "#{args[:cwd]} does not exist or is not a directory"
@@ -68,26 +52,44 @@ module Ohai
if args[:timeout]
begin
Timeout.timeout(args[:timeout]) do
- status = popen4(args[:command], args, &exec_processing_block)
+ status, stdout_string, stderr_string = systemu(args[:command])
end
rescue Exception => e
Ohai::Log.error("#{args[:command_string]} exceeded timeout #{args[:timeout]}")
raise(e)
end
else
- status = popen4(args[:command], args, &exec_processing_block)
+ status, stdout_string, stderr_string = systemu(args[:command])
+ end
+
+ # systemu returns 42 when it hits unexpected errors
+ if status.exitstatus == 42 and stderr_string == ""
+ stderr_string = "Failed to run: #{args[:command]}, assuming command not found"
+ Ohai::Log.debug(stderr_string)
+ end
+
+ if stdout_string
+ Ohai::Log.debug("---- Begin #{args[:command]} STDOUT ----")
+ Ohai::Log.debug(stdout_string.strip)
+ Ohai::Log.debug("---- End #{args[:command]} STDOUT ----")
+ end
+ if stderr_string
+ Ohai::Log.debug("---- Begin #{args[:command]} STDERR ----")
+ Ohai::Log.debug(stderr_string.strip)
+ Ohai::Log.debug("---- End #{args[:command]} STDERR ----")
end
args[:returns] ||= 0
- if status.exitstatus != args[:returns]
- raise Ohai::Exception::Exec, "#{args[:command_string]} returned #{status.exitstatus}, expected #{args[:returns]}"
+ args[:no_status_check] ||= false
+ if status.exitstatus != args[:returns] and not args[:no_status_check]
+ raise Ohai::Exception::Exec, "#{args[:command]} returned #{status.exitstatus}, expected #{args[:returns]}"
else
Ohai::Log.debug("Ran #{args[:command_string]} (#{args[:command]}) returned #{status.exitstatus}")
end
end
return status, stdout_string, stderr_string
end
-
+
module_function :run_command
# This is taken directly from Ara T Howard's Open4 library, and then
@@ -195,4 +197,4 @@ module Ohai
module_function :popen4
end
end
-end \ No newline at end of file
+end
diff --git a/lib/ohai/mixin/string.rb b/lib/ohai/mixin/string.rb
new file mode 100644
index 00000000..169711a2
--- /dev/null
+++ b/lib/ohai/mixin/string.rb
@@ -0,0 +1,29 @@
+#
+# Author:: James Gartrell (<jgartrel@gmail.com>)
+# Copyright:: Copyright (c) 2009 Opscode, 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.
+#
+
+class String
+ # Add string function to handle WMI property conversion to json hash keys
+ # Makes an underscored, lowercase form from the expression in the string.
+ # underscore will also change ’::’ to ’/’ to convert namespaces to paths.
+ # This should implement the same functionality as underscore method in
+ # ActiveSupport::CoreExtensions::String::Inflections
+ def wmi_underscore
+ self.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
+ end
+end
diff --git a/lib/ohai/plugins/erlang.rb b/lib/ohai/plugins/erlang.rb
index 6c58589f..23343937 100644
--- a/lib/ohai/plugins/erlang.rb
+++ b/lib/ohai/plugins/erlang.rb
@@ -20,18 +20,18 @@ require_plugin "languages"
output = nil
erlang = Mash.new
-status = popen4("erl +V") do |pid, stdin, stdout, stderr|
- stdin.close
- output = stderr.gets.split if stderr
- options = output[1]
- options.gsub!(/(\(|\))/, '')
- erlang[:version] = output[5]
- erlang[:options] = options.split(',')
- erlang[:emulator] = output[2].gsub!(/(\(|\))/, '')
-end
+status, stdout, stderr = run_command(:no_status_check => true, :command => "erl +V")
if status == 0
- if erlang[:version] and erlang[:options] and erlang[:emulator]
- languages[:erlang] = erlang
+ output = stderr.split
+ if output.length >= 6
+ options = output[1]
+ options.gsub!(/(\(|\))/, '')
+ erlang[:version] = output[5]
+ erlang[:options] = options.split(',')
+ erlang[:emulator] = output[2].gsub!(/(\(|\))/, '')
+ if erlang[:version] and erlang[:options] and erlang[:emulator]
+ languages[:erlang] = erlang
+ end
end
end
diff --git a/lib/ohai/plugins/java.rb b/lib/ohai/plugins/java.rb
index b7cfab1f..a6777e78 100644
--- a/lib/ohai/plugins/java.rb
+++ b/lib/ohai/plugins/java.rb
@@ -19,17 +19,17 @@
require_plugin "languages"
java = Mash.new
-status = popen4("java -version") do |pid, stdin, stdout, stderr|
- stdin.close
- stderr.each do |line|
+
+status, stdout, stderr = run_command(:no_status_check => true, :command => "java -version")
+
+if status == 0
+ stderr.split("\n").each do |line|
case line
when /java version \"([0-9\.\_]+)\"/: java[:version] = $1
when /^(.+Runtime Environment.*) \(build (.+)\)$/: java[:runtime] = { "name" => $1, "build" => $2 }
when /^(.+ Client VM) \(build (.+)\)$/: java[:hotspot] = { "name" => $1, "build" => $2 }
end
end
-end
-if status == 0
languages[:java] = java if java[:version]
end
diff --git a/lib/ohai/plugins/kernel.rb b/lib/ohai/plugins/kernel.rb
index 514b4294..b178751c 100644
--- a/lib/ohai/plugins/kernel.rb
+++ b/lib/ohai/plugins/kernel.rb
@@ -16,9 +16,16 @@
# limitations under the License.
#
+require_plugin 'ruby'
+
kernel Mash.new
-kernel[:name] = from("uname -s")
-kernel[:release] = from("uname -r")
-kernel[:version] = from("uname -v")
-kernel[:machine] = from("uname -m")
-kernel[:modules] = Mash.new
+case languages[:ruby][:host_os]
+when /mswin/
+ require_plugin "windows::kernel"
+else
+ kernel[:name] = from("uname -s")
+ kernel[:release] = from("uname -r")
+ kernel[:version] = from("uname -v")
+ kernel[:machine] = from("uname -m")
+ kernel[:modules] = Mash.new
+end
diff --git a/lib/ohai/plugins/os.rb b/lib/ohai/plugins/os.rb
index 114f75d2..b133062d 100644
--- a/lib/ohai/plugins/os.rb
+++ b/lib/ohai/plugins/os.rb
@@ -26,6 +26,13 @@ when /linux/
os "linux"
when /freebsd(.+)$/
os "freebsd"
+when /mswin/
+ # After long discussion in IRC the "powers that be" have come to a concensus
+ # that there is no other Windows platforms exist that were not based on the
+ # Windows_NT kernel, so we herby decree that "windows" will refer to all
+ # platforms built upon the Windows_NT kernel and have access to win32 or win64
+ # subsystems.
+ os "windows"
else
os languages[:ruby][:host_os]
end
diff --git a/lib/ohai/plugins/python.rb b/lib/ohai/plugins/python.rb
index c2e63745..fbc4fc75 100644
--- a/lib/ohai/plugins/python.rb
+++ b/lib/ohai/plugins/python.rb
@@ -20,16 +20,14 @@ require_plugin "languages"
output = nil
python = Mash.new
-status = popen4("python -c \"import sys; print sys.version\"") do |pid, stdin, stdout, stderr|
- stdin.close
- output_string = stdout.gets
- if output_string
- output = output_string.split
- python[:version] = output[0]
+status, stdout, stderr = run_command(:no_status_check => true, :command => "python -c \"import sys; print sys.version\"")
+
+if status == 0
+ output = stdout.split
+ python[:version] = output[0]
+ if output.length >= 6
python[:builddate] = "%s %s %s %s" % [output[2],output[3],output[4],output[5].gsub!(/\)/,'')]
end
-end
-if status == 0
languages[:python] = python if python[:version] and python[:builddate]
end
diff --git a/lib/ohai/plugins/windows/filesystem.rb b/lib/ohai/plugins/windows/filesystem.rb
new file mode 100644
index 00000000..192bca25
--- /dev/null
+++ b/lib/ohai/plugins/windows/filesystem.rb
@@ -0,0 +1,44 @@
+#
+# Author:: James Gartrell (<jgartrel@gmail.com>)
+# Copyright:: Copyright (c) 2009 Opscode, 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 'ruby-wmi'
+
+fs = Mash.new
+ld_info = Mash.new
+
+# Grab filesystem data from WMI
+# Note: we should really be parsing Win32_Volume and Win32_Mapped drive
+disks = WMI::Win32_LogicalDisk.find(:all)
+disks.each do |disk|
+ filesystem = disk.DeviceID
+ fs[filesystem] = Mash.new
+ ld_info[filesystem] = Mash.new
+ disk.properties_.each do |p|
+ ld_info[filesystem][p.name.wmi_underscore.to_sym] = disk[p.name]
+ end
+ fs[filesystem][:kb_size] = ld_info[filesystem][:size].to_i / 1000
+ fs[filesystem][:kb_available] = ld_info[filesystem][:free_space].to_i / 1000
+ fs[filesystem][:kb_used] = fs[filesystem][:kb_size].to_i - fs[filesystem][:kb_available].to_i
+ fs[filesystem][:percent_used] = fs[filesystem][:kb_used].to_i * 100 / fs[filesystem][:kb_size].to_i
+ fs[filesystem][:mount] = ld_info[filesystem][:name]
+ fs[filesystem][:fs_type] = ld_info[filesystem][:file_system].downcase
+ fs[filesystem][:volume_name] = ld_info[filesystem][:volume_name]
+end
+
+# Set the filesystem data
+filesystem fs
diff --git a/lib/ohai/plugins/windows/hostname.rb b/lib/ohai/plugins/windows/hostname.rb
new file mode 100644
index 00000000..f68560b4
--- /dev/null
+++ b/lib/ohai/plugins/windows/hostname.rb
@@ -0,0 +1,25 @@
+#
+# Author:: James Gartrell (<jgartrel@gmail.com>)
+# Copyright:: Copyright (c) 2009 Opscode, 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 'ruby-wmi'
+require 'socket'
+
+host = WMI::Win32_ComputerSystem.find(:first)
+hostname "#{host.Name}"
+#hostname "#{Socket.gethostname}"
+fqdn "#{Socket.gethostbyname(Socket.gethostname).first}"
diff --git a/lib/ohai/plugins/windows/kernel.rb b/lib/ohai/plugins/windows/kernel.rb
new file mode 100644
index 00000000..2f487847
--- /dev/null
+++ b/lib/ohai/plugins/windows/kernel.rb
@@ -0,0 +1,75 @@
+#
+# Author:: James Gartrell (<jgartrel@gmail.com>)
+# Copyright:: Copyright (c) 2009 Opscode, 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 'ruby-wmi'
+
+def machine_lookup(sys_type)
+ return "i386" if sys_type.eql?("X86-based PC")
+ return "x86_64" if sys_type.eql?("x64-based PC")
+ sys_type
+end
+
+def os_lookup(sys_type)
+ return "Unknown" if sys_type.to_s.eql?("0")
+ return "Other" if sys_type.to_s.eql?("1")
+ return "MSDOS" if sys_type.to_s.eql?("14")
+ return "WIN3x" if sys_type.to_s.eql?("15")
+ return "WIN95" if sys_type.to_s.eql?("16")
+ return "WIN98" if sys_type.to_s.eql?("17")
+ return "WINNT" if sys_type.to_s.eql?("18")
+ return "WINCE" if sys_type.to_s.eql?("19")
+ return nil
+end
+
+host = WMI::Win32_OperatingSystem.find(:first)
+kernel[:os_info] = Mash.new
+host.properties_.each do |p|
+ kernel[:os_info][p.name.wmi_underscore.to_sym] = host[p.name]
+end
+
+kernel[:name] = "#{kernel[:os_info][:caption]}"
+kernel[:release] = "#{kernel[:os_info][:version]}"
+kernel[:version] = "#{kernel[:os_info][:version]} #{kernel[:os_info][:csd_version]} Build #{kernel[:os_info][:build_number]}"
+kernel[:os] = os_lookup(kernel[:os_info][:os_type]) || languages[:ruby][:host_os]
+
+host = WMI::Win32_ComputerSystem.find(:first)
+kernel[:cs_info] = Mash.new
+host.properties_.each do |p|
+ kernel[:cs_info][p.name.wmi_underscore.to_sym] = host[p.name]
+end
+
+kernel[:machine] = machine_lookup("#{kernel[:cs_info][:system_type]}")
+
+kext = Mash.new
+pnp_drivers = Mash.new
+
+drivers = WMI::Win32_PnPSignedDriver.find(:all)
+drivers.each do |driver|
+ pnp_drivers[driver.DeviceID] = Mash.new
+ driver.properties_.each do |p|
+ pnp_drivers[driver.DeviceID][p.name.wmi_underscore.to_sym] = driver[p.name]
+ end
+ if driver.DeviceName
+ kext[driver.DeviceName] = pnp_drivers[driver.DeviceID]
+ kext[driver.DeviceName][:version] = pnp_drivers[driver.DeviceID][:driver_version]
+ kext[driver.DeviceName][:date] = pnp_drivers[driver.DeviceID][:driver_date] ? pnp_drivers[driver.DeviceID][:driver_date].to_s[0..7] : nil
+ end
+end
+
+kernel[:pnp_drivers] = pnp_drivers
+kernel[:modules] = kext
diff --git a/lib/ohai/plugins/windows/network.rb b/lib/ohai/plugins/windows/network.rb
new file mode 100644
index 00000000..e1e815c5
--- /dev/null
+++ b/lib/ohai/plugins/windows/network.rb
@@ -0,0 +1,114 @@
+#
+# Author:: James Gartrell (<jgartrel@gmail.com>)
+# Copyright:: Copyright (c) 2008 Opscode, 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 'ruby-wmi'
+
+def encaps_lookup(encap)
+ return "Ethernet" if encap.eql?("Ethernet 802.3")
+ encap
+end
+
+def derive_bcast(ipaddr, ipmask, zero_bcast = false)
+ begin
+ ipaddr_int = ipaddr.split(".").collect{ |x| x.to_i}.pack("C4").unpack("N").first
+ ipmask_int = ipmask.split(".").collect{ |x| x.to_i}.pack("C4").unpack("N").first
+ if zero_bcast
+ bcast_int = ipaddr_int & ipmask_int
+ else
+ bcast_int = ipaddr_int | 2 ** 32 - ipmask_int - 1
+ end
+ bcast = [bcast_int].pack("N").unpack("C4").join(".")
+ return bcast
+ rescue
+ return nil
+ end
+end
+
+iface = Mash.new
+iface_config = Mash.new
+iface_instance = Mash.new
+
+adapters = WMI::Win32_NetworkAdapterConfiguration.find(:all)
+adapters.each do |adapter|
+ i = adapter.Index
+ iface_config[i] = Mash.new
+ adapter.properties_.each do |p|
+ iface_config[i][p.name.wmi_underscore.to_sym] = adapter[p.name]
+ end
+end
+
+adapters = WMI::Win32_NetworkAdapter.find(:all)
+adapters.each do |adapter|
+ i = adapter.Index
+ iface_instance[i] = Mash.new
+ adapter.properties_.each do |p|
+ iface_instance[i][p.name.wmi_underscore.to_sym] = adapter[p.name]
+ end
+end
+
+iface_instance.keys.each do |i|
+ if iface_config[i][:ip_enabled] and iface_instance[i][:net_connection_id] and iface_instance[i][:interface_index]
+ cint = sprintf("0x%X", iface_instance[i][:interface_index])
+ iface[cint] = Mash.new
+ iface[cint][:configuration] = iface_config[i]
+ iface[cint][:instance] = iface_instance[i]
+
+ iface[cint][:counters] = Mash.new
+ iface[cint][:addresses] = Mash.new
+ iface[cint][:configuration][:ip_address].each_index do |i|
+ begin
+ if iface[cint][:configuration][:ip_address][i] =~ /./
+ iface[cint][:addresses][iface[cint][:configuration][:ip_address][i]] = {
+ "family" => "inet",
+ "netmask" => iface[cint][:configuration][:ip_subnet][i],
+ "broadcast" => derive_bcast( iface[cint][:configuration][:ip_address][i],
+ iface[cint][:configuration][:ip_subnet][i],
+ iface[cint][:configuration][:ip_use_zero_broadcast]
+ )
+ }
+ end
+ rescue
+ end
+ end
+ iface[cint][:configuration][:mac_address].each do |mac_addr|
+ iface[cint][:addresses][mac_addr] = {
+ "family" => "lladdr"
+ }
+ end
+ iface[cint][:mtu] = iface[cint][:configuration][:mtu]
+ iface[cint][:type] = iface[cint][:instance][:adapter_type]
+ iface[cint][:arp] = {}
+ iface[cint][:encapsulation] = encaps_lookup(iface[cint][:instance][:adapter_type])
+ end
+end
+
+cint=nil
+from("arp /a").split("\n").each do |line|
+ if line == ""
+ cint = nil
+ end
+ if line =~ /^Interface:\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+[-]+\s+(0x\d+)/
+ cint = $2
+ end
+ next unless iface[cint]
+ if line =~ /^\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([a-fA-F0-9\:-]+)/
+ iface[cint][:arp][$1] = $2.gsub("-",":").downcase
+ end
+end
+
+network["interfaces"] = iface
diff --git a/lib/ohai/plugins/windows/platform.rb b/lib/ohai/plugins/windows/platform.rb
new file mode 100644
index 00000000..c40675aa
--- /dev/null
+++ b/lib/ohai/plugins/windows/platform.rb
@@ -0,0 +1,26 @@
+#
+# Author:: James Gartrell (<jgartrel@gmail.com>)
+# Copyright:: Copyright (c) 2009 Opscode, 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.
+#
+
+# After long discussion in IRC the "powers that be" have come to a concensus
+# that there is no other Windows platforms exist that were not based on the
+# Windows_NT kernel, so we herby decree that "windows" will refer to all
+# platforms built upon the Windows_NT kernel and have access to win32 or win64
+# subsystems.
+platform os
+platform_version kernel['release']
+
diff --git a/lib/ohai/system.rb b/lib/ohai/system.rb
index ed80c59d..90adedd7 100644
--- a/lib/ohai/system.rb
+++ b/lib/ohai/system.rb
@@ -21,6 +21,7 @@ require 'extlib'
require 'ohai/log'
require 'ohai/mixin/from_file'
require 'ohai/mixin/command'
+require 'ohai/mixin/string'
require 'json'
module Ohai