Change in vdsm[master]: Query interface for all VM fields
by Vinzenz Feenstra
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>
9 years, 2 months
Change in vdsm[master]: logs: improve VDSM logs human-readability
by ykleinbe@redhat.com
Yoav Kleinberger has uploaded a new change for review.
Change subject: logs: improve VDSM logs human-readability
......................................................................
logs: improve VDSM logs human-readability
In this patch I introduce a new formatting for log messages that is more
uniform and much easier to read. I find the previous format extremely
hard to look at.
Change-Id: I65fcc843b4c2c6f1b0f438937a0702b80b714978
Signed-off-by: Yoav Kleinberger <ykleinbe(a)redhat.com>
---
M vdsm/logger.conf.in
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/69/28869/1
diff --git a/vdsm/logger.conf.in b/vdsm/logger.conf.in
index e7ff032..00f5590 100644
--- a/vdsm/logger.conf.in
+++ b/vdsm/logger.conf.in
@@ -67,7 +67,7 @@
format: %(message)s
[formatter_long]
-format: %(threadName)s::%(levelname)s::%(asctime)s::%(module)s::%(lineno)d::%(name)s::(%(funcName)s) %(message)s
+format: %(asctime)s %(levelname)s %(threadName)s: %(message)s (in function %(funcName)s %(pathname)s:%(lineno)d)
[formatter_sysform]
format= vdsm %(name)s %(levelname)s %(message)s
--
To view, visit http://gerrit.ovirt.org/28869
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I65fcc843b4c2c6f1b0f438937a0702b80b714978
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yoav Kleinberger <ykleinbe(a)redhat.com>
9 years, 2 months
Change in vdsm[master]: vdsm-tool: vdsm-id: add force option to force generate id
by Alon Bar-Lev
Alon Bar-Lev has uploaded a new change for review.
Change subject: vdsm-tool: vdsm-id: add force option to force generate id
......................................................................
vdsm-tool: vdsm-id: add force option to force generate id
this is handy to hide the existence and usage of /etc/vdsm/vdsm.id from
users (other components).
Change-Id: I89f1e29c9cdad0cadb32545fa27c1702ad2e116a
Signed-off-by: Alon Bar-Lev <alonbl(a)redhat.com>
---
M lib/vdsm/tool/vdsm-id.py
M lib/vdsm/utils.py
2 files changed, 35 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/08/20808/1
diff --git a/lib/vdsm/tool/vdsm-id.py b/lib/vdsm/tool/vdsm-id.py
index 109c382..01f94a9 100644
--- a/lib/vdsm/tool/vdsm-id.py
+++ b/lib/vdsm/tool/vdsm-id.py
@@ -17,9 +17,13 @@
# Refer to the README and COPYING files for full details of the license
#
+
+import sys
+import argparse
+
+
from vdsm.utils import getHostUUID
from vdsm.tool import expose
-import sys
@expose("vdsm-id")
@@ -27,7 +31,19 @@
"""
Printing host uuid
"""
- hostUUID = getHostUUID(False)
+ parser = argparse.ArgumentParser('vdsm-tool configure')
+ parser.add_argument(
+ '--force',
+ dest='force',
+ default=False,
+ action='store_true',
+ help='Generate vdsmid if not available',
+ )
+ args = parser.parse_args(sys.argv[2:])
+ hostUUID = getHostUUID(
+ legacy=False,
+ force=args.force,
+ )
if hostUUID is None:
raise RuntimeError('Cannot retrieve host UUID')
sys.stdout.write(hostUUID)
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index 78d055e..d38a273 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -48,6 +48,7 @@
import subprocess
import threading
import time
+import uuid
from cpopen import CPopen as BetterPopen
import constants
@@ -599,7 +600,7 @@
__hostUUID = None
-def getHostUUID(legacy=True):
+def getHostUUID(legacy=True, force=False):
global __hostUUID
if __hostUUID:
return __hostUUID
@@ -624,6 +625,14 @@
if p.returncode == 0 and 'Not' not in out:
#Avoid error string - 'Not Settable' or 'Not Present'
__hostUUID = out.strip()
+ elif force:
+ hostid = str(uuid.uuid4())
+ with open(constants.P_VDSM_NODE_ID, 'w') as f:
+ f.write("%s\n", hostid)
+ if isOvirtNode():
+ from ovirtnode import ovirtfunctions
+ ovirtfunctions.ovirt_store_config(constants.P_VDSM_NODE_ID)
+ __hostUUID = hostid
else:
logging.warning('Could not find host UUID.')
@@ -877,3 +886,10 @@
logging.error("Panic: %s", msg, exc_info=True)
os.killpg(0, 9)
sys.exit(-3)
+
+
+def isOvirtNode():
+ return (
+ os.path.exists('/etc/rhev-hypervisor-release') or
+ glob.glob('/etc/ovirt-node-*-release')
+ )
--
To view, visit http://gerrit.ovirt.org/20808
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I89f1e29c9cdad0cadb32545fa27c1702ad2e116a
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Alon Bar-Lev <alonbl(a)redhat.com>
9 years, 3 months
Change in vdsm[master]: vdsm: add check for hostdev passthrough to caps
by Martin Polednik
Martin Polednik has uploaded a new change for review.
Change subject: vdsm: add check for hostdev passthrough to caps
......................................................................
vdsm: add check for hostdev passthrough to caps
Currently only for intel + will not be 100% accurate source
Change-Id: I789f93679740e87b2f5a88351261bc58852990d4
Signed-off-by: Martin Polednik <mpoledni(a)redhat.com>
---
M vdsm/caps.py
1 file changed, 27 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/71/30471/1
diff --git a/vdsm/caps.py b/vdsm/caps.py
index 0993939..2b0aa21 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -246,6 +246,32 @@
return None
+def _iommuPresent(cmdline):
+ if 'intel_iommu' in cmdline:
+ if 'intel_iommu=off' not in cmdline:
+ return 'yes'
+
+ return 'no'
+
+
+def _getIommuSupport():
+ try:
+ import systemd.journal
+ reader = systemd.journal.Reader()
+ reader.this_boot()
+ reader.add_match(_TRANSPORT='kernel')
+ for index, entry in enumerate(reader):
+ if 'Command line:' in entry['MESSAGE']:
+ return _iommuPresent(entry['MESSAGE'])
+ except:
+ with open('/var/log/dmesg', 'r') as fd:
+ for index, line in enumerate(fd):
+ if 'Command line:' in line:
+ return _iommuPresent(line)
+
+ return 'no'
+
+
@utils.memoized
def getLiveMergeSupport():
"""
@@ -642,6 +668,7 @@
caps['autoNumaBalancing'] = getAutoNumaBalancingInfo()
caps['selinux'] = _getSELinux()
+ caps['hostdevSupport'] = _getIommuSupport()
liveSnapSupported = _getLiveSnapshotSupport(targetArch)
if liveSnapSupported is not None:
--
To view, visit http://gerrit.ovirt.org/30471
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I789f93679740e87b2f5a88351261bc58852990d4
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Martin Polednik <mpolednik(a)redhat.com>
9 years, 3 months
Change in vdsm[master]: net_func_tests: Rollback only when an error happens
by asegurap@redhat.com
Antoni Segura Puimedon has uploaded a new change for review.
Change subject: net_func_tests: Rollback only when an error happens
......................................................................
net_func_tests: Rollback only when an error happens
Up until now, net_func_tests used RollbackContext that always
performs all the rolling back operations on context exit. This patch
adds a flag to RollbackContext that if explicitely set to True, will
only perform the rollback operations in case the context was left
due to an exception.
Change-Id: Iaeb9bf19f4bf63d3705cfdda92aa6ec7513a8b98
Signed-off-by: Antoni S. Puimedon <asegurap(a)redhat.com>
---
M lib/vdsm/utils.py
M tests/functional/networkTests.py
2 files changed, 6 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/17/29817/1
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index 76c2a79..7b06ea2 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -1057,8 +1057,9 @@
More examples see tests/utilsTests.py
'''
- def __init__(self, *args):
+ def __init__(self, on_exception_only=False):
self._finally = []
+ self._on_exception_only = on_exception_only
def __enter__(self):
return self
@@ -1069,6 +1070,9 @@
exception), python re-raises the original exception once this
function is finished.
"""
+ if self._on_exception_only and exc_type is None and exc_value is None:
+ return
+
undoExcInfo = None
for undo, args, kwargs in self._finally:
try:
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index b59ef01..2a58970 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -191,7 +191,7 @@
@wraps(func)
def wrapper(*args, **kwargs):
- with RollbackContext() as rollback:
+ with RollbackContext(on_exception_only=True) as rollback:
rollback.prependDefer(args[0].vdsm_net.restoreNetConfig)
func(*args, **kwargs)
return wrapper
--
To view, visit http://gerrit.ovirt.org/29817
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaeb9bf19f4bf63d3705cfdda92aa6ec7513a8b98
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap(a)redhat.com>
9 years, 4 months
Change in vdsm[master]: gluster: geo-replication configuration related verbs.
by dnarayan@redhat.com
Darshan N has uploaded a new change for review.
Change subject: gluster: geo-replication configuration related verbs.
......................................................................
gluster: geo-replication configuration related verbs.
This patch adds four verbs related to geo-replication
configuration.
Verbs:
* glusterVolumeGeoRepConfigList
- Lists all the configuration for the session.
Returns:
{georepConfig:[{'configName': configuration name,
'description': value}]}
* glusterVolumeGeoRepConfigGet
- Gives the configuration value for a specified
configuration.
Returns:
{georepConfig:{'configName': configuration name,
'description': value}}
* glusterVolumeGeoRepConfigSet
- Sets the configuration value for a given
configuration.
Returns:bool
* glusterVolumeGeoRepConfigSetDefault
- Sets the configuration to its default value
Returns:bool
Change-Id: Ifee571dbf3c56633e415d32f8d518cb64aaf1add
Signed-off-by: ndarshan <dnarayan(a)redhat.com>
---
M client/vdsClientGluster.py
M vdsm/gluster/api.py
M vdsm/gluster/cli.py
M vdsm/gluster/exception.py
M vdsm/gluster/vdsmapi-gluster-schema.json
5 files changed, 354 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/62/30162/1
diff --git a/client/vdsClientGluster.py b/client/vdsClientGluster.py
index 421c853..4c65707 100644
--- a/client/vdsClientGluster.py
+++ b/client/vdsClientGluster.py
@@ -430,6 +430,70 @@
pp.pprint(status)
return status['status']['code'], status['status']['message']
+ def do_glusterVolumeGeoRepConfigList(self, args):
+ params = self._eqSplit(args)
+ masterVolName = params.get('volumeName', '')
+ slaveHost = params.get('slaveHost', '')
+ slaveVolName = params.get('slaveVolName', '')
+ if not(masterVolName and slaveHost and slaveVolName):
+ raise ValueError
+
+ status = self.s.glusterVolumeGeoRepConfigList(masterVolName,
+ slaveHost,
+ slaveVolName)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
+ def do_glusterVolumeGeoRepConfigSet(self, args):
+ params = self._eqSplit(args)
+ masterVolName = params.get('volumeName', '')
+ slaveHost = params.get('slaveHost', '')
+ slaveVolName = params.get('slaveVolName', '')
+ key = params.get('key', '')
+ value = params.get('value', '')
+ if not(masterVolName and slaveHost and slaveVolName and key and value):
+ raise ValueError
+
+ status = self.s.glusterVolumeGeoRepConfigSet(masterVolName,
+ slaveHost,
+ slaveVolName,
+ key,
+ value)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
+ def do_glusterVolumeGeoRepConfigGet(self, args):
+ params = self._eqSplit(args)
+ masterVolName = params.get('volumeName', '')
+ slaveHost = params.get('slaveHost', '')
+ slaveVolName = params.get('slaveVolName', '')
+ key = params.get('key', '')
+ if not(masterVolName and slaveHost and slaveVolName and key):
+ raise ValueError
+
+ status = self.s.glusterVolumeGeoRepConfigGet(masterVolName,
+ slaveHost,
+ slaveVolName,
+ key)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
+ def do_glusterVolumeGeoRepConfigSetDefault(self, args):
+ params = self._eqSplit(args)
+ masterVolName = params.get('volumeName', '')
+ slaveHost = params.get('slaveHost', '')
+ slaveVolName = params.get('slaveVolName', '')
+ key = params.get('key', '')
+ if not(masterVolName and slaveHost and slaveVolName and key):
+ raise ValueError
+
+ status = self.s.glusterVolumeGeoRepConfigSetDefault(masterVolName,
+ slaveHost,
+ slaveVolName,
+ key)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
def getGlusterCmdDict(serv):
return \
@@ -731,4 +795,55 @@
('volumeName=<volume name>',
'Returns total, free and used space(bytes) of gluster volume'
)),
+ 'glusterVolumeGeoRepConfigList': (
+ serv.do_glusterVolumeGeoRepConfigList,
+ ('volumeName=<master_volume_name> slaveHost=<slave_host> '
+ 'slaveVolName=<slave_volume_name>\n\t'
+ '<master_volume_name> is an existing volume name in '
+ 'the master node\n\t'
+ '<slave_host> is slave host name\n\t'
+ '<slave_volume_name> is an existing volume name '
+ 'in the slave node',
+ 'list volume geo-replication configurations'
+ )),
+ 'glusterVolumeGeoRepConfigSet': (
+ serv.do_glusterVolumeGeoRepConfigSet,
+ ('volumeName=<master_volume_name> slaveHost=<slave_host> '
+ 'slaveVolName=<slave_volume_name> keyName=<key> '
+ 'value=<value>\n\t'
+ '<master_volume_name> is an existing volume name '
+ 'in the master node\n\t'
+ '<slave_host> is slave host name\n\t'
+ '<slave_volume_name> is an existing volume name in '
+ 'the slave node\n\t'
+ '<key> is the key name of configuration\n\t'
+ '<value> is the key value',
+ 'set volume geo-replication configuration'
+ )),
+ 'glusterVolumeGeoRepConfigGet': (
+ serv.do_glusterVolumeGeoRepConfigGet,
+ ('volumeName=<master_volume_name> slaveHost=<slave_host> '
+ 'slaveVolName=<slave_volume_name> keyName=<key> '
+ 'value=<value>\n\t'
+ '<master_volume_name> is an existing volume name in '
+ 'the master node\n\t'
+ '<slave_host> is slave host name\n\t'
+ '<slave_volume_name> is an existing volume name in '
+ 'the slave node\n\t'
+ '<key> is the key name of configuration',
+ 'get volume geo-replication configuration'
+ )),
+ 'glusterVolumeGeoRepConfigSetDefault': (
+ serv.do_glusterVolumeGeoRepConfigSetDefault,
+ ('masterVolName=<master_volume_name> slaveHost=<slave_host> '
+ 'slaveVolName=<slave_volume_name> keyName=<key> '
+ 'value=<value>\n\t'
+ '<master_volume_name> is an existing volume name in '
+ 'the master node\n\t'
+ '<slave_host> is slave host name\n\t'
+ '<slave_volume_name> is an existing volume name in '
+ 'the slave node\n\t'
+ '<key> is the key name',
+ 'Set volume geo-replication configuration to devault'
+ ))
}
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 0e6c850..5b3eec7 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -322,6 +322,46 @@
data = self.svdsmProxy.glusterVolumeStatvfs(volumeName)
return self._computeVolumeStats(data)
+ @exportAsVerb
+ def volumeGeoRepConfigList(self, masterVolName, slaveHost, slaveVolName,
+ options=None):
+ status = self.svdsmProxy.glusterVolumeGeoRepConfigList(masterVolName,
+ slaveHost,
+ slaveVolName)
+ return {'geoRepConfig': status}
+
+ @exportAsVerb
+ def volumeGeoRepConfigSet(self, masterVolName, slaveHost, slaveVolName,
+ key, value, options=None):
+ status = self.svdsmProxy.glusterVolumeGeoRepConfigSet(masterVolName,
+ slaveHost,
+ slaveVolName,
+ key,
+ value)
+ return {'geoRepSet': status}
+
+ @exportAsVerb
+ def volumeGeoRepConfigGet(self, masterVolName, slaveHost, slaveVolName,
+ key, options=None):
+
+ status = self.svdsmProxy.glusterVolumeGeoRepConfigGet(masterVolName,
+ slaveHost,
+ slaveVolName,
+ key)
+ return {'geoRepGet': status}
+
+ @exportAsVerb
+ def volumeGeoRepConfigSetDefault(self, masterVolName, slaveHost,
+ slaveVolName,
+ key, options=None):
+
+ status = self.svdsmProxy.glusterVolumeGeoRepConfigSetDefault(
+ masterVolName,
+ slaveHost,
+ slaveVolName,
+ key)
+ return {'geoRepSetDefault': status}
+
def getGlusterMethods(gluster):
l = []
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index 2e1c9a9..6a4ffd6 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -1054,3 +1054,74 @@
return _parseVolumeTasks(xmltree)
except _etreeExceptions:
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
+
+
+def _parseVolumeGeoRepConfigList(tree):
+ """
+ Returns:
+ {geoRepConfig:[{'option name': name of the configuration,
+ 'description': value of the configuration}]
+ }
+ """
+ result = {}
+ conf = tree.find('geoRep/config')
+ config_list = []
+ for child in conf.getchildren():
+ config = {}
+ config['optionName'] = child.tag
+ config['description'] = child.text
+ config_list.append(config)
+ result['geoRepConfig'] = config_list
+ return result
+
+
+@makePublic
+def volumeGeoRepConfigList(masterVolName, slaveHost, slaveVolName):
+ command = _getGlusterVolCmd() + ["geo-replication", masterVolName,
+ "%s::%s" % (slaveHost, slaveVolName),
+ "config"]
+ try:
+ xmltree = _execGlusterXml(command)
+ except ge.GlusterCmdFailedException as e:
+ raise ge.GlusterGeoRepConfigListFailedException(rc=e.rc, err=e.err)
+ try:
+ return _parseVolumeGeoRepConfigList(xmltree)
+ except _etreeExceptions:
+ raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
+
+
+@makePublic
+def volumeGeoRepConfigSet(masterVolName, slaveHost, slaveVolName, key, value):
+ command = _getGlusterVolCmd() + ["geo-replication", masterVolName,
+ "%s::%s" % (slaveHost, slaveVolName),
+ "config", key, value]
+ rc, out, err = _execGluster(command)
+ if rc:
+ raise ge.GlusterGeoRepConfigSetFailedException(rc, out, err)
+ return True
+
+
+@makePublic
+def volumeGeoRepConfigGet(masterVolName, slaveHost, slaveVolName, key):
+ command = _getGlusterVolCmd() + ["geo-replication", masterVolName,
+ "%s::%s" % (slaveHost, slaveVolName),
+ "config", key]
+ try:
+ xmltree = _execGlusterXml(command)
+ except ge.GlusterCmdFailedException as e:
+ raise ge.GlusterGeoRepConfigGetFailedException(rc=e.rc, err=e.err)
+ try:
+ return _parseVolumeGeoRepConfigList(xmltree)
+ except _etreeExceptions:
+ raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
+
+
+@makePublic
+def volumeGeoRepConfigSetDefault(masterVolName, slaveHost, slaveVolName, key):
+ command = _getGlusterVolCmd() + ["geo-replication", masterVolName,
+ "%s::%s" % (slaveHost, slaveVolName),
+ "config", "!%s" % key]
+ rc, out, err = _execGluster(command)
+ if rc:
+ raise ge.GlusterGeoRepConfigSetDefaultFailedException(rc, out, err)
+ return True
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index 0205cb1..ca6b7cf 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -506,3 +506,29 @@
class GlfsFiniException(GlusterLibgfapiException):
code = 4573
message = "glfs fini failed"
+
+
+#geo-replication
+class GlusterGeoRepException(GlusterException):
+ code = 4560
+ message = "Gluster Geo-Replication Exception"
+
+
+class GlusterGeoRepConfigListFailedException(GlusterVolumeException):
+ code = 4169
+ message = "Get volume geo-replication config list failed"
+
+
+class GlusterGeoRepConfigSetFailedException(GlusterVolumeException):
+ code = 4170
+ message = "Set volume geo-replication config failed"
+
+
+class GlusterGeoRepConfigGetFailedException(GlusterVolumeException):
+ code = 4171
+ message = "Get volume geo-replication config failed"
+
+
+class GlusterGeoRepConfigSetDefaultFailedException(GlusterVolumeException):
+ code = 4172
+ message = "Set volume geo-replication config to default failed"
diff --git a/vdsm/gluster/vdsmapi-gluster-schema.json b/vdsm/gluster/vdsmapi-gluster-schema.json
index 4ddd182..06de6ca 100644
--- a/vdsm/gluster/vdsmapi-gluster-schema.json
+++ b/vdsm/gluster/vdsmapi-gluster-schema.json
@@ -1238,3 +1238,105 @@
{'command': {'class': 'GlusterVolume', 'name': 'statsInfoGet'},
'data': {'volumeName': 'str'},
'returns': 'GlusterVolumeStatsInfo'}
+
+# @GeoRepConfig:
+#
+# Geo replication config details.
+#
+# @optionname: Config option name
+#
+# @description: Option details
+#
+# Since: 4.16.0
+##
+{'type': 'GeoRepConfig',
+ 'data': {'optionname': 'str', 'description': 'str'}}
+
+##
+# @GlusterGeoRep.configList:
+#
+# List Geo Replication configuration
+#
+# @mastervolname: is an existing volume name in the master node
+#
+# @slavehost: is remote slave host name or ip
+#
+# @slavevolname: is an available existing volume name in the slave node
+#
+# Returns:
+# List of geo replication configurations
+#
+# Since: 4.16.0
+##
+{'command': {'class': 'GlusterGeoRep', 'name': 'geoRepConfigList'},
+ 'data': {'mastervolname': 'str', 'slavehost': 'str', 'slavevolname': 'str'},
+ 'returns': 'GeoRepConfig'}
+
+##
+# @GlusterGeoRep.configSet:
+#
+# Set Geo Replication config option
+#
+# @mastervolname: is an existing volume name in the master node
+#
+# @slavehost: is remote slave host name or ip
+#
+# @slavevolname: is an available existing volume name in the slave node
+#
+# @key: valid configuration option name
+#
+# @value: value to the option
+#
+# Returns:
+# True if it sets value to the option successfully
+#
+# Since: 4.16.0
+##
+{'command': {'class': 'GlusterGeoRep', 'name': 'geoRepConfigSet'},
+ 'data': {'mastervolname': 'str', 'slavehost': 'str', 'slavevolname': 'str', 'key': 'str', 'value': 'str'},
+ 'returns': 'bool'}
+
+##
+# @GlusterVolume.geoRepConfigGet:
+#
+# Get value of the Geo Replication config option
+#
+# @mastervolname: is an existing volume name in the master node
+#
+# @slavehost: is remote slave host name or ip
+#
+# @slavevolname: is an available existing volume name in the slave node
+#
+# @key: valid configuration option name
+#
+# Returns:
+# The value of the Geo Replication config option
+#
+# Since: 4.16.0
+##
+{'command': {'class': 'GlusterGeoRep', 'name': 'geoRepConfigGet'},
+ 'data': {'mastervolname': 'str', 'slavehost': 'str', 'slavevolname': 'str', 'key': 'str'},
+ 'returns': 'GeoRepConfig'}
+
+##
+# @GlusterVolume.geoRepConfigSetDefault:
+#
+# Resets the the config option to default value
+#
+# @mastervolname: is an existing volume name in the master node
+#
+# @slavehost: is remote slave host name or ip
+#
+# @slavevolname: is an available existing volume name in the slave node
+#
+# @key: valid configuration option name
+#
+# Returns:
+# True if default value is set successfully
+#
+# Since: 4.16.0
+##
+{'command': {'class': 'GlusterGeoRep', 'name': 'geoRepConfigSetDefault'},
+ 'data': {'mastervolname': 'str', 'slavehost': 'str', 'slavevolname': 'str', 'key': 'str'},
+ 'returns': 'bool'}
+
--
To view, visit http://gerrit.ovirt.org/30162
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifee571dbf3c56633e415d32f8d518cb64aaf1add
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Darshan N <dnarayan(a)redhat.com>
9 years, 4 months
Change in vdsm[master]: assert: Replace assetion with AssertionError
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: assert: Replace assetion with AssertionError
......................................................................
assert: Replace assetion with AssertionError
If Python is run with -O flag, assertions are removed. This may casue a
useful error message to be hidden, making it harder to debug, or worse,
code invoke inside an assert will not run, changing the flow of the
"optimized" code.
This patch replaces assertions with raising AssertionError, ensuring
that when the impossible happen, we will get an expection.
This patch, together with http://gerrit.ovirt.org/29302 replace all the
asserts in vdsm code. The rest of the assert are in tests where they
safe and useful.
Change-Id: I8c60c65b283f4343448bb9eaf6ccf2526b188db0
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M lib/vdsm/libvirtconnection.py
M lib/vdsm/netinfo.py
M vdsm/rpc/BindingXMLRPC.py
M vdsm/rpc/process-schema.py
M vdsm/storage/misc.py
5 files changed, 25 insertions(+), 10 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/29307/1
diff --git a/lib/vdsm/libvirtconnection.py b/lib/vdsm/libvirtconnection.py
index b1332db..260de23 100644
--- a/lib/vdsm/libvirtconnection.py
+++ b/lib/vdsm/libvirtconnection.py
@@ -37,7 +37,8 @@
self.__thread = None
def start(self):
- assert not self.run
+ if self.run:
+ raise AssertionError("EventLoop is running")
self.__thread = threading.Thread(target=self.__run,
name="libvirtEventLoop")
self.__thread.setDaemon(True)
diff --git a/lib/vdsm/netinfo.py b/lib/vdsm/netinfo.py
index 8d4dc19..78055b4 100644
--- a/lib/vdsm/netinfo.py
+++ b/lib/vdsm/netinfo.py
@@ -986,8 +986,9 @@
def getBondingForNic(self, nic):
bondings = list(self.getBondingsForNic(nic))
if bondings:
- assert len(bondings) == 1, \
- "Unexpected configuration: More than one bonding per nic"
+ if len(bondings) != 1:
+ raise AssertionError("Unexpected configuration: More than "
+ "one bonding per nic")
return bondings[0]
return None
@@ -1005,13 +1006,19 @@
for port in ports:
if port in self.vlans:
- assert vlan is None
+ if vlan is not None:
+ raise AssertionError("Unexpected vlan: %s exepected: None"
+ % (vlan,))
nic = getVlanDevice(port)
vlan = getVlanID(port)
- assert self.vlans[port]['iface'] == nic
+ if self.vlans[port]['iface'] != nic:
+ raise AssertionError("Unexpected iface: %s expected: %s" %
+ (self.vlans[port]['iface'], nic))
port = nic
if port in self.bondings:
- assert bonding is None
+ if bonding is not None:
+ raise AssertionError("Unexpected bonding: %s expected: "
+ "None" % bonding)
bonding = port
lnics += self.bondings[bonding]['slaves']
elif port in self.nics:
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index 42aad1b..ffe233d 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -1088,7 +1088,8 @@
logLevel = logging.TRACE
displayArgs = args
if f.__name__ == 'vmDesktopLogin':
- assert 'password' not in kwargs
+ if 'password' in kwargs:
+ raise AssertionError("Unexpected kwarg: password")
if len(args) > 3:
displayArgs = args[:3] + ('****',) + args[4:]
diff --git a/vdsm/rpc/process-schema.py b/vdsm/rpc/process-schema.py
index ee88d93..51ec55c 100755
--- a/vdsm/rpc/process-schema.py
+++ b/vdsm/rpc/process-schema.py
@@ -103,7 +103,9 @@
'xxx': []})
# Pop a blank line
- assert('' == lines.pop(0))
+ line = lines.pop(0)
+ if line != '':
+ raise AssertionError("Expected empty line: %s" % line)
# Grab the entity description. It might span multiple lines.
symbol['desc'] = lines.pop(0)
@@ -111,7 +113,9 @@
symbol['desc'] += lines.pop(0)
# Pop a blank line
- assert ('' == lines.pop(0))
+ line = lines.pop(0)
+ if line != '':
+ raise AssertionError("Expected empty line: %s" % line)
# Populate the rest of the human-readable data.
# First try to read the parameters/members information. We are finished
diff --git a/vdsm/storage/misc.py b/vdsm/storage/misc.py
index d0869ee..4e7d9ba 100644
--- a/vdsm/storage/misc.py
+++ b/vdsm/storage/misc.py
@@ -697,7 +697,9 @@
def exit(self):
with self._cond:
- assert self._busy, "Attempt to exit a barrier without entering"
+ if not self._busy:
+ raise AssertionError("Attempt to exit a barrier without "
+ "entering")
self._busy = False
self._cond.notifyAll()
--
To view, visit http://gerrit.ovirt.org/29307
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8c60c65b283f4343448bb9eaf6ccf2526b188db0
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
9 years, 4 months
Change in vdsm[master]: mailbox: Log traceback after fatal failures in mailbox monitors
by Nir Soffer
Nir Soffer has uploaded a new change for review.
Change subject: mailbox: Log traceback after fatal failures in mailbox monitors
......................................................................
mailbox: Log traceback after fatal failures in mailbox monitors
Mailbox monitor threads were not logging fatal error properly. Now these
threads use our standard @traceback decorator to ensure that failures
are logged properly.
The message when stopping the spm mailbox thread normally was moved out
of the try finally block, to ensure that it shows only for normal
shutdown, and not for unexpected death of the thread, where we will have
a clear traceback.
Change-Id: I68957ca745018349cae488acfe252e902c2af3ae
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/storage/storage_mailbox.py
1 file changed, 7 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/53/29853/1
diff --git a/vdsm/storage/storage_mailbox.py b/vdsm/storage/storage_mailbox.py
index c31018a..59d0060 100644
--- a/vdsm/storage/storage_mailbox.py
+++ b/vdsm/storage/storage_mailbox.py
@@ -36,6 +36,7 @@
from threadPool import ThreadPool
from storage_exception import InvalidParameterException
from vdsm import constants
+from vdsm import utils
__author__ = "ayalb"
__date__ = "$Mar 9, 2009 5:25:07 PM$"
@@ -425,6 +426,8 @@
MESSAGES_PER_MAILBOX,
repr(self._outgoingMail[start:end])))
+ @utils.traceback(on=log.name,
+ msg="Unhandled exception in HSM_MailMonitor thread")
def run(self):
try:
failures = 0
@@ -778,6 +781,8 @@
finally:
self._outLock.release()
+ @utils.traceback(on=log.name,
+ msg="Unhandled exception in SPM_MailMonitor thread")
def run(self, *args):
try:
while not self._stop:
@@ -788,8 +793,8 @@
self._inLock.release()
self.log.error("Error checking for mail", exc_info=True)
time.sleep(self._monitorInterval)
+ self.log.info("SPM_MailMonitor - Incoming mail monitoring thread "
+ "stopped")
finally:
self._stopped = True
self.tp.joinAll(waitForTasks=False)
- self.log.info("SPM_MailMonitor - Incoming mail monitoring thread "
- "stopped")
--
To view, visit http://gerrit.ovirt.org/29853
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I68957ca745018349cae488acfe252e902c2af3ae
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
9 years, 4 months
Change in vdsm[master]: vdsm-gluster: Added gluster volume geo-replication start verb
by tjeyasin@redhat.com
Hello Ayal Baron, Bala.FA, Saggi Mizrahi, Dan Kenigsberg,
I'd like you to do a code review. Please visit
http://gerrit.ovirt.org/17766
to review the following change.
Change subject: vdsm-gluster: Added gluster volume geo-replication start verb
......................................................................
vdsm-gluster: Added gluster volume geo-replication start verb
Start the geo-replication session between the hosts.
Start distributed geo-replication on all the nodes that are a part
of the master-volume. Even if any node, that is a part of the
master-volume is down, the command will still be successful.
Change-Id: I3cf03c748cf9fe28efe7d407727cd52da20701c5
Signed-off-by: Timothy Asir <tjeyasin(a)redhat.com>
---
M client/vdsClientGluster.py
M vdsm/gluster/api.py
M vdsm/gluster/cli.py
M vdsm/gluster/exception.py
4 files changed, 100 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/66/17766/1
diff --git a/client/vdsClientGluster.py b/client/vdsClientGluster.py
index 90af83e..feb6387 100644
--- a/client/vdsClientGluster.py
+++ b/client/vdsClientGluster.py
@@ -424,6 +424,34 @@
pp.pprint(status)
return status['status']['code'], status['status']['message']
+ def do_glusterVolumeGeoRepStart(self, args):
+ params = self._eqSplit(args)
+ masterVolName = params.get('masterVolName', '')
+ slaveHost = params.get('slaveHost', '')
+ slaveVolName = params.get('slaveVolName', '')
+ if not(masterVolName and slaveHost and slaveVolName):
+ raise ValueError
+
+ status = self.s.glusterVolumeGeoRepStart(masterVolName,
+ slaveHost,
+ slaveVolName)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
+ def do_glusterVolumeGeoRepStop(self, args):
+ params = self._eqSplit(args)
+ masterVolName = params.get('masterVolName', '')
+ slaveHost = params.get('slaveHost', '')
+ slaveVolName = params.get('slaveVolName', '')
+ if not(masterVolName and slaveHost and slaveVolName):
+ raise ValueError
+
+ status = self.s.glusterVolumeGeoRepStop(masterVolName,
+ slaveHost,
+ slaveVolName)
+ pp.pprint(status)
+ return status['status']['code'], status['status']['message']
+
def getGlusterCmdDict(serv):
return \
@@ -705,4 +733,26 @@
'not set'
'(swift, glusterd, smb, memcached)'
)),
+ 'glusterVolumeGeoRepStart': (
+ serv.do_glusterVolumeGeoRepStart,
+ ('masterVolName=<master_volume_name> slaveHost=<slave_host> '
+ 'slaveVolName=<slave_volume_name>\n\t'
+ '<master_volume_name> is an existing volume name in the '
+ 'master node\n\t'
+ '<slave_host> is slave host name\n\t'
+ '<slave_volume_name> is an existing volume name in the '
+ 'slave node',
+ 'start volume geo-replication'
+ )),
+ 'glusterVolumeGeoRepStop': (
+ serv.do_glusterVolumeGeoRepStop,
+ ('masterVolName=<master_volume_name> slaveHost=<slave_host> '
+ 'slaveVolName=<slave_volume_name>\n\t'
+ '<master_volume_name> is an existing volume name in the '
+ 'master node\n\t'
+ '<slave_host> is slave host name\n\t'
+ '<slave_volume_name> is an existing volume name in the '
+ 'slave node',
+ 'stop volume geo-replication'
+ )),
}
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 4bd8308..ed9f5ae 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -287,6 +287,20 @@
status = self.svdsmProxy.glusterServicesGet(serviceNames)
return {'services': status}
+ @exportAsVerb
+ def volumeGeoRepStart(self, masterVolName, slaveHost, slaveVolName,
+ options=None):
+ self.svdsmProxy.glusterVolumeGeoRepStart(masterVolName,
+ slaveHost,
+ slaveVolName)
+
+ @exportAsVerb
+ def volumeGeoRepStop(self, masterVolName, slaveHost, slaveVolName,
+ options=None):
+ self.svdsmProxy.glusterVolumeGeoRepStop(masterVolName,
+ slaveHost,
+ slaveVolName)
+
def getGlusterMethods(gluster):
l = []
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index bac6d1c..e4d6615 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -897,3 +897,29 @@
return _parseVolumeProfileInfo(xmltree, nfs)
except _etreeExceptions:
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
+
+
+@makePublic
+def volumeGeoRepStart(masterVolName, slaveHost, slaveVolName):
+ command = _getGlusterVolCmd() + ["geo-replication", masterVolName,
+ "%s::%s" % (slaveHost, slaveVolName),
+ "start"]
+ try:
+ _execGlusterXml(command)
+ return True
+ except ge.GlusterCmdFailedException as e:
+ raise ge.GlusterVolumeGeoRepStartFailedException(rc=e.rc,
+ err=e.err)
+
+
+@makePublic
+def volumeGeoRepStop(masterVolName, slaveHost, slaveVolName):
+ command = _getGlusterVolCmd() + ["geo-replication", masterVolName,
+ "%s::%s" % (slaveHost, slaveVolName),
+ "stop"]
+ try:
+ _execGlusterXml(command)
+ return True
+ except ge.GlusterCmdFailedException as e:
+ raise ge.GlusterVolumeGeoRepStopFailedException(rc=e.rc,
+ err=e.err)
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index c569a9e..259df32 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -484,3 +484,13 @@
prefix = "%s: " % (action)
self.message = prefix + "Service action is not supported"
self.err = [self.message]
+
+
+class GlusterVolumeGeoRepStartFailedException(GlusterVolumeException):
+ code = 4164
+ message = "Volume geo-replication start failed"
+
+
+class GlusterVolumeGeoRepStopFailedException(GlusterVolumeException):
+ code = 4165
+ message = "Volume geo-replication stop failed"
--
To view, visit http://gerrit.ovirt.org/17766
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3cf03c748cf9fe28efe7d407727cd52da20701c5
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Timothy Asir <tjeyasin(a)redhat.com>
Gerrit-Reviewer: Ayal Baron <abaron(a)redhat.com>
Gerrit-Reviewer: Bala.FA <barumuga(a)redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken(a)redhat.com>
Gerrit-Reviewer: Saggi Mizrahi <smizrahi(a)redhat.com>
9 years, 4 months
Change in vdsm[master]: networkTests: Extend a test to also consider DHCPv6
by osvoboda@redhat.com
Ondřej Svoboda has uploaded a new change for review.
Change subject: networkTests: Extend a test to also consider DHCPv6
......................................................................
networkTests: Extend a test to also consider DHCPv6
Change-Id: Ic5d821edd54681a7a8c1013a90af61ae835baa39
Signed-off-by: Ondřej Svoboda <osvoboda(a)redhat.com>
---
M tests/functional/dummy.py
M tests/functional/firewall.py
M tests/functional/networkTests.py
3 files changed, 32 insertions(+), 16 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/32/30532/1
diff --git a/tests/functional/dummy.py b/tests/functional/dummy.py
index aa56c71..b94c77d 100644
--- a/tests/functional/dummy.py
+++ b/tests/functional/dummy.py
@@ -54,9 +54,9 @@
(dummyName, e))
-def setIP(dummyName, ipaddr, netmask):
+def setIP(dummyName, ipaddr, netmask, family=4):
try:
- addrAdd(dummyName, ipaddr, netmask)
+ addrAdd(dummyName, ipaddr, netmask, family)
except IPRoute2Error:
raise SkipTest('Failed to set device ip')
diff --git a/tests/functional/firewall.py b/tests/functional/firewall.py
index ee7bb9f..9940a75 100644
--- a/tests/functional/firewall.py
+++ b/tests/functional/firewall.py
@@ -43,7 +43,10 @@
if _serviceRunning('iptables'):
_execCmdChecker([_IPTABLES_BINARY.cmd, '-I', 'INPUT', '-i',
veth, '-p', 'udp', '--sport', '68', '--dport',
- '67', '-j', 'ACCEPT'])
+ '67', '-j', 'ACCEPT']) # DHCPv4
+ _execCmdChecker([_IPTABLES_BINARY.cmd, '-I', 'INPUT', '-i',
+ veth, '-p', 'udp', '--sport', '546', '--dport',
+ '547', '-j', 'ACCEPT']) # DHCPv6
elif _serviceRunning('firewalld'):
_execCmdChecker([_FIREWALLD_BINARY.cmd, '--zone=trusted',
'--change-interface=' + veth])
@@ -68,7 +71,10 @@
if _serviceRunning('iptables'):
_execCmdChecker([_IPTABLES_BINARY.cmd, '-D', 'INPUT', '-i',
veth, '-p', 'udp', '--sport', '68', '--dport',
- '67', '-j', 'ACCEPT'])
+ '67', '-j', 'ACCEPT']) # DHCPv4
+ _execCmdChecker([_IPTABLES_BINARY.cmd, '-D', 'INPUT', '-i',
+ veth, '-p', 'udp', '--sport', '546', '--dport',
+ '547', '-j', 'ACCEPT']) # DHCPv6
elif _serviceRunning('firewalld'):
_execCmdChecker([_FIREWALLD_BINARY.cmd, '--zone=trusted',
'--remove-interface=' + veth])
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index f87f49b..0033c19 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -64,8 +64,11 @@
DHCP_RANGE_TO = '240.0.0.100'
CUSTOM_PROPS = {'linux': 'rules', 'vdsm': 'as well'}
-IPv6_ADDRESS = 'fdb3:84e5:4ff4:55e3::1/64'
+IPv6_ADDRESS = 'fdb3:84e5:4ff4:55e3::1'
+IPv6_CIDR = '64'
+IPv6_ADDRESS_AND_CIDR = IPv6_ADDRESS + '/' + IPv6_CIDR
IPv6_GATEWAY = 'fdb3:84e5:4ff4:55e3::ff'
+DHCPv6_ADDRESS = 'fdb3:84e5:4ff4:55e3::2'
dummyPool = set()
DUMMY_POOL_SIZE = 5
@@ -90,11 +93,16 @@
@contextmanager
-def dnsmasqDhcp(interface):
+def dnsmasqDhcp(interface, family=4):
"""Manages the life cycle of dnsmasq as a DHCP server."""
dhcpServer = dhcp.Dnsmasq()
+ if family == 4:
+ rangeFrom, rangeTo = DHCP_RANGE_FROM, DHCP_RANGE_TO
+ else:
+ rangeFrom, rangeTo = DHCPv6_ADDRESS, DHCPv6_ADDRESS
+
try:
- dhcpServer.start(interface, DHCP_RANGE_FROM, DHCP_RANGE_TO)
+ dhcpServer.start(interface, rangeFrom, rangeTo)
except dhcp.DhcpError as e:
raise SkipTest(e)
@@ -1769,11 +1777,11 @@
nic, = nics
networks = {
NETWORK_NAME + '1':
- {'nic': nic, 'bootproto': 'none', 'ipv6addr': IPv6_ADDRESS,
- 'ipv6gateway': IPv6_GATEWAY},
+ {'nic': nic, 'bootproto': 'none', 'ipv6gateway': IPv6_GATEWAY,
+ 'ipv6addr': IPv6_ADDRESS_AND_CIDR},
NETWORK_NAME + '2':
- {'nic': nic, 'bootproto': 'none', 'ipv6addr': IPv6_ADDRESS,
- 'ipv6gateway': IPv6_GATEWAY, 'ipaddr': IP_ADDRESS,
+ {'nic': nic, 'bootproto': 'none', 'ipv6gateway': IPv6_GATEWAY,
+ 'ipv6addr': IPv6_ADDRESS_AND_CIDR, 'ipaddr': IP_ADDRESS,
'gateway': IP_GATEWAY,
'netmask': prefix2netmask(int(IP_CIDR))}}
for network, netdict in networks.iteritems():
@@ -1783,7 +1791,7 @@
self.assertEqual(status, SUCCESS, msg)
self.assertNetworkExists(network)
self.assertIn(
- IPv6_ADDRESS,
+ IPv6_ADDRESS_AND_CIDR,
self.vdsm_net.netinfo.networks[network]['ipv6addrs'])
self.assertEqual(
IPv6_GATEWAY,
@@ -1836,14 +1844,15 @@
NOCHK)
@permutations([[True], [False]])
+ @permutations([[(4, IP_ADDRESS, IP_CIDR)], [(6, IPv6_ADDRESS, IPv6_CIDR)]])
@cleanupNet
@RequireVethMod
@ValidateRunningAsRoot
- def testSetupNetworksAddDelDhcp(self, bridged):
+ def testSetupNetworksAddDelDhcp(self, bridged, (family, addr, cidr)):
with vethIf() as (left, right):
- veth.setIP(left, IP_ADDRESS, IP_CIDR)
+ veth.setIP(left, addr, cidr)
veth.setLinkUp(left)
- with dnsmasqDhcp(left):
+ with dnsmasqDhcp(left, family):
network = {NETWORK_NAME: {'nic': right, 'bridged': bridged,
'bootproto': 'dhcp',
'blockingdhcp': True}}
@@ -1853,7 +1862,8 @@
self.assertNetworkExists(NETWORK_NAME)
net = self.vdsm_net.netinfo.networks[NETWORK_NAME]
- self.assertEqual(net['bootproto4'], 'dhcp')
+ if family == 4:
+ self.assertEqual(net['bootproto4'], 'dhcp')
if bridged:
self.assertEqual(net['cfg']['BOOTPROTO'], 'dhcp')
--
To view, visit http://gerrit.ovirt.org/30532
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic5d821edd54681a7a8c1013a90af61ae835baa39
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ondřej Svoboda <osvoboda(a)redhat.com>
9 years, 4 months