Francesco Romani has uploaded a new change for review.
Change subject: vm: remove guest agent channels tunables
......................................................................
vm: remove guest agent channels tunables
We had tunables to disable vm/ga channels
creation from a long time, but it was just on
debug purposes and these settings should never
be used in production.
Moreover, we acttually rely on the channel being
here (see RHBZ#1126887).
Since it is now possible the achive the same results
through hooks, is time to drop these tunables.
Change-Id: I4774441d7bd6dcdbb58e38886eb522851d4af37c
Relates-To: https://bugzilla.redhat.com/1126887
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M client/vdsClient.py
M tests/vmTestsData.py
M vdsm/virt/vm.py
3 files changed, 6 insertions(+), 19 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/45/31245/1
diff --git a/client/vdsClient.py b/client/vdsClient.py
index 2c09b28..ca82519 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -1869,7 +1869,6 @@
# 'want to reserve with the machine'
'o acpiEnable : If present will remove the default '
'-no-acpi switch',
- 'o qgaEnable : use qemu-ga as guest agent',
'o spiceSecureChannels : comma-separated list of '
'spice channel that will be encrypted',
'o spiceMonitors : number of emulated screen heads',
diff --git a/tests/vmTestsData.py b/tests/vmTestsData.py
index 02959fd..0990641 100644
--- a/tests/vmTestsData.py
+++ b/tests/vmTestsData.py
@@ -27,7 +27,6 @@
'acpiEnable': 'true', 'cpuType': 'qemu64',
'smpCoresPerSocket': 1, 'smpThreadsPerCore': 1,
'smp': '1', 'cpuPinning': {}, 'numaTune': {}, 'maxVCpus': '160',
- 'vmchannel': 'true', 'qgaEnable': 'true',
'tabletEnable': False,
'displayNetwork': 'mydisp', 'custom': {},
'guestNumaNodes': []},
@@ -95,7 +94,6 @@
'acpiEnable': 'true', 'cpuType': 'qemu64',
'smpCoresPerSocket': 1, 'smpThreadsPerCore': 1,
'smp': '1', 'cpuPinning': {}, 'numaTune': {}, 'maxVCpus': '160',
- 'vmchannel': 'true', 'qgaEnable': 'true',
'tabletEnable': False,
'displayNetwork': 'mydisp', 'custom': {},
'guestNumaNodes': []},
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 591616d..714b718 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -2689,17 +2689,10 @@
domxml.appendNumaTune()
- if utils.tobool(self.conf.get('vmchannel', 'true')):
- domxml._appendAgentDevice(self._guestSocketFile.decode('utf-8'),
- _VMCHANNEL_DEVICE_NAME)
- else:
- self.log.warning('detected disabled vmchannel.'
- ' This should be done ONLY for debug purposes'
- ' and never in production environments')
- if utils.tobool(self.conf.get('qgaEnable', 'true')):
- domxml._appendAgentDevice(
- self._qemuguestSocketFile.decode('utf-8'),
- _QEMU_GA_DEVICE_NAME)
+ domxml._appendAgentDevice(self._guestSocketFile.decode('utf-8'),
+ _VMCHANNEL_DEVICE_NAME)
+ domxml._appendAgentDevice(self._qemuguestSocketFile.decode('utf-8'),
+ _QEMU_GA_DEVICE_NAME)
domxml.appendInput()
if self.arch == caps.Architecture.PPC64:
@@ -2841,8 +2834,7 @@
# So, run it after you have this info
self._initVmStats()
self.guestAgent = guestagent.GuestAgent(
- self._guestSocketFile, self.cif.channelListener, self.log,
- connect=utils.tobool(self.conf.get('vmchannel', 'true')))
+ self._guestSocketFile, self.cif.channelListener, self.log)
self._guestCpuRunning = self._isDomainRunning()
if self.lastStatus not in (vmstatus.MIGRATION_DESTINATION,
@@ -4010,9 +4002,7 @@
snap.appendChild(_memorySnapshot(memoryVolPath))
else:
snapFlags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY
-
- if utils.tobool(self.conf.get('qgaEnable', 'true')):
- snapFlags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE
+ snapFlags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE
snapxml = snap.toprettyxml()
self.log.debug(snapxml)
--
To view, visit http://gerrit.ovirt.org/31245
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4774441d7bd6dcdbb58e38886eb522851d4af37c
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Francesco Romani has uploaded a new change for review.
Change subject: vm: make new timekeeping revertable
......................................................................
vm: make new timekeeping revertable
The commit Icb0752e54a4cb9ff609b8ddfaf5c8fe2ed5b9e72
implemented the new timekeeping options recommended
by QEMU developers.
In order to maximize the backward compatibility and
to deal with possible regression with old guests,
this patch makes the new timekeeping settings revertable
by exposing a new configuration variable.
The default is enabled because those settings, being
recommended, are supposed to be safe.
Change-Id: I471be44454dcae6e73c46a473eb1eee19a5275ab
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M lib/vdsm/config.py.in
M vdsm/vm.py
2 files changed, 8 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/43/24443/1
diff --git a/lib/vdsm/config.py.in b/lib/vdsm/config.py.in
index 01590a1..075face 100644
--- a/lib/vdsm/config.py.in
+++ b/lib/vdsm/config.py.in
@@ -192,6 +192,9 @@
('transient_disks_repository', '@VDSMLIBDIR@/transient',
'Local path to the transient disks repository.'),
+
+ ('new_timekeeping_enable', 'true',
+ 'Enable the new recomended QEMU time keeping settings'),
]),
# Section: [ksm]
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 9371049..d3baca8 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -970,10 +970,12 @@
m = XMLElement('clock', offset='variable',
adjustment=str(self.conf.get('timeOffset', 0)))
m.appendChildWithArgs('timer', name='rtc', tickpolicy='catchup')
- m.appendChildWithArgs('timer', name='pit', tickpolicy='delay')
- if self.arch == caps.Architecture.X86_64:
- m.appendChildWithArgs('timer', name='hpet', present='no')
+ if config.getboolean('vars', 'new_timekeeping_enable'):
+ m.appendChildWithArgs('timer', name='pit', tickpolicy='delay')
+
+ if self.arch == caps.Architecture.X86_64:
+ m.appendChildWithArgs('timer', name='hpet', present='no')
self.dom.appendChild(m)
--
To view, visit http://gerrit.ovirt.org/24443
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I471be44454dcae6e73c46a473eb1eee19a5275ab
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: virt: Add a function to execute a qemu monitor command
......................................................................
virt: Add a function to execute a qemu monitor command
Sometimes it is necessary to execute a monitor command directly (eg. if
libvirt does not yet support a certain qemu feature). Libvirt will mark
the VM as 'tainted' once this is done for the first time. The reason is
that making modifications to a VM using this facility could cause a
split-brain situation. It is generally harmless to execute monitor
commands which act in a read-only fashion. This function is also useful
as a utility for developers who are working on new features.
Change-Id: I3e9e07ba0c236c0938b129ae90af825f18f0e644
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/virt/vm.py
1 file changed, 11 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/50/27950/1
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 9cc9958..de27a53 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -30,9 +30,11 @@
import threading
import time
import xml.dom.minidom
+import json
# 3rd party libs imports
import libvirt
+import libvirt_qemu
# vdsm imports
from vdsm import constants
@@ -4948,6 +4950,15 @@
if 'tlsPort' in dev:
self.conf['displaySecurePort'] = dev['tlsPort']
+ def _internalQMPMonitorCommand(self, cmdDict):
+ """
+ Execute a qemu monitor command directly.
+ WARNING: This will cause libvirt to mark the VM as tainted.
+ """
+ jsonCmd = json.dumps(cmdDict)
+ ret = libvirt_qemu.qemuMonitorCommand(self._dom, jsonCmd, 0)
+ return json.loads(ret)
+
def _getNetworkIp(network):
try:
--
To view, visit http://gerrit.ovirt.org/27950
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3e9e07ba0c236c0938b129ae90af825f18f0e644
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Xavi Francisco has uploaded a new change for review.
Change subject: storage: ignore missing pv metadata
......................................................................
storage: ignore missing pv metadata
Ignore missing metadata when trying to parse PV information from a
problematic LVM device.
When vdsm tries to read metadata from a LVM physical volume and
there's an error, the lvm command exits normally but no pv metadata
is retrieved and a message is printed in stderr. When this happens the
method getPV() in LVM returns None. This has to be checked whenever the
PV metadata is needed to avoid throwing an exception.
Change-Id: I9932b044c8b439dc8b1f09191a5d89f4bc44c38a
Bug-Url: https://bugzilla.redhat.com/1048696
Signed-off-by: Xavi Francisco <xfrancis(a)redhat.com>
---
M vdsm/storage/blockSD.py
1 file changed, 4 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/42/27442/1
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index 377b132..c41e737 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -668,6 +668,10 @@
continue
pv = lvm.getPV(dev)
+ if not pv:
+ cls.log.warning("Could not get metadata from the device: %s",
+ dev)
+ continue
pvInfo = {}
pvInfo["guid"] = os.path.basename(pv.name)
pvInfo["uuid"] = pv.uuid
--
To view, visit http://gerrit.ovirt.org/27442
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9932b044c8b439dc8b1f09191a5d89f4bc44c38a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Xavi Francisco <xfrancis(a)redhat.com>
Vinzenz Feenstra has uploaded a new change for review.
Change subject: Query interface for all VM fields
......................................................................
Query interface for all VM fields
Change-Id: Iddb4657d738ca0406950d07b84a7c85721e80b78
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1083070
Signed-off-by: Vinzenz Feenstra <vfeenstr(a)redhat.com>
---
A lib/vdsm/trackable.py
M vdsm/API.py
M vdsm/rpc/vdsmapi-schema.json
M vdsm/virt/vm.py
4 files changed, 511 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/19/28819/1
diff --git a/lib/vdsm/trackable.py b/lib/vdsm/trackable.py
new file mode 100644
index 0000000..7455025
--- /dev/null
+++ b/lib/vdsm/trackable.py
@@ -0,0 +1,223 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+"""
+ Implementation for Trackable, a wrapper for objects whose values should be
+ trackable for changes
+"""
+
+import collections
+import threading
+
+
+class ChangeCounter(object):
+ def __init__(self):
+ self._counter_lock = threading.Lock()
+ self._current = 0
+
+ def next(self):
+ with self._counter_lock:
+ self._current += 1
+ return self._current
+
+
+_counter = ChangeCounter()
+
+
+class Trackable(object):
+ """
+ Trackable implements common functionality of TrackableMapping and
+ TrackableSequence and it is not required to be used.
+ """
+ def __init__(self):
+ super(Trackable, self).__init__()
+ self._last_changed = _counter.next()
+ self._item_last_changed = {}
+ self._tracked = None
+ self._watcher = None
+ self._track_depth = 0
+
+ def _set_item(self, key, value):
+ needs_update = True
+ if key in self._tracked:
+ old = self._tracked[key]
+ if isinstance(old, Trackable):
+ old._update(value)
+ # if an item is updated through _update it does not need to
+ # we are not propagating the update, this would bubble up on
+ # it's own
+ needs_update = False
+ elif old == value:
+ # Not updated, no change required
+ needs_update = False
+ else:
+ self._tracked.__setitem__(key, _wrap(value, self,
+ self._track_depth))
+ else:
+ self._tracked.__setitem__(key, _wrap(value, self,
+ self._track_depth))
+ if needs_update:
+ self._on_item_changed(key)
+
+ def _on_item_removed(self, key):
+ changed = _counter.next()
+ self._last_changed = changed
+ if self._watcher:
+ self._on_subitem_changed(changed)
+ del self._item_last_changed[key]
+
+ def _on_item_changed(self, key):
+ changed = _counter.next()
+ self._last_changed = changed
+ if self._watcher:
+ self._on_subitem_changed(changed)
+ self._item_last_changed[key] = changed
+
+ def _on_subitem_changed(self, changed):
+ self._last_changed = changed
+ if self._watcher:
+ self._watcher._on_subitem_changed(changed)
+
+ def changed(self, since, key=None):
+ if not key:
+ return self._last_changed > since
+ if isinstance(self._tracked.get(key, None), Trackable):
+ return self._tracked[key].changed(since=since)
+ return self._item_last_changed[key] > since
+
+ def last_changed(self):
+ return self._last_changed
+
+
+def _wrap(v, watcher, track_depth):
+ if track_depth == 0 or isinstance(v, Trackable):
+
+ return v
+ elif isinstance(v, collections.MutableSequence):
+ return TrackableSequence(tracked=v, _watcher=watcher,
+ track_depth=track_depth - 1)
+ elif isinstance(v, collections.MutableMapping):
+ return TrackableMapping(tracked=v, _watcher=watcher,
+ track_depth=track_depth - 1)
+ return v
+
+
+class TrackableSequence(collections.MutableSequence, Trackable):
+ """
+ TrackableSequence implements a mutable sequence interface to
+ track changes to the elements in the list.
+ """
+ def __init__(self, tracked=None, track_depth=0, _watcher=None):
+ super(TrackableSequence, self).__init__()
+ self._tracked = tracked.__class__() if tracked else []
+ self._track_depth = track_depth
+ self._watcher = _watcher
+ if tracked:
+ for elem in tracked:
+ self.append(elem)
+
+ def insert(self, index, value):
+ self._tracked.insert(index, _wrap(value, self, self._track_depth))
+ self._on_item_changed(index)
+
+ def _update(self, value):
+ # lists when different need a full update
+ if self._tracked != value:
+ self._item_last_changed = {}
+ self._tracked = self._tracked.__class__()
+ for elem in value:
+ self.append(elem)
+
+ def __setitem__(self, key, value):
+ self._set_item(key, value)
+
+ def __getitem__(self, key):
+ return self._tracked.__getitem__(key)
+
+ def __delitem__(self, idx):
+ self._tracked.__delitem__(idx)
+ if not isinstance(self._tracked, Trackable):
+ self._on_item_removed(idx)
+
+ def __len__(self):
+ return self._tracked.__len__()
+
+ def __iter__(self):
+ return self._tracked.__iter__()
+
+ def __hash__(self):
+ return self._tracked.__hash__()
+
+
+class TrackableMapping(Trackable, collections.MutableMapping):
+ """
+ TrackableMapping implements a mutable mapping interface to track
+ changes in the keys/values in a mapping and acts like a proxy thereof
+ """
+ def __init__(self, tracked=None, track_depth=0, _watcher=None):
+ """
+ :param tracked: The object which should be tracked usually a dict
+ :param track_depth: The depth the tracking should be applied
+ the default value is 0 which means only the current
+ objects keys are tracked.
+ :return:
+ """
+ super(TrackableMapping, self).__init__()
+ self._tracked = tracked.__class__() if tracked else {}
+ self._track_depth = track_depth
+ self._watcher = _watcher
+ if tracked:
+ for k, v in tracked.iteritems():
+ self[k] = v
+
+ def update(self, value, filter_if=None):
+ for k in value.keys():
+ if filter and filter(k):
+ continue
+ self[k] = value[k]
+
+ def _update(self, value):
+ for k in self._tracked.keys():
+ if k not in value:
+ del self[k]
+ elif self._tracked[k] != value[k]:
+ self[k] = value[k]
+ for k in value.keys():
+ if k not in self._tracked:
+ self[k] = value[k]
+
+ def __setitem__(self, key, value):
+ self._set_item(key, value)
+
+ def __getitem__(self, key):
+ return self._tracked.__getitem__(key)
+
+ def __delitem__(self, key):
+ self._tracked.__delitem__(key)
+ if not isinstance(self._tracked, Trackable):
+ self._on_item_removed(key)
+
+ def __len__(self):
+ return self._tracked.__len__()
+
+ def __iter__(self):
+ return self._tracked.__iter__()
+
+ def __hash__(self):
+ return self._tracked.__hash__()
\ No newline at end of file
diff --git a/vdsm/API.py b/vdsm/API.py
index ff2627e..5464d5f 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -353,6 +353,20 @@
return errCode['noVM']
return v.migrateStatus()
+ def query(self, fields=None, changedSince=-1, runHooks=True):
+ v = self._cif.vmContainer.get(self._UUID)
+ if not v:
+ return errCode['noVM']
+
+ if runHooks:
+ hooks.before_get_vm_stats()
+ stats = v.query(fields=fields, changedSince=changedSince).copy()
+ stats['vmId'] = self._UUID
+ if runHooks:
+ stats = hooks.after_get_vm_stats([stats])[0]
+ return {'status': doneCode, 'dataList': [stats]}
+
+
def getStats(self, runHooks=True):
"""
Obtain statistics of the specified VM
@@ -1194,6 +1208,21 @@
self.log.error("failed to retrieve hardware info", exc_info=True)
return errCode['hwInfoErr']
+ def queryVms(self, vmIDs=None, fields=None, changedSince=-1):
+ hooks.before_get_all_vm_stats()
+ vms = self.getVMList()
+ statsList = []
+ for s in vms['vmList']:
+ if vmIDs and s['vmId'] not in vmIDs:
+ continue
+ response = VM(s['vmId']).query(fields=fields,
+ changedSince=changedSince,
+ runHooks=False)
+ if response:
+ statsList.append(response['dataList'][0])
+ statsList = hooks.after_get_all_vm_stats(statsList)
+ return {'status': doneCode, 'dataList': statsList}
+
def getAllVmStats(self):
"""
Get statistics of all running VMs.
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index af563c0..dc475de 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -3190,6 +3190,248 @@
{'type': 'VmShortStatus',
'data': {'vmId': 'UUID', 'status': 'VmStatus'}}
+
+##
+# @VmData:
+#
+# All available queryable data fields of a VM instance.
+#
+# @acpiEnable: #optional Indicates if ACPI is enabled inside the
+# VM
+#
+# @appsList: #optional A list of installed applications with
+# their versions
+#
+# @balloonInfo: #optional Guest memory balloon information
+#
+# @boot: #optional An alias for the type of device used to
+# boot the VM
+#
+# @cdrom: #optional The path to an ISO image used in the VM's
+# CD-ROM device
+#
+# @clientIp: #optional The IP address of the client connected to
+# the display
+#
+# @copyPasteEnable: #optional Specify if copy and paste is enabled.
+# Currently relevant for @qxl devices only.
+#
+# @cpuShares: #optional The host scheduling priority (relative to
+# other VMs). In case both cpuShares and nice are
+# present, cpuShares will be used.
+#
+# @cpuSys: #optional Ratio of CPU time spent by qemu on other
+# than guest time
+#
+# @cpuType: #optional The type of CPU being emulated
+# special values 'hostPassthrough' and 'hostModel'
+# are reserved for host-passthrough and host-mode cpu
+# mode
+#
+# @cpuUser: #optional Ratio of CPU time spent by the guest VM
+#
+# @custom: #optional A dictionary of custom, free-form
+# properties
+#
+# @devices: #optional An array of VM devices present
+#
+# @disks: #optional Disk bandwidth/utilization statistics
+#
+# @disksUsage: #optional Info about mounted filesystems as
+# reported by the agent
+#
+# @display: #optional The type of display
+#
+# @displayInfo: #optional Display and graphics device informations.
+#
+# @displayIp: #optional The IP address to use for accessing the
+# VM display
+#
+# @displayPort: #optional The port in use for unencrypted display
+# data
+#
+# @displaySecurePort: #optional The port in use for encrypted display
+# data
+#
+# @displayType: #optional The type of display in use
+#
+# @elapsedTime: #optional The number of seconds that the VM has
+# been running
+#
+# @emulatedMachine: #optional The machine specification being emulated
+#
+# @exitCode: #optional The exit code f the VM process has ended
+#
+# @exitMessage: #optional Explains the reason that the VM process
+# has exited
+#
+# @guestCPUCount: #optional The number of CPU cores are visible as
+# online on the guest OS. This value is -1 if not
+# supported to report
+#
+# @guestFQDN: #optional Fully qualified domain name of the guest
+# OS. (Reported by the guest agent)
+#
+# @guestIPs: #optional A space separated string of assigned IPv4
+# addresses
+#
+# @keyboardLayout: #optional The keyboard layout string (eg. 'en-us')
+#
+# @kvmEnable: #optional Indicates if KVM hardware acceleration is
+# enabled
+#
+# @maxVCpus: #optional Maximum number of CPU available for the
+# guest. It is the upper boundry for hot plug CPU
+# action
+#
+# @memGuaranteedSize: #optional The amount of memory guaranteed to the VM
+# in MB
+#
+# @memSize: #optional The amount of memory assigned to the VM
+# in MB
+#
+# @memUsage: #optional The percent of memory in use by the guest
+#
+# @memoryStats: #optional Memory statistics as reported by the
+# guest agent
+#
+# @migrationProgress: #optional Indicates the percentage progress of a
+# Migration, when there is one active.
+#
+# @monitorResponse: #optional Indicates if the qemu monitor is
+# responsive
+#
+# @netIfaces: #optional Network device address info as reported
+# by the agent
+#
+# @network: #optional Network bandwidth/utilization statistics
+#
+# @nicModel: #optional A comma-separated list of NIC models in
+# use by the VM
+#
+# @nice: #optional The host scheduling priority
+#
+# @pauseCode: #optional Indicates the reason a VM has been paused
+#
+# @pid: #optional The process ID of the underlying qemu
+# process
+#
+# @serial: #optional Serial number for the VM.
+#
+# @session: #optional The current state of user interaction
+# with the VM
+#
+# @smp: #optional The number of CPUs presented to the VM
+#
+# @smpCoresPerSocket: #optional Indicates the number of CPU cores per
+# socket
+#
+# @smpThreadsPerCore: #optional Indicates the number of CPU threads per
+# core
+#
+# @statsAge: #optional The age of these statistics in seconds
+#
+# @status: #optional The current VM status
+#
+# @timeOffset: #optional The time difference from host to the VM
+# in seconds
+#
+# @transparentHugePages: #optional Indicates if the Transparent Huge Pages
+# feature is enabled for this virtual machine
+#
+# @username: #optional The username associated with the current
+# session
+#
+# @vNodeRuntimeInfo: #optional Information about the vm numa node
+# runtime pinning to host numa node.
+#
+# @vmId: #optional The VM UUID
+#
+# @vmJobs: #optional Info about active vm jobs
+#
+# @vmName: #optional The VM name
+#
+# @vmType: #optional The type of VM
+#
+# @watchdogEvent: #optional Information about the most recent
+# watchdog event
+#
+# Since: 4.15.0
+{'type': 'VmQueryResult',
+ 'data': {
+ '*acpiEnable': 'bool', '*appsList': ['str'], '*balloonInfo': 'BalloonInfo',
+ '*boot': 'VmBootMode', '*cdrom': 'str', '*clientIp': 'str',
+ '*copyPasteEnable': 'bool', '*cpuShares': 'str', '*cpuSys': 'float',
+ '*cpuType': 'str', '*cpuUser': 'float', '*custom': 'StringMap',
+ '*devices': ['VmDevice'], '*disks': 'VmDiskStatsMap',
+ '*disksUsage': ['GuestMountInfo'], '*display': 'VmDisplayType',
+ '*displayInfo': ['VmDisplayInfo'], '*displayIp': 'str',
+ '*displayPort': 'uint', '*displaySecurePort': 'uint',
+ '*displayType': 'VmDisplayType', '*elapsedTime': 'uint',
+ '*emulatedMachine': 'str', '*exitCode': 'int', '*exitMessage': 'str',
+ '*guestCPUCount': 'int', '*guestFQDN': 'str', '*guestIPs': 'str',
+ '*keyboardLayout': 'str', '*kvmEnable': 'bool', '*maxVCpus': 'uint',
+ '*memGuaranteedSize': 'uint', '*memSize': 'uint', '*memUsage': 'uint',
+ '*memoryStats': 'GuestMemoryStats', '*migrationProgress': 'uint',
+ '*monitorResponse': 'int', '*netIfaces': ['GuestNetworkDeviceInfo'],
+ '*network': 'NetworkInterfaceStatsMap', '*nicModel': 'str', '*nice': 'int',
+ '*pauseCode': 'str', '*pid': 'uint', '*serial': 'str',
+ '*session': 'GuestSessionState', '*smp': 'uint',
+ '*smpCoresPerSocket': 'uint', '*smpThreadsPerCore': 'uint',
+ '*statsAge': 'float', '*status': 'VmStatus', '*timeOffset': 'uint',
+ '*transparentHugePages': 'bool', '*username': 'str',
+ '*vNodeRuntimeInfo': 'VmNumaNodeRuntimeInfoMap', '*vmId': 'UUID',
+ '*vmJobs': 'VmJobsMap', '*vmName': 'str', '*vmType': 'VmType',
+ '*watchdogEvent': 'WatchdogEvent'}}
+
+##
+# @VM.query:
+#
+# Get statistics about a running virtual machine.
+#
+# @vmID: The UUID of the VM
+#
+# @fields: #optional A list of strings which specify the keys which
+# should be queried. All fields will be returned if this
+# value is not specified.
+#
+# @changedSince: #optional If specified, all modifications since the given
+# change id are returned. Values for fields where the value
+# has not changed since, will not be returned.
+#
+# Returns:
+# An array containing a single VmData record
+#
+# Since: 4.10.0
+##
+{'command': {'class': 'VM', 'name': 'getStats'},
+ 'data': {'vmID': 'UUID', '*fields': ['string'], '*changedSince': 'uint'},
+ 'returns': ['VmData']}
+
+##
+# @Host.queryVms:
+#
+# Query all specified virtual machines for the specified fields.
+#
+# @vmIDs: #optional A list of VM UUIDs. If not set, all VMs are used.
+#
+# @fields: #optional A list of strings which specify the keys which
+# should be queried. All fields will be returned if this
+# value is not specified.
+#
+# @changedSince: #optional If specified, all modifications since the given
+# change id are returned. Values for fields where the value
+# has not changed since, will not be returned.
+#
+# Returns:
+# A list of query results for all VMs in vmIDs or all VMs if vmIDs not set
+#
+# Since: 4.15.0
+##
+{'command': {'class': 'Host', 'name': 'queryAllVm'},
+ 'data': {'*vmIDs': ['UUID'], '*fields': ['string'], '*changedSince': 'uint'},
+ 'returns': ['VmData']}
+
##
# @VmDefinition:
#
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 4b00c51..839f72c 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -41,6 +41,7 @@
from vdsm import libvirtconnection
from vdsm import netinfo
from vdsm import qemuimg
+from vdsm import trackable
from vdsm import utils
from vdsm.compat import pickle
from vdsm.config import config
@@ -1773,6 +1774,8 @@
self._watchdogEvent = {}
self.sdIds = []
self.arch = caps.getTargetArch()
+ self._queryCacheLock = threading.Lock()
+ self._queryCache = trackable.TrackableMapping()
if (self.arch not in ['ppc64', 'x86_64']):
raise RuntimeError('Unsupported architecture: %s' % self.arch)
@@ -2663,6 +2666,20 @@
stats["watchdogEvent"] = self._watchdogEvent
return stats
+ def query(self, fields=None, changedSince=-1, runHooks=False):
+ # First we need to update the query cache
+ stats = self.getStats()
+ with self._queryCacheLock:
+ self._queryCache.update(stats)
+ self._queryCache.update(self.conf, lambda x: x.startswith('_'))
+
+ # Now we build up the response
+ result = {}
+ for k in (fields or self._queryCache.keys()):
+ if self._queryCache[k].changed(changedSince):
+ result[k] = self._queryCache[k]
+ return result
+
def _getStatsInternal(self):
"""
used by API.Vm.getStats
--
To view, visit http://gerrit.ovirt.org/28819
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iddb4657d738ca0406950d07b84a7c85721e80b78
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Vinzenz Feenstra <vfeenstr(a)redhat.com>