On 28/05/2015 10:59, Rodrigo Trujillo wrote:
This patch creates new colletion and resource of memory devices.
They
are subnodes of a given VM resource, that means the user is going to use
the VM url/api to add or fetch the memory devices, such as:
http://<HOST>/vms/<YOUR_VM>/memdevices (GET) -> to list memory devs
http://<HOST>/vms/<YOUR_VM>/memdevices (POST) -> to add a memory dev
http://<HOST>/vms/<YOUR_VM>/memdevices/<SLOT> (GET) -> to retrieve
a
given memory device in SLOT
This patch does not give support do DELETE or UPDATE a memory device
As I said before, unless we change the UI to looks like the same we did
for network interfaces (which I think will only add more complexity), I
don't think this API will work good for us.
The user should be able to only specify the amount of memory to the
guest, and the backend identify how many devices should be added and do
the operation.
Otherwise, we will insert backend logic to the UI and if a request fails
we will need to do a rollback also on UI.
Signed-off-by: Rodrigo Trujillo
<rodrigo.trujillo(a)linux.vnet.ibm.com>
---
src/kimchi/control/vm/memdevices.py | 47 +++++++++++++++++++
src/kimchi/i18n.py | 2 +
src/kimchi/model/vmmemdevices.py | 94 +++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+)
create mode 100644 src/kimchi/control/vm/memdevices.py
create mode 100644 src/kimchi/model/vmmemdevices.py
diff --git a/src/kimchi/control/vm/memdevices.py b/src/kimchi/control/vm/memdevices.py
new file mode 100644
index 0000000..2d96104
--- /dev/null
+++ b/src/kimchi/control/vm/memdevices.py
@@ -0,0 +1,47 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2015
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+from kimchi.control.base import Collection, Resource
+from kimchi.control.utils import UrlSubNode
+
+
+@UrlSubNode("memdevices")
+class VMMemDevices(Collection):
+ def __init__(self, model, vm):
+ super(VMMemDevices, self).__init__(model)
+ self.admin_methods = ['GET', 'POST']
+ self.resource = VMMemDevice
+ self.vm = vm
+ self.resource_args = [self.vm, ]
+ self.model_args = [self.vm, ]
+
+
+class VMMemDevice(Resource):
+ def __init__(self, model, vm, ident):
+ super(VMMemDevice, self).__init__(model, ident)
+ self.admin_methods = ['GET']
+ self.vm = vm
+ self.ident = ident
+ self.info = {}
+ self.model_args = [self.vm, self.ident]
+ self.uri_fmt = '/vms/%s/memdevices/%s'
+
+ @property
+ def data(self):
+ return self.info
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 9f169ab..7085530 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -340,4 +340,6 @@ messages = {
"KCHCPUINF0002E": _("Invalid vCPU/topology combination."),
"KCHCPUINF0003E": _("This host (or current configuration) does not
allow CPU topology."),
+ "KCHMEMDEV0001E": _("Host's libvirt version does not support
memory devices. Libvirt must be >= 1.2.14"),
+ "KCHMEMDEV0002E": _("Error attaching memory device. Details:
%(error)s"),
}
diff --git a/src/kimchi/model/vmmemdevices.py b/src/kimchi/model/vmmemdevices.py
new file mode 100644
index 0000000..c92678d
--- /dev/null
+++ b/src/kimchi/model/vmmemdevices.py
@@ -0,0 +1,94 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2015
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+from libvirt import VIR_DOMAIN_MEM_CONFIG, VIR_DOMAIN_MEM_LIVE
+from lxml import etree, objectify
+from lxml.builder import E
+
+
+from kimchi.exception import InvalidOperation, OperationFailed
+from kimchi.model.config import CapabilitiesModel
+
+
+def _get_all_memory_devices(conn, vm_name):
+ # Return all memory devices from a given guest
+ dom = conn.get().lookupByName(vm_name)
+ devs = objectify.fromstring(dom.XMLDesc(0)).devices
+ return devs.findall('memory')
+
+
+class VMMemDevicesModel(object):
+ def __init__(self, **kargs):
+ self.conn = kargs['conn']
+ self.objstore = kargs['objstore']
+ self.caps = CapabilitiesModel(**kargs)
+
+ def create(self, vm_name, params):
+ # Check if host supports memory device
+ if not self.caps.mem_hotplug_support:
+ raise InvalidOperation("KCHMEMDEV0001E")
+
+ dom = self.conn.get().lookupByName(vm_name)
+ # Setting flags, depending if machine is running or not
+ flags = VIR_DOMAIN_MEM_CONFIG
+ if dom.isActive():
+ flags = flags | VIR_DOMAIN_MEM_LIVE
+
+ # Create memory device xml
+ mem_dev_xml = etree.tostring(
+ E.memory(
+ E.target(
+ E.size('1', unit='GiB'),
+ E.node('0')),
+ model='dimm'
+ )
+ )
+ # Add chunks of 1G of memory
+ for i in range(params['amount']):
+ try:
+ dom.attachDeviceFlags(mem_dev_xml, flags)
+ except Exception as e:
+ raise OperationFailed("KCHMEMDEV0002E", {'error':
e.message})
+ return len(_get_all_memory_devices(self.conn, vm_name)) - 1
+
+ def get_list(self, vm_name):
+ # Memory devices do not have an ID or something similar in the XML, so
+ # lets return the positions of all memory devices in the XML.
+ return [str(i) for i in range(len(
+ _get_all_memory_devices(self.conn, vm_name)))]
+
+
+class VMMemDeviceModel(object):
+ def __init__(self, **kargs):
+ self.conn = kargs['conn']
+ self.objstore = kargs['objstore']
+ self.caps = CapabilitiesModel(**kargs)
+
+ def lookup(self, vm_name, dev_slot):
+ # We are considering the memory device position in the XML, which
+ # can also be considered the slot position
+ try:
+ memdev = _get_all_memory_devices(self.conn, vm_name)[int(dev_slot)]
+ return {
+ 'slot': dev_slot,
+ 'size': str(memdev.xpath('./target/size')[0] >>
20) + 'G',
+ 'node': str(memdev.xpath('./target/node')[0])
+ }
+ except IndexError:
+ return {}