summaryrefslogtreecommitdiff
path: root/lib/ohai/plugins/vbox_host.rb
blob: f1657dd20d8e3d7d06ac2e1f0d84b4dbabc0173a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# Author:: "Joshua Colson" <joshua.colson@gmail.com>
# 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(:VboxHost) do
  depends "virtualization"
  provides "vbox"

  # determine if this host is configured with virtualbox or not
  # the determination is ultimately controlled by the "virtualization" plugin
  def vbox_host?
    virtualization.dig("systems", "vbox") == "host"
  end

  # query virtualbox for each configured vm, as well as
  # each guest"s individual configuration settings
  def vboxmanage_list_vms
    vms = Mash.new
    if vbox_host?
      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
    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

    if vbox_host?
      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 =
            case left
            when /^"(.*)"$/
              Regexp.last_match(1)
            else
              left
            end

          # skip the name attribute since that is the parent key
          next if left == "name"

          # remove enclosing quotes, if needed
          value =
            case right
            when /^"(.*)"$/
              Regexp.last_match(1)
            else
              right
            end

          vm[key.downcase] = value
        end
      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 ostypes
    }
    return nil unless supported_queries.include? query_type
    results = Mash.new

    if vbox_host?
      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
    end
    results
  rescue Ohai::Exceptions::Exec
    logger.trace("Plugin VboxHost: Could not run '#{so_cmd}'. Skipping data")
  end

  # collect the data for a virtualization host running VirtualBox
  collect_data(:default) do
    ostypes = "ostypes"
    guests = "guests"
    natnets = "natnets"
    hostonlyifs = "hostonlyifs"
    bridgedifs = "bridgedifs"
    dhcpservers = "dhcpservers"
    hdds = "hdds"
    dvds = "dvds"
    hostdvds = "hostdvds"
    hostfloppies = "hostfloppies"

    if vbox_host?
      vbox Mash.new unless vbox

      # get a list of virtualbox virtual hard disk drives
      vbox[ostypes] = vboxmanage_list_blocks(ostypes, "ID")

      # get a list of virtualbox guest vms
      vbox[guests] = vboxmanage_list_vms

      # get a list of virtualbox virtual hard disk drives
      vbox[hdds] = vboxmanage_list_blocks(hdds, "Location")

      # get a list of virtualbox virtual dvd drives
      vbox[dvds] = vboxmanage_list_blocks(dvds, "Location")

      # get a list of virtualbox host dvd drives
      vbox[hostdvds] = vboxmanage_list_blocks(hostdvds, "Name")

      # get a list of virtualbox host floppy drives
      vbox[hostfloppies] = vboxmanage_list_blocks(hostfloppies, "Name")

      # get a list of virtualbox hostonly network interfaces
      vbox[hostonlyifs] = vboxmanage_list_blocks(hostonlyifs, "Name")

      # get a list of virtualbox bridged network interfaces
      vbox[bridgedifs] = vboxmanage_list_blocks(bridgedifs, "Name")

      # get a list of virtualbox dhcp servers
      vbox[dhcpservers] = vboxmanage_list_blocks(dhcpservers, "NetworkName")

      # get a list of virtualbox nat networks
      vbox[natnets] = vboxmanage_list_blocks(natnets, "NetworkName")
    end
    vbox
  rescue Ohai::Exceptions::Exec
    logger.trace("Plugin VboxHost: Could not collect data for VirtualBox host. Skipping data")
  end
end