mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
169 lines
6.6 KiB
PHP
169 lines
6.6 KiB
PHP
<?php
|
|
/*
|
|
* VminfoLibvirt.php
|
|
*
|
|
* -Description-
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* @package LibreNMS
|
|
* @link http://librenms.org
|
|
* @copyright 2023 Tony Murray
|
|
* @author Tony Murray <murraytony@gmail.com>
|
|
*/
|
|
|
|
namespace LibreNMS\OS\Traits;
|
|
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Str;
|
|
use LibreNMS\Config;
|
|
use LibreNMS\Enum\PowerState;
|
|
|
|
trait VminfoLibvirt
|
|
{
|
|
public function discoverVminfo(): Collection
|
|
{
|
|
echo 'LibVirt VM: ';
|
|
|
|
if (! Config::get('enable_libvirt')) {
|
|
echo 'not configured';
|
|
|
|
return new Collection;
|
|
}
|
|
|
|
$vms = new Collection;
|
|
|
|
$ssh_ok = 0;
|
|
|
|
$userHostname = $this->getDevice()->hostname;
|
|
if (Config::has('libvirt_username')) {
|
|
$userHostname = Config::get('libvirt_username') . '@' . $userHostname;
|
|
}
|
|
|
|
foreach (Config::get('libvirt_protocols') as $method) {
|
|
if (Str::contains($method, 'qemu')) {
|
|
$uri = $method . '://' . $userHostname . '/system';
|
|
} else {
|
|
$uri = $method . '://' . $userHostname;
|
|
}
|
|
|
|
if (Str::contains($method, 'ssh') && ! $ssh_ok) {
|
|
// Check if we are using SSH if we can log in without password - without blocking the discovery
|
|
// Also automatically add the host key so discovery doesn't block on the yes/no question, and run echo so we don't get stuck in a remote shell ;-)
|
|
exec('ssh -o "StrictHostKeyChecking no" -o "PreferredAuthentications publickey" -o "IdentitiesOnly yes" ' . $userHostname . ' echo -e', $out, $ret);
|
|
if ($ret != 255) {
|
|
$ssh_ok = 1;
|
|
}
|
|
}
|
|
|
|
if ($ssh_ok || ! Str::contains($method, 'ssh')) {
|
|
// Fetch virtual machine list
|
|
unset($domlist);
|
|
exec(Config::get('virsh') . ' -rc ' . $uri . ' list', $domlist);
|
|
|
|
foreach ($domlist as $dom) {
|
|
[$dom_id] = explode(' ', trim($dom), 2);
|
|
|
|
if (is_numeric($dom_id)) {
|
|
// Fetch the Virtual Machine information.
|
|
unset($vm_info_array);
|
|
exec(Config::get('virsh') . ' -rc ' . $uri . ' dumpxml ' . $dom_id, $vm_info_array);
|
|
|
|
// Example xml:
|
|
// <domain type='kvm' id='3'>
|
|
// <name>moo.example.com</name>
|
|
// <uuid>48cf6378-6fd5-4610-0611-63dd4b31cfd6</uuid>
|
|
// <memory>1048576</memory>
|
|
// <currentMemory>1048576</currentMemory>
|
|
// <vcpu>8</vcpu>
|
|
// <os>
|
|
// <type arch='x86_64' machine='pc-0.12'>hvm</type>
|
|
// <boot dev='hd'/>
|
|
// </os>
|
|
// <features>
|
|
// <acpi/>
|
|
// (...)
|
|
// See spec at https://libvirt.org/formatdomain.html
|
|
|
|
// Convert array to string
|
|
$vm_info_xml = implode($vm_info_array);
|
|
|
|
$xml = simplexml_load_string('<?xml version="1.0"?> ' . $vm_info_xml);
|
|
Log::debug($xml);
|
|
|
|
// libvirt does not supply this
|
|
exec(Config::get('virsh') . ' -rc ' . $uri . ' domstate ' . $dom_id, $vm_state);
|
|
$vmwVmState = PowerState::STATES[strtolower($vm_state[0])] ?? PowerState::UNKNOWN;
|
|
|
|
$vmwVmMemSize = $xml->memory;
|
|
// Convert memory size to MiB
|
|
switch ($xml->memory['unit']) {
|
|
case 'T':
|
|
case 'TiB':
|
|
$vmwVmMemSize = $xml->memory * 1048576;
|
|
break;
|
|
case 'TB':
|
|
$vmwVmMemSize = $xml->memory * 1000000;
|
|
break;
|
|
case 'G':
|
|
case 'GiB':
|
|
$vmwVmMemSize = $xml->memory * 1024;
|
|
break;
|
|
case 'GB':
|
|
$vmwVmMemSize = $xml->memory * 1000;
|
|
break;
|
|
case 'M':
|
|
case 'MiB':
|
|
break;
|
|
case 'MB':
|
|
$vmwVmMemSize = $xml->memory * 1000000 / 1048576;
|
|
break;
|
|
case 'KB':
|
|
$vmwVmMemSize = $xml->memory / 1000;
|
|
break;
|
|
case 'b':
|
|
case 'bytes':
|
|
$vmwVmMemSize = $xml->memory / 1048576;
|
|
break;
|
|
default:
|
|
// KiB or k or no value
|
|
$vmwVmMemSize = $xml->memory / 1024;
|
|
break;
|
|
}
|
|
|
|
// Save the discovered Virtual Machine.
|
|
$vms->push(new \App\Models\Vminfo([
|
|
'vmtype' => 'libvirt',
|
|
'vmwVmVMID' => $dom_id,
|
|
'vmwVmState' => $vmwVmState,
|
|
'vmwVmGuestOS' => '',
|
|
'vmwVmDisplayName' => $xml->name,
|
|
'vmwVmMemSize' => $vmwVmMemSize,
|
|
'vmwVmCpus' => $xml->vcpu['current'] ?? $xml->vcpu,
|
|
]));
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we found VMs, don't cycle the other protocols anymore.
|
|
if ($vms->isNotEmpty()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $vms;
|
|
}
|
|
}
|