# frozen_string_literal: true # # Author:: Tim Smith # Author:: Joshua Colson # Copyright:: Copyright (c) Chef Software Inc. # Copyright:: 2019 Joshua Colson # 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(:Virtualbox) do depends "virtualization" provides "virtualbox" # query virtualbox for each configured vm, as well as # each guest's individual configuration settings def vboxmanage_list_vms vms = Mash.new so_cmd = "VBoxManage list --sorted vms" logger.trace(so_cmd) so = shell_out(so_cmd) if so.exitstatus == 0 # parse the output so.stdout.lines.each do |line| case line when /^"(\S*)" \{(\S*)\}$/ name = Regexp.last_match(1) uuid = Regexp.last_match(2) vms[name] = vboxmanage_vminfo(uuid) end end end vms rescue Ohai::Exceptions::Exec logger.trace("Plugin VboxHost: Could not run 'VBoxManage list --sorted vms'. Skipping data") end # query the vminfo for particular guest instance, normalizing # the fields so that they're not enclosed in double-quotes (") def vboxmanage_vminfo(machine_id) vm = Mash.new so_cmd = "VBoxManage showvminfo #{machine_id} --machinereadable" logger.trace(so_cmd) so = shell_out(so_cmd) if so.exitstatus == 0 so.stdout.lines.each do |line| line.chomp! left, right = line.split("=") # remove enclosing quotes, if needed key = left.delete_prefix('"').delete_suffix('"') # skip the name attribute since that is the parent key next if key == "name" vm[key.downcase] = right.delete_prefix('"').delete_suffix('"') end end vm rescue Ohai::Exceptions::Exec logger.trace("Plugin VboxHost: Could not run '#{so_cmd}'. Skipping data") end # query virtualbox for a list of #{query_type} items # these queries return a result set that is delimited by # multiple successive newlines, with each block containing # key/value pairs delimited by a colon (:) and column aligned # # the keys of each k/v pair are normalized to lowercase def vboxmanage_list_blocks(query_type, name_key) # ignore unrecognized query type supported_queries = %w{ bridgedifs dhcpservers dvds hdds hostdvds hostfloppies hostonlyifs natnets } return nil unless supported_queries.include? query_type results = Mash.new so_cmd = "VBoxManage list --sorted #{query_type}" logger.trace(so_cmd) so = shell_out(so_cmd) # raise an exception if the command fails # so.error! if so.exitstatus == 0 # break the result into paragraph blocks, on successive newlines so.stdout.each_line("") do |blk| # remove the multiple newlines of each record blk.chomp!.chomp! # initialize a blank record hash record = Mash.new # parse the record block into key/value pairs blk.each_line do |line| next unless line.include? ":" # split the line into key/value pair key, right = line.split(":", 2) # strip the leading/trailing whitespace if the value is not nil value = right.nil? ? "" : right.strip record[key.downcase] = value end # insert the record into the list of results if record.key? name_key.downcase name = record.delete(name_key.downcase) results[name] = record end end end results rescue Ohai::Exceptions::Exec logger.trace("Plugin VboxHost: Could not run '#{so_cmd}'. Skipping data") end collect_data(:windows, :linux, :solaris2, :darwin) do case virtualization.dig("systems", "vbox") when "guest" logger.trace("Plugin Virtualbox: Node detected as vbox guest. Collecting guest data.") begin so = shell_out("VBoxControl guestproperty enumerate") if so.exitstatus == 0 virtualbox Mash.new virtualbox[:host] = Mash.new virtualbox[:guest] = Mash.new so.stdout.lines.each do |line| case line when /LanguageID, value: (\S*),/ virtualbox[:host][:language] = Regexp.last_match(1) when /VBoxVer, value: (\S*),/ virtualbox[:host][:version] = Regexp.last_match(1) when /VBoxRev, value: (\S*),/ virtualbox[:host][:revision] = Regexp.last_match(1) when %r{GuestAdd/VersionExt, value: (\S*),} virtualbox[:guest][:guest_additions_version] = Regexp.last_match(1) when %r{GuestAdd/Revision, value: (\S*),} virtualbox[:guest][:guest_additions_revision] = Regexp.last_match(1) end end end rescue Ohai::Exceptions::Exec logger.trace('Plugin Virtualbox: Could not execute "VBoxControl guestproperty enumerate". Skipping data collection.') end when "host" logger.trace("Plugin Virtualbox: Node detected as vbox host. Collecting host data.") virtualbox Mash.new begin # get a list of virtualbox guest vms virtualbox["guests"] = vboxmanage_list_vms # get a list of virtualbox virtual hard disk drives virtualbox["hdds"] = vboxmanage_list_blocks("hdds", "Location") # get a list of virtualbox virtual dvd drives virtualbox["dvds"] = vboxmanage_list_blocks("dvds", "Location") # get a list of virtualbox host dvd drives virtualbox["hostdvds"] = vboxmanage_list_blocks("hostdvds", "Name") # get a list of virtualbox host floppy drives virtualbox["hostfloppies"] = vboxmanage_list_blocks("hostfloppies", "Name") # get a list of virtualbox hostonly network interfaces virtualbox["hostonlyifs"] = vboxmanage_list_blocks("hostonlyifs", "Name") # get a list of virtualbox bridged network interfaces virtualbox["bridgedifs"] = vboxmanage_list_blocks("bridgedifs", "Name") # get a list of virtualbox dhcp servers virtualbox["dhcpservers"] = vboxmanage_list_blocks("dhcpservers", "NetworkName") # get a list of virtualbox nat networks virtualbox["natnets"] = vboxmanage_list_blocks("natnets", "NetworkName") rescue Ohai::Exceptions::Exec logger.trace("Plugin VboxHost: Could not collect data for VirtualBox host. Skipping data") end else logger.trace("Plugin Virtualbox: Not on a Virtualbox host or guest. Skipping plugin.") end end end