From 627e9b2474b51444d3d651c62464afa0b40a0379 Mon Sep 17 00:00:00 2001 From: Dennis Dmitriev Date: Thu, 25 Jun 2015 17:50:50 +0300 Subject: [PATCH] Add test 'check_ceph_cinder_cow' for ceph. Cinder and Glance should use Ceph for this test. Test creates RAW image and make a volume from it. Volume should have a parent if copy-on-write used by Cinder. - use OpenStackActions.create_image() instead of Common.image_import() Change-Id: I136aa29abef492971c5be7ae732cd42f5c7f77bc Closes-Bug:#1379543 --- fuelweb_test/helpers/ceph.py | 11 +++++++ fuelweb_test/helpers/common.py | 12 ------- fuelweb_test/helpers/os_actions.py | 12 +++++-- fuelweb_test/requirements.txt | 1 + fuelweb_test/tests/test_ceph.py | 50 ++++++++++++++++++++++++++++- fuelweb_test/tests/test_services.py | 38 +++++++++++++--------- 6 files changed, 92 insertions(+), 32 deletions(-) diff --git a/fuelweb_test/helpers/ceph.py b/fuelweb_test/helpers/ceph.py index 5bd854118..a55a3c82b 100644 --- a/fuelweb_test/helpers/ceph.py +++ b/fuelweb_test/helpers/ceph.py @@ -221,3 +221,14 @@ def get_osd_ids(remote): logger.debug("Fetching Ceph OSD ids") cmd = 'ceph osd ls -f json' return run_on_remote(remote, cmd, jsonify=True) + + +def get_rbd_images_list(remote, pool): + """Returns all OSD ids. + + :param remote: devops.helpers.helpers.SSHClient + :param pool: string, can be: 'images', 'volumes', etc. + :return: JSON-like object + """ + cmd = 'rbd --pool {pool} --format json ls -l'.format(pool=pool) + return run_on_remote(remote, cmd, jsonify=True) diff --git a/fuelweb_test/helpers/common.py b/fuelweb_test/helpers/common.py index ebf9e2e9e..1ce17b807 100644 --- a/fuelweb_test/helpers/common.py +++ b/fuelweb_test/helpers/common.py @@ -72,18 +72,6 @@ class Common(object): from_port=-1, to_port=-1) - def image_import(self, local_path, image, image_name, properties=None): - LOGGER.debug('Import image {0}/{1} to glance'. - format(local_path, image)) - with open('{0}/{1}'.format(local_path, image)) as fimage: - LOGGER.debug('Try to open image') - image = self.glance.images.create( - name=image_name, is_public=True, - disk_format='qcow2', - container_format='bare', data=fimage, - properties=properties) - return image - def update_image(self, image, **kwargs): self.glance.images.update(image.id, **kwargs) return self.glance.images.get(image.id) diff --git a/fuelweb_test/helpers/os_actions.py b/fuelweb_test/helpers/os_actions.py index 37de95da8..4616e5d7b 100644 --- a/fuelweb_test/helpers/os_actions.py +++ b/fuelweb_test/helpers/os_actions.py @@ -192,12 +192,13 @@ class OpenStackActions(common.Common): server = self.get_instance_detail(server.id) return server - def create_volume(self, size=1): - volume = self.cinder.volumes.create(size) + def create_volume(self, size=1, image_id=None): + volume = self.cinder.volumes.create(size=size, imageRef=image_id) helpers.wait( lambda: self.cinder.volumes.get(volume.id).status == "available", timeout=100) - logger.info("Created volume") + logger.info("Created volume: '{0}', parent image: '{1}'" + .format(volume.id, image_id)) return self.cinder.volumes.get(volume.id) def delete_volume(self, volume): @@ -345,6 +346,11 @@ class OpenStackActions(common.Common): return router return None + def create_image(self, **kwargs): + image = self.glance.images.create(**kwargs) + logger.info("Created image: '{0}'".format(image.id)) + return self.glance.images.get(image.id) + def get_image_list(self): return self.glance.images.list() diff --git a/fuelweb_test/requirements.txt b/fuelweb_test/requirements.txt index 0dc3049d7..7e0971490 100644 --- a/fuelweb_test/requirements.txt +++ b/fuelweb_test/requirements.txt @@ -10,6 +10,7 @@ python-keystoneclient>=0.3.2 python-novaclient>=2.15.0 python-cinderclient>=1.0.5 python-neutronclient>=2.0 +six Jinja2 AllPairs==2.0.1 launchpadlib diff --git a/fuelweb_test/tests/test_ceph.py b/fuelweb_test/tests/test_ceph.py index ffb34da7c..42ab48a92 100644 --- a/fuelweb_test/tests/test_ceph.py +++ b/fuelweb_test/tests/test_ceph.py @@ -13,6 +13,7 @@ # under the License. import proboscis +from six import BytesIO import time from proboscis.asserts import assert_true, assert_false, assert_equal @@ -22,6 +23,7 @@ from devops.helpers.helpers import tcp_ping from devops.helpers.helpers import wait from fuelweb_test.helpers import os_actions +from fuelweb_test.helpers import ceph from fuelweb_test.helpers import checkers from fuelweb_test.helpers.decorators import log_snapshot_after_test from fuelweb_test import ostf_test_mapping as map_ostf @@ -55,6 +57,7 @@ class CephCompact(TestBasic): Duration 35m Snapshot ceph_ha_one_controller_compact """ + self.check_run('ceph_ha_one_controller_compact') self.env.revert_snapshot("ready_with_3_slaves") data = { 'volumes_ceph': True, @@ -87,7 +90,52 @@ class CephCompact(TestBasic): # Run ostf self.fuel_web.run_ostf(cluster_id=cluster_id) - self.env.make_snapshot("ceph_ha_one_controller_compact") + self.env.make_snapshot("ceph_ha_one_controller_compact", is_make=True) + + @test(depends_on=[ceph_ha_one_controller_compact], + groups=["check_ceph_cinder_cow"]) + @log_snapshot_after_test + def check_ceph_cinder_cow(self): + """Check copy-on-write when Cinder creates a volume from Glance image + + Scenario: + 1. Revert a snapshot where ceph enabled for volumes and images: + "ceph_ha_one_controller_compact" + 2. Create a Glance image in RAW disk format + 3. Create a Cinder volume using Glance image in RAW disk format + 4. Check on a ceph-osd node if the volume has a parent image. + + Duration 5m + """ + self.env.revert_snapshot("ceph_ha_one_controller_compact") + cluster_id = self.fuel_web.get_last_created_cluster() + os_conn = os_actions.OpenStackActions( + self.fuel_web.get_public_vip(cluster_id), 'ceph1', 'ceph1', + 'ceph1') + + image_data = BytesIO(bytearray(self.__class__.__name__)) + image = os_conn.create_image(disk_format='raw', + container_format='bare', + data=image_data) + volume = os_conn.create_volume(size=1, image_id=image.id) + + remote = self.fuel_web.get_ssh_for_node('slave-01') + rbd_list = ceph.get_rbd_images_list(remote, 'volumes') + + for item in rbd_list: + if volume.id in item['image']: + assert_true('parent' in item, + "Volume {0} created from image {1} doesn't have" + " parents. Copy-on-write feature doesn't work." + .format(volume.id, image.id)) + assert_true(image.id in item['parent']['image'], + "Volume {0} created from image {1}, but have a " + "different image in parent: {2}" + .format(volume.id, image.id, + item['parent']['image'])) + break + else: + raise Exception("Volume {0} not found!".format(volume.id)) @test(groups=["thread_3", "ceph"]) diff --git a/fuelweb_test/tests/test_services.py b/fuelweb_test/tests/test_services.py index 92060397d..1011fe8e5 100644 --- a/fuelweb_test/tests/test_services.py +++ b/fuelweb_test/tests/test_services.py @@ -20,7 +20,6 @@ from proboscis import test from proboscis.asserts import assert_equal from fuelweb_test.helpers import checkers -from fuelweb_test.helpers.common import Common from fuelweb_test.helpers.decorators import log_snapshot_after_test from fuelweb_test.helpers import os_actions from fuelweb_test import settings @@ -111,14 +110,17 @@ class SaharaHAOneController(TestBasic): ) LOGGER.debug('Import Vanilla2 image for Sahara') - common_func = Common( - self.fuel_web.get_public_vip(cluster_id), - data['user'], data['password'], data['tenant']) - common_func.image_import( - settings.SERVTEST_LOCAL_PATH, - settings.SERVTEST_SAHARA_VANILLA_2_IMAGE, - settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_NAME, - settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_META) + + with open('{0}/{1}'.format( + settings.SERVTEST_LOCAL_PATH, + settings.SERVTEST_SAHARA_VANILLA_2_IMAGE)) as data: + os_conn.create_image( + name=settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_NAME, + properties=settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_META, + data=data, + is_public=True, + disk_format='qcow2', + container_format='bare') path_to_tests = 'fuel_health.tests.tests_platform.test_sahara.' test_names = ['VanillaTwoClusterTest.test_vanilla_two_cluster'] @@ -217,13 +219,17 @@ class SaharaHA(TestBasic): ) LOGGER.debug('Import Vanilla2 image for Sahara') - common_func = Common(cluster_vip, - data['user'], data['password'], data['tenant']) - common_func.image_import( - settings.SERVTEST_LOCAL_PATH, - settings.SERVTEST_SAHARA_VANILLA_2_IMAGE, - settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_NAME, - settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_META) + + with open('{0}/{1}'.format( + settings.SERVTEST_LOCAL_PATH, + settings.SERVTEST_SAHARA_VANILLA_2_IMAGE)) as data: + os_conn.create_image( + name=settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_NAME, + properties=settings.SERVTEST_SAHARA_VANILLA_2_IMAGE_META, + data=data, + is_public=True, + disk_format='qcow2', + container_format='bare') path_to_tests = 'fuel_health.tests.tests_platform.test_sahara.' test_names = ['VanillaTwoClusterTest.test_vanilla_two_cluster']