Hello Dan Kenigsberg, Francesco Romani,

I'd like you to do a code review.  Please visit

    http://gerrit.ovirt.org/30076

to review the following change.

Change subject: Add API.VM.setIoTune
......................................................................

Add API.VM.setIoTune

This allows MoM (and the engine if necessary) to set the iotune
limits for disk devices.

Change-Id: I0bd48f13311ad2efc4241117a777ca3400c259ea
Signed-off-by: Martin Sivak <msi...@redhat.com>
Reviewed-on: http://gerrit.ovirt.org/28714
Reviewed-by: Francesco Romani <from...@redhat.com>
Reviewed-by: Dan Kenigsberg <dan...@redhat.com>
---
M lib/vdsm/define.py
M tests/vmTests.py
M vdsm/API.py
M vdsm/rpc/vdsmapi-schema.json
M vdsm/virt/vm.py
5 files changed, 173 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/76/30076/1

diff --git a/lib/vdsm/define.py b/lib/vdsm/define.py
index 4b25f89..34f423a 100644
--- a/lib/vdsm/define.py
+++ b/lib/vdsm/define.py
@@ -144,6 +144,9 @@
     'updateVmPolicyErr': {'status': {
         'code': 63,
         'message': 'Failed to update VM SLA policy'}},
+    'updateIoTuneErr': {'status': {
+        'code': 64,
+        'message': 'Failed to update ioTune values'}},
     'recovery': {'status': {
         'code': 99,
         'message': 'Recovering from crash or Initializing'}},
diff --git a/tests/vmTests.py b/tests/vmTests.py
index 5c3d445..11a256d 100644
--- a/tests/vmTests.py
+++ b/tests/vmTests.py
@@ -60,6 +60,7 @@
         self.devXml = ''
         self._virtError = virtError
         self._metadata = ""
+        self._io_tune = {}
 
     def _failIfRequested(self):
         if self._virtError != libvirt.VIR_ERR_OK:
@@ -94,6 +95,10 @@
     def schedulerParameters(self):
         return {'vcpu_quota': vm._NO_CPU_QUOTA,
                 'vcpu_period': vm._NO_CPU_PERIOD}
+
+    def setBlockIoTune(self, name, io_tune, flags):
+        self._io_tune[name] = io_tune
+        return 1
 
 
 class TestVm(TestCaseBase):
@@ -1145,6 +1150,76 @@
             self.maxDiff = None
             self.assertEqual(expected_xml, self._xml_sanitizer(dom._metadata))
 
+    def testSetIoTune(self):
+
+        drives = [
+            vm.Drive({
+                "specParams": {
+                    "ioTune": {
+                        "total_bytes_sec": 9999,
+                        "total_iops_sec": 9999}
+                }},
+                log=self.log,
+                index=0,
+                device="hdd",
+                path="/dev/dummy",
+                type=vm.DISK_DEVICES,
+                iface="ide")
+        ]
+
+        # Make the drive look like a VDSM volume
+        required = ('domainID', 'imageID', 'poolID', 'volumeID')
+        for p in required:
+            setattr(drives[0], p, "1")
+        drives[0]._blockDev = True
+
+        tunables = [
+            {
+                "name": drives[0].name,
+                "ioTune": {
+                    "write_bytes_sec": 1,
+                    "total_bytes_sec": 0,
+                    "read_bytes_sec": 2
+                }
+            }
+        ]
+
+        expected_io_tune = {
+            drives[0].name: {
+                "write_bytes_sec": 1,
+                "total_bytes_sec": 0,
+                "read_bytes_sec": 2
+            }
+        }
+
+        expected_xml = """
+            <disk device="hdd" snapshot="no" type="block">
+                <source dev="/dev/dummy"/>
+                <target bus="ide" dev="hda"/>
+                <serial></serial>
+                <iotune>
+                    <read_bytes_sec>2</read_bytes_sec>
+                    <write_bytes_sec>1</write_bytes_sec>
+                    <total_bytes_sec>0</total_bytes_sec>
+                </iotune>
+            </disk>"""
+
+        with FakeVM() as machine:
+            dom = FakeDomain()
+            machine._dom = dom
+            for drive in drives:
+                machine._devices[drive.type].append(drive)
+
+            machine.setIoTune(tunables)
+
+            self.assertEqual(expected_io_tune, dom._io_tune)
+
+            # Test that caches were properly updated
+            self.assertEqual(drives[0].specParams["ioTune"],
+                             expected_io_tune[drives[0].name])
+            self.assertEqual(self._xml_sanitizer(drives[0]._deviceXML),
+                             self._xml_sanitizer(expected_xml))
+
 
 class FakeGuestAgent(object):
     def getGuestInfo(self):
diff --git a/vdsm/API.py b/vdsm/API.py
index ace68d1..509fa9d 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -708,6 +708,12 @@
             return errCode['noVM']
         return v.setCpuTuneQuota(quota)
 
