[Kimchi-devel] [PATCH 4/5] CDROM Management: Guest vm storage devices mockmodel and rest api test cases
Rodrigo Trujillo
rodrigo.trujillo at linux.vnet.ibm.com
Fri Feb 14 17:51:00 UTC 2014
Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo at linux.vnet.ibm.com>
On 02/14/2014 03:26 PM, Aline Manera wrote:
> From: Rodrigo Trujillo <rodrigo.trujillo at linux.vnet.ibm.com>
>
> This patch implements the mockmodel class to simulate lookup, add,
> remove, update of devices in a guest vm. Also, it adds test cases to
> test the rest API.
>
> Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo at linux.vnet.ibm.com>
>
> Minor changes/improvements based on ML feedback
> Removing hard disk tests from tests/tests_rest.py
>
> Signed-off-by: Daniel Henrique Barboza <danielhb at linux.vnet.ibm.com>
> ---
> src/kimchi/mockmodel.py | 70 ++++++++++++++++++++++++++++++++++++++++++-
> tests/test_rest.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 144 insertions(+), 1 deletion(-)
>
> diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
> index 988683f..329e17c 100644
> --- a/src/kimchi/mockmodel.py
> +++ b/src/kimchi/mockmodel.py
> @@ -28,6 +28,7 @@ import ipaddr
> import os
> import psutil
> import random
> +import string
> import time
> import uuid
>
> @@ -164,8 +165,23 @@ class MockModel(object):
> for vol in params['volumes']:
> vm.disk_paths.append({'pool': pool.name,
> 'volume': vol})
> +
> else:
> vm.disk_paths = t.fork_vm_storage(vm_uuid)
> +
> + index = 0
> + for disk in vm.disk_paths:
> + storagepath = self._mock_storagepools[disk['pool']].info['path']
> + fullpath = os.path.join(storagepath, disk['volume'])
> + dev_name = "hd" + string.ascii_lowercase[index]
> + params = {'dev': dev_name, 'path': fullpath, 'type': 'disk'}
> + vm.storagedevices[dev_name] = MockVMStorageDevice(params)
> + index += 1
> +
> + cdrom = "hd" + string.ascii_lowercase[index + 1]
> + cdrom_params = {'dev': cdrom, 'path': t_info['cdrom'], 'type': 'cdrom'}
> + vm.storagedevices[cdrom] = MockVMStorageDevice(cdrom_params)
> +
> self._mock_vms[name] = vm
> return name
>
> @@ -570,6 +586,50 @@ class MockModel(object):
> def networks_get_list(self):
> return sorted(self._mock_networks.keys())
>
> + def vmstorages_create(self, vm_name, params):
> + path = params.get('path')
> + if path.startswith('/') and not os.path.exists(path):
> + raise InvalidParameter("KCHCDROM0003E", {'value': path})
> +
> + dom = self._get_vm(vm_name)
> + dev = params.get('dev', None)
> + if dev and dev in self.vmstorages_get_list(vm_name):
> + return OperationFailed("KCHCDROM0004E", {'dev_name': dev,
> + 'vm_name': vm_name})
> + if not dev:
> + index = len(dom.storagedevices.keys()) + 1
> + params['dev'] = "hd" + string.ascii_lowercase[index]
> +
> + vmdev = MockVMStorageDevice(params)
> + dom.storagedevices[params['dev']] = vmdev
> + return params['dev']
> +
> + def vmstorages_get_list(self, vm_name):
> + dom = self._get_vm(vm_name)
> + return dom.storagedevices.keys()
> +
> + def vmstorage_lookup(self, vm_name, dev_name):
> + dom = self._get_vm(vm_name)
> + if dev_name not in self.vmstorages_get_list(vm_name):
> + raise NotFoundError("KCHCDROM0007E", {'dev_name': dev_name,
> + 'vm_name': vm_name})
> + return dom.storagedevices.get(dev_name).info
> +
> + def vmstorage_delete(self, vm_name, dev_name):
> + dom = self._get_vm(vm_name)
> + if dev_name not in self.vmstorages_get_list(vm_name):
> + raise NotFoundError("KCHCDROM0007E", {'dev_name': dev_name,
> + 'vm_name': vm_name})
> + dom.storagedevices.pop(dev_name)
> +
> + def vmstorage_update(self, vm_name, dev_name, params):
> + try:
> + dom = self._get_vm(vm_name)
> + dom.storagedevices[dev_name].info.update(params)
> + except Exception as e:
> + raise OperationFailed("KCHCDROM0009E", {'error': e.message})
> + return dev_name
> +
> def vmifaces_create(self, vm, params):
> if (params["type"] == "network" and
> params["network"] not in self.networks_get_list()):
> @@ -752,6 +812,13 @@ class MockVMTemplate(VMTemplate):
> return disk_paths
>
>
> +class MockVMStorageDevice(object):
> + def __init__(self, params):
> + self.info = {'dev': params.get('dev'),
> + 'type': params.get('type'),
> + 'path': params.get('path')}
> +
> +
> class MockVMIface(object):
> counter = 0
>
> @@ -777,6 +844,7 @@ class MockVM(object):
> self.disk_paths = []
> self.networks = template_info['networks']
> ifaces = [MockVMIface(net) for net in self.networks]
> + self.storagedevices = {}
> self.ifaces = dict([(iface.info['mac'], iface) for iface in ifaces])
> self.info = {'state': 'shutoff',
> 'stats': "{'cpu_utilization': 20, 'net_throughput' : 35, \
> @@ -898,7 +966,7 @@ def get_mock_environment():
> model = MockModel()
> for i in xrange(5):
> name = 'test-template-%i' % i
> - params = {'name': name}
> + params = {'name': name, 'cdrom': '/file.iso'}
> t = MockVMTemplate(params, model)
> model._mock_templates[name] = t
>
> diff --git a/tests/test_rest.py b/tests/test_rest.py
> index deb6fe8..37bfccf 100644
> --- a/tests/test_rest.py
> +++ b/tests/test_rest.py
> @@ -354,6 +354,81 @@ class RestTests(unittest.TestCase):
> resp = self.request('/templates/test', '{}', 'DELETE')
> self.assertEquals(204, resp.status)
>
> + def test_vm_storage_devices(self):
> +
> + with RollbackContext() as rollback:
> + # Create a template as a base for our VMs
> + req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso'})
> + resp = self.request('/templates', req, 'POST')
> + self.assertEquals(201, resp.status)
> + # Delete the template
> + rollback.prependDefer(self.request,
> + '/templates/test', '{}', 'DELETE')
> +
> + # Create a VM with default args
> + req = json.dumps({'name': 'test-vm',
> + 'template': '/templates/test'})
> + resp = self.request('/vms', req, 'POST')
> + self.assertEquals(201, resp.status)
> + # Delete the VM
> + rollback.prependDefer(self.request,
> + '/vms/test-vm', '{}', 'DELETE')
> +
> + # Check storage devices
> + resp = self.request('/vms/test-vm/storages', '{}', 'GET')
> + devices = json.loads(resp.read())
> + self.assertEquals(2, len(devices))
> + dev_types = []
> + for d in devices:
> + self.assertIn(u'type', d.keys())
> + self.assertIn(u'dev', d.keys())
> + self.assertIn(u'path', d.keys())
> + dev_types.append(d['type'])
> +
> + self.assertEquals(['cdrom', 'disk'], sorted(dev_types))
> +
> + # Attach cdrom with nonexistent iso
> + req = json.dumps({'dev': 'hdx',
> + 'type': 'cdrom',
> + 'path': '/tmp/nonexistent.iso'})
> + resp = self.request('/vms/test-vm/storages', req, 'POST')
> + self.assertEquals(400, resp.status)
> +
> + # Attach a cdrom with existent dev name
> + open('/tmp/existent.iso', 'w').close()
> + req = json.dumps({'dev': 'hdx',
> + 'type': 'cdrom',
> + 'path': '/tmp/existent.iso'})
> + resp = self.request('/vms/test-vm/storages', req, 'POST')
> + self.assertEquals(201, resp.status)
> + cd_info = json.loads(resp.read())
> + self.assertEquals('hdx', cd_info['dev'])
> + self.assertEquals('cdrom', cd_info['type'])
> + self.assertEquals('/tmp/existent.iso', cd_info['path'])
> + # Delete the file and cdrom
> + rollback.prependDefer(self.request,
> + '/vms/test-vm/storages/hdx', '{}', 'DELETE')
> + os.remove('/tmp/existent.iso')
> +
> + # Change path of storage cdrom
> + req = json.dumps({'path': 'http://myserver.com/myiso.iso'})
> + resp = self.request('/vms/test-vm/storages/hdx', req, 'PUT')
> + self.assertEquals(200, resp.status)
> + cd_info = json.loads(resp.read())
> + self.assertEquals('http://myserver.com/myiso.iso', cd_info['path'])
> +
> + # Test GET
> + devs = json.loads(self.request('/vms/test-vm/storages').read())
> + self.assertEquals(3, len(devs))
> +
> + # Detach storage cdrom
> + resp = self.request('/vms/test-vm/storages/hdx', '{}', 'DELETE')
> + self.assertEquals(204, resp.status)
> +
> + # Test GET
> + devs = json.loads(self.request('/vms/test-vm/storages').read())
> + self.assertEquals(2, len(devs))
> +
> def test_vm_iface(self):
>
> with RollbackContext() as rollback:
More information about the Kimchi-devel
mailing list