def _do_volume_test(self, model, host, ssl_port, pool_name): def _task_lookup(taskid): return json.loads( self.request('/plugins/kimchi/tasks/%s' % taskid).read() ) uri = '/plugins/kimchi/storagepools/%s/storagevolumes' \ % pool_name.encode('utf-8') resp = self.request(uri) self.assertEquals(200, resp.status) resp = self.request('/plugins/kimchi/storagepools/%s' % pool_name.encode('utf-8')) pool_info = json.loads(resp.read()) with RollbackContext() as rollback: # Create storage volume with 'capacity' vol = 'test-volume' vol_uri = uri + '/' + vol req = json.dumps({'name': vol, 'format': 'raw', 'capacity': 1073741824}) # 1 GiB resp = self.request(uri, req, 'POST') if pool_info['type'] in READONLY_POOL_TYPE: self.assertEquals(400, resp.status) else: rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, pool_name, vol) self.assertEquals(202, resp.status) task_id = json.loads(resp.read())['id'] wait_task(_task_lookup, task_id) status = json.loads( self.request('/plugins/kimchi/tasks/%s' % task_id).read() ) self.assertEquals('finished', status['status']) vol_info = json.loads(self.request(vol_uri).read()) vol_info['name'] = vol vol_info['format'] = 'raw' vol_info['capacity'] = 1073741824 # Resize the storage volume: increase its capacity to 2 GiB req = json.dumps({'size': 2147483648}) # 2 GiB resp = self.request(vol_uri + '/resize', req, 'POST') self.assertEquals(200, resp.status) storagevolume = json.loads(self.request(vol_uri).read()) self.assertEquals(2147483648, storagevolume['capacity']) # Resize the storage volume: decrease its capacity to 512 MiB # This test case may fail if libvirt does not include the fix for # https://bugzilla.redhat.com/show_bug.cgi?id=1021802 req = json.dumps({'size': 536870912}) # 512 MiB resp = self.request(vol_uri + '/resize', req, 'POST') self.assertEquals(200, resp.status) storagevolume = json.loads(self.request(vol_uri).read()) self.assertEquals(536870912, storagevolume['capacity']) # Wipe the storage volume resp = self.request(vol_uri + '/wipe', '{}', 'POST') self.assertEquals(200, resp.status) storagevolume = json.loads(self.request(vol_uri).read()) self.assertEquals(0, storagevolume['allocation']) # Clone the storage volume vol_info = json.loads(self.request(vol_uri).read()) resp = self.request(vol_uri + '/clone', '{}', 'POST') self.assertEquals(202, resp.status) task = json.loads(resp.read()) cloned_vol_name = task['target_uri'].split('/')[-2] rollback.prependDefer(model.storagevolume_delete, pool_name, cloned_vol_name) wait_task(_task_lookup, task['id']) task = json.loads( self.request('/plugins/kimchi/tasks/%s' % task['id']).read() ) self.assertEquals('finished', task['status']) resp = self.request(uri + '/' + cloned_vol_name.encode('utf-8')) self.assertEquals(200, resp.status) cloned_vol = json.loads(resp.read()) self.assertNotEquals(vol_info['name'], cloned_vol['name']) self.assertNotEquals(vol_info['path'], cloned_vol['path']) for key in ['name', 'path', 'allocation']: del vol_info[key] del cloned_vol[key] self.assertEquals(vol_info, cloned_vol) # Delete the storage volume resp = self.request(vol_uri, '{}', 'DELETE') self.assertEquals(204, resp.status) resp = self.request(vol_uri) self.assertEquals(404, resp.status) # Storage volume upload # It is done through a sequence of POST and several PUT requests filename = 'COPYING.LGPL' filepath = os.path.join(paths.get_prefix(), filename) filesize = os.stat(filepath).st_size # Create storage volume for upload req = json.dumps({'name': filename, 'format': 'raw', 'capacity': filesize, 'upload': True}) resp = self.request(uri, req, 'POST') if pool_info['type'] in READONLY_POOL_TYPE: self.assertEquals(400, resp.status) else: rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, pool_name, filename) self.assertEquals(202, resp.status) task_id = json.loads(resp.read())['id'] wait_task(_task_lookup, task_id) status = json.loads(self.request('/plugins/kimchi/tasks/%s' % task_id).read()) self.assertEquals('ready for upload', status['message']) # Upload volume content url = 'https://%s:%s' % (host, ssl_port) + uri + '/' + filename # Create a file with 5M to upload # Max body size is set to 4M so the upload will fail with 413 newfile = '/tmp/5m-file' with open(newfile, 'wb') as fd: fd.seek(5*1024*1024-1) fd.write("\0") rollback.prependDefer(os.remove, newfile) with open(newfile, 'rb') as fd: with open(newfile + '.tmp', 'wb') as tmp_fd: data = fd.read() tmp_fd.write(data) with open(newfile + '.tmp', 'rb') as tmp_fd: r = requests.put(url, data={'chunk_size': len(data)}, files={'chunk': tmp_fd}, verify=False, headers=fake_auth_header()) self.assertEquals(r.status_code, 413) # Do upload index = 0 chunk_size = 2 * 1024 content = '' with open(filepath, 'rb') as fd: while True: with open(filepath + '.tmp', 'wb') as tmp_fd: fd.seek(index*chunk_size) data = fd.read(chunk_size) tmp_fd.write(data) with open(filepath + '.tmp', 'rb') as tmp_fd: r = requests.put(url, data={'chunk_size': len(data)}, files={'chunk': tmp_fd}, verify=False, headers=fake_auth_header()) self.assertEquals(r.status_code, 200) content += data index = index + 1 if len(data) < chunk_size: break rollback.prependDefer(os.remove, filepath + '.tmp') resp = self.request(uri + '/' + filename) self.assertEquals(200, resp.status) uploaded_path = json.loads(resp.read())['path'] with open(uploaded_path) as fd: uploaded_content = fd.read() self.assertEquals(content, uploaded_content) # Create storage volume with 'url' url = 'https://github.com/kimchi-project/kimchi/raw/master/COPYING' req = json.dumps({'url': url}) resp = self.request(uri, req, 'POST') if pool_info['type'] in READONLY_POOL_TYPE: self.assertEquals(400, resp.status) else: rollback.prependDefer(model.storagevolume_delete, pool_name, 'COPYING') self.assertEquals(202, resp.status) task = json.loads(resp.read()) wait_task(_task_lookup, task['id']) resp = self.request(uri + '/COPYING') self.assertEquals(200, resp.status)
def _do_volume_test(self, model, host, ssl_port, pool_name): def _task_lookup(taskid): return json.loads( self.request('/plugins/kimchi/tasks/%s' % taskid).read()) uri = '/plugins/kimchi/storagepools/%s/storagevolumes' \ % pool_name.encode('utf-8') resp = self.request(uri) self.assertEquals(200, resp.status) resp = self.request('/plugins/kimchi/storagepools/%s' % pool_name.encode('utf-8')) pool_info = json.loads(resp.read()) with RollbackContext() as rollback: # Create storage volume with 'capacity' vol = 'test-volume' vol_uri = uri + '/' + vol req = json.dumps({ 'name': vol, 'format': 'raw', 'capacity': 1073741824 }) # 1 GiB resp = self.request(uri, req, 'POST') if pool_info['type'] in READONLY_POOL_TYPE: self.assertEquals(400, resp.status) else: rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, pool_name, vol) self.assertEquals(202, resp.status) task_id = json.loads(resp.read())['id'] wait_task(_task_lookup, task_id) status = json.loads( self.request('/plugins/kimchi/tasks/%s' % task_id).read()) self.assertEquals('finished', status['status']) vol_info = json.loads(self.request(vol_uri).read()) vol_info['name'] = vol vol_info['format'] = 'raw' vol_info['capacity'] = 1073741824 # Resize the storage volume: increase its capacity to 2 GiB req = json.dumps({'size': 2147483648}) # 2 GiB resp = self.request(vol_uri + '/resize', req, 'POST') self.assertEquals(200, resp.status) storagevolume = json.loads(self.request(vol_uri).read()) self.assertEquals(2147483648, storagevolume['capacity']) # Resize the storage volume: decrease its capacity to 512 MiB # This test case may fail if libvirt does not include the fix for # https://bugzilla.redhat.com/show_bug.cgi?id=1021802 req = json.dumps({'size': 536870912}) # 512 MiB resp = self.request(vol_uri + '/resize', req, 'POST') self.assertEquals(200, resp.status) storagevolume = json.loads(self.request(vol_uri).read()) self.assertEquals(536870912, storagevolume['capacity']) # Wipe the storage volume resp = self.request(vol_uri + '/wipe', '{}', 'POST') self.assertEquals(200, resp.status) storagevolume = json.loads(self.request(vol_uri).read()) self.assertEquals(0, storagevolume['allocation']) # Clone the storage volume vol_info = json.loads(self.request(vol_uri).read()) resp = self.request(vol_uri + '/clone', '{}', 'POST') self.assertEquals(202, resp.status) task = json.loads(resp.read()) cloned_vol_name = task['target_uri'].split('/')[-1] rollback.prependDefer(model.storagevolume_delete, pool_name, cloned_vol_name) wait_task(_task_lookup, task['id']) task = json.loads( self.request('/plugins/kimchi/tasks/%s' % task['id']).read()) self.assertEquals('finished', task['status']) resp = self.request(uri + '/' + cloned_vol_name.encode('utf-8')) self.assertEquals(200, resp.status) cloned_vol = json.loads(resp.read()) self.assertNotEquals(vol_info['name'], cloned_vol['name']) self.assertNotEquals(vol_info['path'], cloned_vol['path']) for key in ['name', 'path', 'allocation']: del vol_info[key] del cloned_vol[key] self.assertEquals(vol_info, cloned_vol) # Delete the storage volume resp = self.request(vol_uri, '{}', 'DELETE') self.assertEquals(204, resp.status) resp = self.request(vol_uri) self.assertEquals(404, resp.status) # Storage volume upload # It is done through a sequence of POST and several PUT requests filename = 'COPYING.LGPL' filepath = os.path.join(paths.get_prefix(), filename) filesize = os.stat(filepath).st_size # Create storage volume for upload req = json.dumps({ 'name': filename, 'format': 'raw', 'capacity': filesize, 'upload': True }) resp = self.request(uri, req, 'POST') if pool_info['type'] in READONLY_POOL_TYPE: self.assertEquals(400, resp.status) else: rollback.prependDefer(rollback_wrapper, model.storagevolume_delete, pool_name, filename) self.assertEquals(202, resp.status) task_id = json.loads(resp.read())['id'] wait_task(_task_lookup, task_id) status = json.loads( self.request('/plugins/kimchi/tasks/%s' % task_id).read()) self.assertEquals('ready for upload', status['message']) # Upload volume content url = 'https://%s:%s' % (host, ssl_port) + uri + '/' + filename # Create a file with 5M to upload # Max body size is set to 4M so the upload will fail with 413 newfile = '/tmp/5m-file' with open(newfile, 'wb') as fd: fd.seek(5 * 1024 * 1024 - 1) fd.write("\0") rollback.prependDefer(os.remove, newfile) with open(newfile, 'rb') as fd: with open(newfile + '.tmp', 'wb') as tmp_fd: data = fd.read() tmp_fd.write(data) with open(newfile + '.tmp', 'rb') as tmp_fd: r = requests.put(url, data={'chunk_size': len(data)}, files={'chunk': tmp_fd}, verify=False, headers=fake_auth_header()) self.assertEquals(r.status_code, 413) # Do upload index = 0 chunk_size = 2 * 1024 content = '' with open(filepath, 'rb') as fd: while True: with open(filepath + '.tmp', 'wb') as tmp_fd: fd.seek(index * chunk_size) data = fd.read(chunk_size) tmp_fd.write(data) with open(filepath + '.tmp', 'rb') as tmp_fd: r = requests.put(url, data={'chunk_size': len(data)}, files={'chunk': tmp_fd}, verify=False, headers=fake_auth_header()) self.assertEquals(r.status_code, 200) content += data index = index + 1 if len(data) < chunk_size: break rollback.prependDefer(os.remove, filepath + '.tmp') resp = self.request(uri + '/' + filename) self.assertEquals(200, resp.status) uploaded_path = json.loads(resp.read())['path'] with open(uploaded_path) as fd: uploaded_content = fd.read() self.assertEquals(content, uploaded_content) # Create storage volume with 'url' url = 'https://github.com/kimchi-project/kimchi/raw/master/COPYING' req = json.dumps({'url': url}) resp = self.request(uri, req, 'POST') if pool_info['type'] in READONLY_POOL_TYPE: self.assertEquals(400, resp.status) else: rollback.prependDefer(model.storagevolume_delete, pool_name, 'COPYING') self.assertEquals(202, resp.status) task = json.loads(resp.read()) wait_task(_task_lookup, task['id']) resp = self.request(uri + '/COPYING') self.assertEquals(200, resp.status)