+    def setIoTune(self, tunables):
+        v = self._cif.vmContainer.get(self._UUID)
+        if not v:
+            return errCode['noVM']
+        return v.setIoTune(tunables)
+
     def setCpuTunePeriod(self, period):
         v = self._cif.vmContainer.get(self._UUID)
         if not v:
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index 47124af..31b1873 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -7496,6 +7496,24 @@
  'returns': 'VmDefinition'}
 
 ##
+# @VM.setIoTune:
+#
+# Sets the ioTune parameters for block devices
+#
+# @vmID:    The UUID of the VM
+#
+# @tunables: list of VmDiskDeviceTuneParams objects
+#            describing the new settings
+# Returns:
+# Status code
+#
+# Since: 4.15.0
+##
+{'command': {'class': 'VM', 'name': 'setIoTune'},
+ 'data': {'vmID': 'UUID', 'tunables': ['VmDiskDeviceTuneParams']},
+ 'returns': 'TaskStatus'}
+
+##
 # @VM.setCpuTuneQuota:
 #
 # Set the vCpu quota tune parameter to the VM
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index b3dd8f2..80ede4c 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -64,7 +64,8 @@
 from . import sampling
 from . import vmexitreason
 from . import vmstatus
-from .vmtune import updateIoTuneDom
+from .vmtune import updateIoTuneDom, collectInnerElements
+from .vmtune import ioTuneValuesToDom
 
 from .utils import XMLElement
 from vmpowerdown import VmShutdown, VmReboot
@@ -3743,6 +3744,75 @@
         metadata = xml.dom.minidom.parseString(metadata_xml)
         return metadata.getElementsByTagName("qos")[0]
 
+    def _findDeviceByNameOrPath(self, device_name, device_path):
+        for device in self._devices[DISK_DEVICES]:
+            if ((device.name == device_name
+                or ("path" in device and device["path"] == device_path))
+                    and isVdsmImage(device)):
+                return device
+        else:
+            return None
+
+    def setIoTune(self, tunables):
+        for io_tune_change in tunables:
+            device_name = io_tune_change.get('name', None)
+            device_path = io_tune_change.get('path', None)
+            io_tune = io_tune_change['ioTune']
+
+            # Find the proper device object
+            found_device = self._findDeviceByNameOrPath(device_name,
+                                                        device_path)
+            if found_device is None:
+                return self._reportError(
+                    key='updateIoTuneErr',
+                    msg="Device {} not found".format(device_name))
+
+            # Merge the update with current values
+            dom = found_device.getXML()
+            io_dom_list = dom.getElementsByTagName("iotune")
+            old_io_tune = {}
+            if io_dom_list:
+                collectInnerElements(io_dom_list[0], old_io_tune)
+                old_io_tune.update(io_tune)
+                io_tune = old_io_tune
+
+            # Verify the ioTune params
+            try:
+                found_device._validateIoTuneParams(io_tune)
+            except ValueError:
+                return self._reportException(key='updateIoTuneErr',
+                                             msg='Invalid ioTune value')
+
+            try:
+                self._dom.setBlockIoTune(found_device.name, io_tune,
+                                         libvirt.VIR_DOMAIN_AFFECT_LIVE)
+            except libvirt.libvirtError as e:
+                self.log.exception("setVmIoTune failed")
+                if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
+                    return errCode['noVM']
+                else:
+                    return self._reportError(key='updateIoTuneErr',
+                                             msg=e.message)
+
+            # Update both the ioTune arguments and device xml DOM
+            # so we are still up-to-date
+            # TODO: improve once libvirt gets support for iotune events
+            #       see https://bugzilla.redhat.com/show_bug.cgi?id=1114492
+            if io_dom_list:
+                dom.removeChild(io_dom_list[0])
+            io_dom = XMLElement("iotune")
+            ioTuneValuesToDom(io_tune, io_dom)
+            dom.appendChild(io_dom)
+            found_device.specParams['ioTune'] = io_tune
+
+            # Make sure the cached XML representation is valid as well
+            xml = found_device.getXML().toprettyxml(encoding='utf-8')
+            self.log.debug("New device XML for %s: %s",
+                           found_device.name, xml)
+            found_device._deviceXML = xml
+
+        return {'status': doneCode}
+
     def _createTransientDisk(self, diskParams):
         if diskParams.get('shared', None) != DRIVE_SHARED_TYPE.TRANSIENT:
             return


-- 
To view, visit http://gerrit.ovirt.org/30076
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0bd48f13311ad2efc4241117a777ca3400c259ea
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.5
Gerrit-Owner: Martin Sivák <msi...@redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <dan...@redhat.com>
Gerrit-Reviewer: Francesco Romani <from...@redhat.com>
_______________________________________________
vdsm-patches mailing list
vdsm-patches@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to