From 92ba62e26880d16036cf3ce4a9472d92d28c3536 Mon Sep 17 00:00:00 2001 From: chemistry_sourabh Date: Tue, 25 Apr 2017 00:04:05 -0400 Subject: [PATCH 1/5] Inconsistent state --- ims/database/image.py | 27 +- ims/einstein/ceph.py | 8 +- ims/einstein/hil.py | 31 ++- ims/einstein/iscsi/tgt.py | 20 +- ims/einstein/operations.py | 92 +------ ims/exception/db_exceptions.py | 14 ++ ims/exception/haas_exceptions.py | 18 ++ tests/integration/einstein/test_operations.py | 12 +- .../einstein/test_state_operations.py | 238 ++++++++++++++++++ 9 files changed, 354 insertions(+), 106 deletions(-) create mode 100644 tests/integration/einstein/test_state_operations.py diff --git a/ims/database/image.py b/ims/database/image.py index 4864716..6fc1187 100644 --- a/ims/database/image.py +++ b/ims/database/image.py @@ -1,7 +1,7 @@ from sqlalchemy import Boolean, ForeignKey from sqlalchemy import Column, Integer, String from sqlalchemy import UniqueConstraint -from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.exc import SQLAlchemyError, IntegrityError from sqlalchemy.orm import relationship import ims.exception.db_exceptions as db_exceptions @@ -37,6 +37,15 @@ def insert(self, image_name, project_id, parent_id=None, is_public=False, img.id = id self.connection.session.add(img) self.connection.session.commit() + except IntegrityError: + logger.info("Integrity Error Caused for %s in project with id %d " + "and parent id %d" % (image_name, project_id, + parent_id)) + self.connection.session.rollback() + actual_parent_id = self.fetch_parent_id_with_project_id(image_name, + project_id) + if actual_parent_id != parent_id: + raise db_exceptions.ImageExistsException(image_name) except SQLAlchemyError as e: self.connection.session.rollback() raise db_exceptions.ORMException(e.message) @@ -61,7 +70,8 @@ def delete_with_name_from_project(self, name, project_name): self.connection.session.delete(image) self.connection.session.commit() else: - raise db_exceptions.ImageNotFoundException(name) + logger.info("%s in project %s already " + "deleted" % (name, project_name)) except SQLAlchemyError as e: self.connection.session.rollback() raise db_exceptions.ORMException(e.message) @@ -230,6 +240,19 @@ def fetch_parent_id(self, project_name, name): except SQLAlchemyError as e: raise db_exceptions.ORMException(e.message) + @log + def fetch_parent_id_with_project_id(self, name, project_id): + try: + image = self.connection.session.query(Image). \ + filter_by(project_id=project_id).filter_by( + name=name).one_or_none() + if image is not None and image.parent_id is not None: + return image.parent_id + elif image is None: + raise db_exceptions.ImageNotFoundException(name) + except SQLAlchemyError as e: + raise db_exceptions.ORMException(e.message) + def fetch_images(self): try: images = self.connection.session.query(Image) diff --git a/ims/einstein/ceph.py b/ims/einstein/ceph.py index c751d25..d51ab54 100755 --- a/ims/einstein/ceph.py +++ b/ims/einstein/ceph.py @@ -108,7 +108,10 @@ def clone(self, parent_img_name, parent_snap_name, clone_img_name): img_name = parent_snap_name raise file_system_exceptions.ImageNotFoundException(img_name) except rbd.ImageExists: - raise file_system_exceptions.ImageExistsException(clone_img_name) + logger.info("Clone with name %s exists" % clone_img_name) + actual_parent = self.get_parent_info(clone_img_name)[1] + if actual_parent != parent_img_name: + raise file_system_exceptions.ImageExistsException(clone_img_name) # No Clue when will this be raised so not testing except rbd.FunctionNotSupported: raise file_system_exceptions.FunctionNotSupportedException() @@ -122,7 +125,8 @@ def remove(self, img_id): self.rbd.remove(self.context, img_id) return True except rbd.ImageNotFound: - raise file_system_exceptions.ImageNotFoundException(img_id) + logger.exception('') + # raise file_system_exceptions.ImageNotFoundException(img_id) # Don't know how to raise this except rbd.ImageBusy: raise file_system_exceptions.ImageBusyException(img_id) diff --git a/ims/einstein/hil.py b/ims/einstein/hil.py index 3374295..a70b8ea 100644 --- a/ims/einstein/hil.py +++ b/ims/einstein/hil.py @@ -57,7 +57,11 @@ def resp_parse(self, obj): raise haas_exceptions.AuthenticationFailedException() elif obj.status_code == 403: raise haas_exceptions.AuthorizationFailedException() - elif obj.status_code >= 400: + elif obj.status_code == 400: + raise haas_exceptions.NotAttachedException() + elif obj.status_code == 409: + raise haas_exceptions.AttachedException() + elif obj.status_code > 400: # For PEP8 error_msg = obj.json()[constants.MESSAGE_KEY] raise haas_exceptions.UnknownException(obj.status_code, @@ -99,9 +103,14 @@ def detach_node_from_project(self, project, node): @log def attach_node_to_project_network(self, node, network, nic): - api = '/node/' + node + '/nic/' + nic + '/connect_network' - body = {"network": network, "channel": constants.HAAS_BMI_CHANNEL} - return self.__call_rest_api_with_body(api=api, body=body) + try: + api = '/node/' + node + '/nic/' + nic + '/connect_network' + body = {"network": network, "channel": constants.HAAS_BMI_CHANNEL} + return self.__call_rest_api_with_body(api=api, body=body) + except haas_exceptions.AttachedException: + logger.info("%s is already attached to %s at %s" % (node, + network, + nic)) @log def attach_node_haas_project(self, project, node): @@ -110,11 +119,15 @@ def attach_node_haas_project(self, project, node): return self.__call_rest_api_with_body(api=api, body=body) @log - def detach_node_from_project_network(self, node, - network, nic): - api = '/node/' + node + '/nic/' + nic + '/detach_network' - body = {"network": network} - return self.__call_rest_api_with_body(api=api, body=body) + def detach_node_from_project_network(self, node, network, nic): + try: + api = '/node/' + node + '/nic/' + nic + '/detach_network' + body = {"network": network} + return self.__call_rest_api_with_body(api=api, body=body) + except haas_exceptions.NotAttachedException: + logger.info("%s is already detached to %s at %s" % (node, + network, + nic)) @log def get_node_mac_addr(self, node): diff --git a/ims/einstein/iscsi/tgt.py b/ims/einstein/iscsi/tgt.py index 08ec020..39a2acb 100644 --- a/ims/einstein/iscsi/tgt.py +++ b/ims/einstein/iscsi/tgt.py @@ -103,12 +103,11 @@ def add_target(self, target_name): """ try: targets = self.list_targets() - if target_name not in targets: - self.__generate_config_file(target_name) - command = "tgt-admin --execute" - shell.call(command, sudo=True) - else: - raise iscsi_exceptions.TargetExistsException() + if target_name in targets: + logger.info("%s target already exists" % target_name) + self.__generate_config_file(target_name) + command = "tgt-admin --execute" + shell.call(command, sudo=True) except (IOError, OSError) as e: raise iscsi_exceptions.TargetCreationFailed(str(e)) except shell_exceptions.CommandFailedException as e: @@ -132,8 +131,15 @@ def remove_target(self, target_name): logger.debug("Output = %s", output) else: raise iscsi_exceptions.TargetDoesntExistException() - except (IOError, OSError) as e: + except OSError as e: + if "[Errno 2] No such file or directory" in str(e): + logger.exception('') + else: + raise iscsi_exceptions.TargetDeletionFailed(str(e)) + except IOError as e: raise iscsi_exceptions.TargetDeletionFailed(str(e)) + except iscsi_exceptions.TargetDoesntExistException: + logger.exception('') except shell_exceptions.CommandFailedException as e: raise iscsi_exceptions.TargetDeletionFailed(str(e)) diff --git a/ims/einstein/operations.py b/ims/einstein/operations.py index c8fffeb..9cd0a75 100755 --- a/ims/einstein/operations.py +++ b/ims/einstein/operations.py @@ -1,8 +1,7 @@ #!/usr/bin/python import base64 -import time - import os +import sys import ims.common.config as config import ims.common.constants as constants @@ -15,7 +14,7 @@ from ims.einstein.iscsi.tgt import TGT from ims.exception.exception import RegistrationFailedException, \ FileSystemException, DBException, HaaSException, ISCSIException, \ - AuthorizationFailedException, DHCPException + AuthorizationFailedException, DHCPException, BMIException logger = create_logger(__name__) @@ -37,9 +36,7 @@ def __init__(self, *args): self.dhcp = DNSMasq() # self.iscsi = IET(self.fs, self.config.iscsi_update_password) # Need to make this generic by passing specific config - self.iscsi = TGT(self.cfg.fs.conf_file, - self.cfg.fs.id, - self.cfg.fs.pool) + elif args.__len__() == 3: username, password, project = args self.cfg = config.get() @@ -233,47 +230,7 @@ def provision(self, node_name, img_name, network, nic): self.__register(node_name, img_name, clone_ceph_name, mac_addr) return self.__return_success(True) - except RegistrationFailedException as e: - # Message is being handled by custom formatter - # TODO: add a deployment and a unit test for this case. - logger.exception('') - clone_ceph_name = self.__get_ceph_image_name(node_name) - self.iscsi.remove_target(clone_ceph_name) - self.fs.remove(clone_ceph_name) - self.db.image.delete_with_name_from_project(node_name, self.proj) - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.detach_node_from_project_network(node_name, network, - nic) - return self.__return_error(e) - - except ISCSIException as e: - # Message is being handled by custom formatter - logger.exception('') - clone_ceph_name = self.__get_ceph_image_name(node_name) - self.fs.remove(clone_ceph_name) - self.db.image.delete_with_name_from_project(node_name, self.proj) - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.detach_node_from_project_network(node_name, network, - nic) - return self.__return_error(e) - - except FileSystemException as e: - # Message is being handled by custom formatter - logger.exception('') - self.db.image.delete_with_name_from_project(node_name, self.proj) - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.detach_node_from_project_network(node_name, network, - nic) - return self.__return_error(e) - except DBException as e: - # Message is being handled by custom formatter - logger.exception('') - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.detach_node_from_project_network(node_name, network, - nic) - return self.__return_error(e) - except HaaSException as e: - # Message is being handled by custom formatter + except BMIException as e: logger.exception('') return self.__return_error(e) @@ -281,7 +238,6 @@ def provision(self, node_name, img_name, network, nic): # and destroying its image @log def deprovision(self, node_name, network, nic): - ceph_img_name = None try: self.hil.detach_node_from_project_network(node_name, network, nic) @@ -293,38 +249,7 @@ def deprovision(self, node_name, network, nic): logger.info("The delete command was executed successfully") ret = self.fs.remove(str(ceph_img_name).encode("utf-8")) return self.__return_success(ret) - - except FileSystemException as e: - logger.exception('') - self.iscsi.add_target(ceph_img_name) - parent_name = self.fs.get_parent_info(ceph_img_name)[1] - - parent_id = self.db.image.fetch_id_with_name_from_project( - parent_name, - self.proj) - self.db.image.insert(node_name, self.pid, parent_id, - id=self.__extract_id(ceph_img_name)) - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.attach_node_to_project_network(node_name, network, nic) - return self.__return_error(e) - except ISCSIException as e: - logger.exception('') - parent_name = self.fs.get_parent_info(ceph_img_name)[1] - parent_id = self.db.image.fetch_id_with_name_from_project( - parent_name, - self.proj) - self.db.image.insert(node_name, self.pid, parent_id, - id=self.__extract_id(ceph_img_name)) - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.attach_node_to_project_network(node_name, network, nic) - return self.__return_error(e) - except DBException as e: - logger.exception('') - time.sleep(constants.HAAS_CALL_TIMEOUT) - self.hil.attach_node_to_project_network(node_name, network, nic) - return self.__return_error(e) - except HaaSException as e: - logger.exception('') + except BMIException as e: return self.__return_error(e) # Creates snapshot for the given image with snap_name as given name @@ -529,11 +454,12 @@ def copy_image(self, img1, dest_project, img2=None): dest_pid = self.__does_project_exist(dest_project) self.db.image.copy_image(self.proj, img1, dest_pid, img2) if img2 is not None: - ceph_name = self.__get_ceph_image_name(img2, dest_project) + ceph_name = self.__get_ceph_image_name(img2) else: - ceph_name = self.__get_ceph_image_name(img1, dest_project) - self.fs.clone(self.__get_ceph_image_name(img1, self.proj), + ceph_name = self.__get_ceph_image_name(img1) + self.fs.clone(self.__get_ceph_image_name(img1), constants.DEFAULT_SNAPSHOT_NAME, ceph_name) + self.fs.flatten(ceph_name) self.fs.snap_image(ceph_name, constants.DEFAULT_SNAPSHOT_NAME) self.fs.snap_protect(ceph_name, constants.DEFAULT_SNAPSHOT_NAME) return self.__return_success(True) diff --git a/ims/exception/db_exceptions.py b/ims/exception/db_exceptions.py index 1979b68..177e919 100644 --- a/ims/exception/db_exceptions.py +++ b/ims/exception/db_exceptions.py @@ -27,6 +27,20 @@ def __str__(self): return self.name + " not found" +class ImageExistsException(DBException): + """ Should be raised when an image with the same name exists """ + + @property + def status_code(self): + return 500 + + def __init__(self, name): + self.name = name + + def __str__(self): + return self.name + " already exists" + + class ImageHasClonesException(DBException): @property def status_code(self): diff --git a/ims/exception/haas_exceptions.py b/ims/exception/haas_exceptions.py index 08d832c..371e501 100644 --- a/ims/exception/haas_exceptions.py +++ b/ims/exception/haas_exceptions.py @@ -32,6 +32,24 @@ def __str__(self): return "Couldnt connect to HaaS" +class NotAttachedException(HaaSException): + @property + def status_code(self): + return 400 + + def __str__(self): + return "Node Not Attached to Nic" + + +class AttachedException(HaaSException): + @property + def status_code(self): + return 409 + + def __str__(self): + return "Node Already Attached to Nic" + + # this exception is a wrapper for any other haas exception that may pop up class UnknownException(HaaSException): @property diff --git a/tests/integration/einstein/test_operations.py b/tests/integration/einstein/test_operations.py index 77d5c6d..8760ef1 100644 --- a/tests/integration/einstein/test_operations.py +++ b/tests/integration/einstein/test_operations.py @@ -5,6 +5,7 @@ from unittest import TestCase import ims.common.config as config + config.load() import ims.common.constants as constants @@ -32,9 +33,8 @@ class TestProvision(TestCase): - """ - Imports an image and calls provision - """ + """ Imports an image and calls provision """ + @trace def setUp(self): self.db = Database() @@ -63,6 +63,7 @@ class TestDeprovision(TestCase): """ Same as above, but calls deprovision in the test (Test is same as previous) """ + @trace def setUp(self): self.db = Database() @@ -90,6 +91,7 @@ class TestCreateSnapshot(TestCase): """ Provisions an imported image and creates snapshot """ + @trace def setUp(self): self.db = Database() @@ -132,6 +134,7 @@ class TestListSnapshots(TestCase): """ Creates snapshot like previous and calls list snapshots """ + @trace def setUp(self): self.db = Database() @@ -166,6 +169,7 @@ class TestRemoveSnapshot(TestCase): """ Snapshot is also an image in bmi, so no need to test for now """ + def setUp(self): pass @@ -180,6 +184,7 @@ class TestListImages(TestCase): """ Imports an image and calls list image """ + @trace def setUp(self): self.db = Database() @@ -206,6 +211,7 @@ class TestRemoveImage(TestCase): """ Imports an image and calls remove image """ + @trace def setUp(self): self.db = Database() diff --git a/tests/integration/einstein/test_state_operations.py b/tests/integration/einstein/test_state_operations.py new file mode 100644 index 0000000..94efff2 --- /dev/null +++ b/tests/integration/einstein/test_state_operations.py @@ -0,0 +1,238 @@ +import time +from unittest import TestCase + +import ims.common.config as config + +config.load() + +import ims.common.constants as constants +from ims.common.log import trace +from ims.database.database import Database +from ims.einstein.operations import BMI +from ims.einstein.hil import HIL +from ims.einstein.ceph import RBD +from ims.einstein.iscsi.tgt import TGT + +_cfg = config.get() + +CORRECT_HIL_USERNAME = _cfg.tests.correct_hil_username +CORRECT_HIL_PASSWORD = _cfg.tests.correct_hil_password +INCORRECT_HIL_PASSWORD = _cfg.tests.incorrect_hil_password + +NODE_NAME = _cfg.tests.node_name +NIC = _cfg.tests.nic + +PROJECT = _cfg.tests.project +NETWORK = _cfg.tests.network + +EXIST_IMG_NAME = _cfg.tests.exist_img_name +NEW_SNAP_NAME = _cfg.tests.new_snap_name +NOT_EXIST_IMG_NAME = _cfg.tests.not_exist_img_name +NOT_EXIST_SNAP_NAME = _cfg.tests.not_exist_snap_name + + +class TestProvisionHILAttached(TestCase): + """ Tries Provisioning with node already attached """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + self.hil = HIL(base_url=_cfg.net_isolator.url, + usr=CORRECT_HIL_USERNAME, + passwd=CORRECT_HIL_PASSWORD) + + self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + + def runTest(self): + response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, + NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + time.sleep(constants.HAAS_CALL_TIMEOUT) + + def tearDown(self): + self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + time.sleep(constants.HAAS_CALL_TIMEOUT) + + +class TestProvisionDBInserted(TestCase): + """ Tries provisioning with node attached and db updated """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + self.hil = HIL(base_url=_cfg.net_isolator.url, + usr=CORRECT_HIL_USERNAME, + passwd=CORRECT_HIL_PASSWORD) + + self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.db.image.insert(NODE_NAME, 1, 1) + + def runTest(self): + response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, + NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + time.sleep(constants.HAAS_CALL_TIMEOUT) + + def tearDown(self): + self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + time.sleep(constants.HAAS_CALL_TIMEOUT) + + +class TestProvisionDBWrongParent(TestCase): + """ Similar like above, but the row has a wrong parent """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + self.hil = HIL(base_url=_cfg.net_isolator.url, + usr=CORRECT_HIL_USERNAME, + passwd=CORRECT_HIL_PASSWORD) + + self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.db.image.insert(EXIST_IMG_NAME + "2", 1) + self.db.image.insert(NODE_NAME, 1, 2) + + def runTest(self): + response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, + NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 500) + time.sleep(constants.HAAS_CALL_TIMEOUT) + + def tearDown(self): + self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + time.sleep(constants.HAAS_CALL_TIMEOUT) + + +class TestProvisionCloneDone(TestCase): + """ Tries provisioning after cloning is also done """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + self.hil = HIL(base_url=_cfg.net_isolator.url, + usr=CORRECT_HIL_USERNAME, + passwd=CORRECT_HIL_PASSWORD) + + self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.db.image.insert(NODE_NAME, 1, 1) + with RBD(_cfg.fs, _cfg.iscsi.password) as fs: + fs.clone(_cfg.bmi.uid + "img1", constants.DEFAULT_SNAPSHOT_NAME, + _cfg.bmi.uid + "img2") + + def runTest(self): + response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, + NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + time.sleep(constants.HAAS_CALL_TIMEOUT) + + def tearDown(self): + self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + time.sleep(constants.HAAS_CALL_TIMEOUT) + + +class TestProvisionCloneWrongParent(TestCase): + """ Similar like above, but clone has a different parent """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + self.good_bmi.copy_image(EXIST_IMG_NAME, PROJECT, EXIST_IMG_NAME + "2") + self.hil = HIL(base_url=_cfg.net_isolator.url, + usr=CORRECT_HIL_USERNAME, + passwd=CORRECT_HIL_PASSWORD) + + self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.db.image.insert(NODE_NAME, 1, 1) + with RBD(_cfg.fs, _cfg.iscsi.password) as fs: + fs.clone(_cfg.bmi.uid + "img2", constants.DEFAULT_SNAPSHOT_NAME, + _cfg.bmi.uid + "img3") + + def runTest(self): + response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, + NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 500) + time.sleep(constants.HAAS_CALL_TIMEOUT) + + def tearDown(self): + self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.good_bmi.remove_image(EXIST_IMG_NAME + "2") + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + time.sleep(constants.HAAS_CALL_TIMEOUT) + + +class TestProvisionISCSIDone(TestCase): + """ Tries provisioning after TGT target is also created """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + self.hil = HIL(base_url=_cfg.net_isolator.url, + usr=CORRECT_HIL_USERNAME, + passwd=CORRECT_HIL_PASSWORD) + + self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.db.image.insert(NODE_NAME, 1, 1) + with RBD(_cfg.fs, _cfg.iscsi.password) as fs: + fs.clone(_cfg.bmi.uid + "img1", constants.DEFAULT_SNAPSHOT_NAME, + _cfg.bmi.uid + "img2") + self.iscsi = TGT(_cfg.fs.conf_file, + _cfg.fs.id, + _cfg.fs.pool) + self.iscsi.add_target(_cfg.bmi.uid + "img2") + + def runTest(self): + response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, + NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + time.sleep(constants.HAAS_CALL_TIMEOUT) + + def tearDown(self): + self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + time.sleep(constants.HAAS_CALL_TIMEOUT) From fbba619eb0ec4d2353b073b37ef704c9d8cb2785 Mon Sep 17 00:00:00 2001 From: chemistry_sourabh Date: Tue, 25 Apr 2017 00:12:20 -0400 Subject: [PATCH 2/5] pep8 fix --- ims/einstein/ceph.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ims/einstein/ceph.py b/ims/einstein/ceph.py index d51ab54..270f0f0 100755 --- a/ims/einstein/ceph.py +++ b/ims/einstein/ceph.py @@ -1,10 +1,10 @@ #! /bin/python +import os +import rbd import subprocess from contextlib import contextmanager -import os import rados -import rbd import sh import ims.common.constants as constants @@ -111,7 +111,8 @@ def clone(self, parent_img_name, parent_snap_name, clone_img_name): logger.info("Clone with name %s exists" % clone_img_name) actual_parent = self.get_parent_info(clone_img_name)[1] if actual_parent != parent_img_name: - raise file_system_exceptions.ImageExistsException(clone_img_name) + clone = clone_img_name # PEP8 fix + raise file_system_exceptions.ImageExistsException(clone) # No Clue when will this be raised so not testing except rbd.FunctionNotSupported: raise file_system_exceptions.FunctionNotSupportedException() From d657f07567389ec7b91795eec0d4a66095759661 Mon Sep 17 00:00:00 2001 From: chemistry_sourabh Date: Mon, 1 May 2017 21:08:03 -0400 Subject: [PATCH 3/5] Finished depro ( Need Test cases) --- ims/einstein/ceph.py | 3 +-- ims/einstein/iscsi/tgt.py | 10 ++++------ ims/einstein/operations.py | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ims/einstein/ceph.py b/ims/einstein/ceph.py index 270f0f0..c65f61c 100755 --- a/ims/einstein/ceph.py +++ b/ims/einstein/ceph.py @@ -126,8 +126,7 @@ def remove(self, img_id): self.rbd.remove(self.context, img_id) return True except rbd.ImageNotFound: - logger.exception('') - # raise file_system_exceptions.ImageNotFoundException(img_id) + logger.info("%s image is not found" % img_id) # Don't know how to raise this except rbd.ImageBusy: raise file_system_exceptions.ImageBusyException(img_id) diff --git a/ims/einstein/iscsi/tgt.py b/ims/einstein/iscsi/tgt.py index 39a2acb..f033506 100644 --- a/ims/einstein/iscsi/tgt.py +++ b/ims/einstein/iscsi/tgt.py @@ -124,22 +124,20 @@ def remove_target(self, target_name): try: targets = self.list_targets() if target_name in targets: - os.remove(os.path.join(self.TGT_ISCSI_CONFIG, - target_name + ".conf")) command = "tgt-admin -f --delete {0}".format(target_name) output = shell.call(command, sudo=True) logger.debug("Output = %s", output) + os.remove(os.path.join(self.TGT_ISCSI_CONFIG, + target_name + ".conf")) else: - raise iscsi_exceptions.TargetDoesntExistException() + logger.info("%s target doesnt exist" % target_name) except OSError as e: if "[Errno 2] No such file or directory" in str(e): - logger.exception('') + pass else: raise iscsi_exceptions.TargetDeletionFailed(str(e)) except IOError as e: raise iscsi_exceptions.TargetDeletionFailed(str(e)) - except iscsi_exceptions.TargetDoesntExistException: - logger.exception('') except shell_exceptions.CommandFailedException as e: raise iscsi_exceptions.TargetDeletionFailed(str(e)) diff --git a/ims/einstein/operations.py b/ims/einstein/operations.py index 9cd0a75..c7deacb 100755 --- a/ims/einstein/operations.py +++ b/ims/einstein/operations.py @@ -242,12 +242,12 @@ def deprovision(self, node_name, network, nic): self.hil.detach_node_from_project_network(node_name, network, nic) ceph_img_name = self.__get_ceph_image_name(node_name) - self.db.image.delete_with_name_from_project(node_name, self.proj) ceph_config = self.cfg.fs logger.debug("Contents of ceph+config = %s", str(ceph_config)) self.iscsi.remove_target(ceph_img_name) logger.info("The delete command was executed successfully") ret = self.fs.remove(str(ceph_img_name).encode("utf-8")) + self.db.image.delete_with_name_from_project(node_name, self.proj) return self.__return_success(ret) except BMIException as e: return self.__return_error(e) From abd3a6fccf79e27518128477fc8780358f1a96e2 Mon Sep 17 00:00:00 2001 From: chemistry_sourabh Date: Thu, 4 May 2017 00:31:17 -0400 Subject: [PATCH 4/5] Finished Testcases Also made them faster --- ims/einstein/ceph.py | 2 +- ims/einstein/hil.py | 20 +- tests/integration/einstein/test_operations.py | 24 +-- .../einstein/test_state_operations.py | 198 ++++++++++++++---- 4 files changed, 186 insertions(+), 58 deletions(-) diff --git a/ims/einstein/ceph.py b/ims/einstein/ceph.py index c65f61c..6782d0f 100755 --- a/ims/einstein/ceph.py +++ b/ims/einstein/ceph.py @@ -124,7 +124,6 @@ def clone(self, parent_img_name, parent_snap_name, clone_img_name): def remove(self, img_id): try: self.rbd.remove(self.context, img_id) - return True except rbd.ImageNotFound: logger.info("%s image is not found" % img_id) # Don't know how to raise this @@ -133,6 +132,7 @@ def remove(self, img_id): # Forgot to test this except rbd.ImageHasSnapshots: raise file_system_exceptions.ImageHasSnapshotException(img_id) + return True @log def write(self, img_id, data, offset): diff --git a/ims/einstein/hil.py b/ims/einstein/hil.py index a70b8ea..274cdb6 100644 --- a/ims/einstein/hil.py +++ b/ims/einstein/hil.py @@ -1,4 +1,5 @@ import json +import time import urlparse import requests @@ -6,6 +7,7 @@ import ims.common.constants as constants import ims.exception.haas_exceptions as haas_exceptions from ims.common.log import create_logger, trace, log +from ims.exception.exception import HaaSException logger = create_logger(__name__) @@ -60,7 +62,11 @@ def resp_parse(self, obj): elif obj.status_code == 400: raise haas_exceptions.NotAttachedException() elif obj.status_code == 409: - raise haas_exceptions.AttachedException() + error_msg = obj.json()[constants.MESSAGE_KEY] + if "already attached" in error_msg: + raise haas_exceptions.AttachedException() + raise haas_exceptions.UnknownException(obj.status_code, + error_msg) elif obj.status_code > 400: # For PEP8 error_msg = obj.json()[constants.MESSAGE_KEY] @@ -140,3 +146,15 @@ def get_node_mac_addr(self, node): def validate_project(self, project): api = '/project/' + project + '/nodes' return self.__call_rest_api(api=api) + + @log + def wait(self, node, network, nic, attaching=True): + while True: + try: + if attaching: + self.attach_node_to_project_network(node, network, nic) + else: + self.detach_node_from_project_network(node, network, nic) + break + except HaaSException: + time.sleep(0) diff --git a/tests/integration/einstein/test_operations.py b/tests/integration/einstein/test_operations.py index 8760ef1..069fd39 100644 --- a/tests/integration/einstein/test_operations.py +++ b/tests/integration/einstein/test_operations.py @@ -48,7 +48,7 @@ def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 200) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -56,7 +56,7 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestDeprovision(TestCase): @@ -73,18 +73,18 @@ def setUp(self): PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 200) - time.sleep(constants.HAAS_CALL_TIMEOUT) def tearDown(self): self.good_bmi.remove_image(EXIST_IMG_NAME) self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) class TestCreateSnapshot(TestCase): @@ -101,7 +101,7 @@ def setUp(self): PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.create_snapshot(NODE_NAME, NEW_SNAP_NAME) @@ -114,11 +114,9 @@ def runTest(self): has_image = True self.assertTrue(has_image) - with ceph.RBD(_cfg.fs, - _cfg.iscsi.password) as fs: - img_id = self.good_bmi.get_ceph_image_name_from_project( - NEW_SNAP_NAME, PROJECT) - fs.get_image(img_id) + img_id = self.good_bmi.get_ceph_image_name_from_project(NEW_SNAP_NAME, + PROJECT) + self.good_bmi.fs.get_image(img_id) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -127,7 +125,7 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestListSnapshots(TestCase): @@ -144,7 +142,7 @@ def setUp(self): PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) self.good_bmi.create_snapshot(NODE_NAME, NEW_SNAP_NAME) @@ -161,7 +159,7 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) @unittest.skip("Same as Remove Image") diff --git a/tests/integration/einstein/test_state_operations.py b/tests/integration/einstein/test_state_operations.py index 94efff2..259ae86 100644 --- a/tests/integration/einstein/test_state_operations.py +++ b/tests/integration/einstein/test_state_operations.py @@ -1,4 +1,4 @@ -import time +import unittest from unittest import TestCase import ims.common.config as config @@ -33,6 +33,7 @@ class TestProvisionHILAttached(TestCase): """ Tries Provisioning with node already attached """ + @trace def setUp(self): self.db = Database() @@ -46,12 +47,13 @@ def setUp(self): passwd=CORRECT_HIL_PASSWORD) self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 200) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -59,11 +61,12 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestProvisionDBInserted(TestCase): """ Tries provisioning with node attached and db updated """ + @trace def setUp(self): self.db = Database() @@ -72,18 +75,17 @@ def setUp(self): self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) - self.hil = HIL(base_url=_cfg.net_isolator.url, - usr=CORRECT_HIL_USERNAME, - passwd=CORRECT_HIL_PASSWORD) - self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.good_bmi.hil.attach_node_to_project_network(NODE_NAME, NETWORK, + NIC) self.db.image.insert(NODE_NAME, 1, 1) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 200) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -91,11 +93,12 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestProvisionDBWrongParent(TestCase): """ Similar like above, but the row has a wrong parent """ + @trace def setUp(self): self.db = Database() @@ -104,19 +107,18 @@ def setUp(self): self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) - self.hil = HIL(base_url=_cfg.net_isolator.url, - usr=CORRECT_HIL_USERNAME, - passwd=CORRECT_HIL_PASSWORD) - self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.good_bmi.hil.attach_node_to_project_network(NODE_NAME, NETWORK, + NIC) self.db.image.insert(EXIST_IMG_NAME + "2", 1) self.db.image.insert(NODE_NAME, 1, 2) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 500) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -124,11 +126,12 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestProvisionCloneDone(TestCase): """ Tries provisioning after cloning is also done """ + @trace def setUp(self): self.db = Database() @@ -137,21 +140,20 @@ def setUp(self): self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) - self.hil = HIL(base_url=_cfg.net_isolator.url, - usr=CORRECT_HIL_USERNAME, - passwd=CORRECT_HIL_PASSWORD) - self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.good_bmi.hil.attach_node_to_project_network(NODE_NAME, NETWORK, + NIC) self.db.image.insert(NODE_NAME, 1, 1) with RBD(_cfg.fs, _cfg.iscsi.password) as fs: fs.clone(_cfg.bmi.uid + "img1", constants.DEFAULT_SNAPSHOT_NAME, _cfg.bmi.uid + "img2") + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 200) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -159,11 +161,12 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestProvisionCloneWrongParent(TestCase): """ Similar like above, but clone has a different parent """ + @trace def setUp(self): self.db = Database() @@ -173,21 +176,20 @@ def setUp(self): PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) self.good_bmi.copy_image(EXIST_IMG_NAME, PROJECT, EXIST_IMG_NAME + "2") - self.hil = HIL(base_url=_cfg.net_isolator.url, - usr=CORRECT_HIL_USERNAME, - passwd=CORRECT_HIL_PASSWORD) - self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.good_bmi.hil.attach_node_to_project_network(NODE_NAME, NETWORK, + NIC) self.db.image.insert(NODE_NAME, 1, 1) - with RBD(_cfg.fs, _cfg.iscsi.password) as fs: - fs.clone(_cfg.bmi.uid + "img2", constants.DEFAULT_SNAPSHOT_NAME, - _cfg.bmi.uid + "img3") + self.good_bmi.fs.clone(_cfg.bmi.uid + "img2", + constants.DEFAULT_SNAPSHOT_NAME, + _cfg.bmi.uid + "img3") + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 500) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -196,11 +198,12 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) class TestProvisionISCSIDone(TestCase): """ Tries provisioning after TGT target is also created """ + @trace def setUp(self): self.db = Database() @@ -209,25 +212,22 @@ def setUp(self): self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, PROJECT) self.good_bmi.import_ceph_image(EXIST_IMG_NAME) - self.hil = HIL(base_url=_cfg.net_isolator.url, - usr=CORRECT_HIL_USERNAME, - passwd=CORRECT_HIL_PASSWORD) - self.hil.attach_node_to_project_network(NODE_NAME, NETWORK, NIC) + self.good_bmi.hil.attach_node_to_project_network(NODE_NAME, NETWORK, + NIC) self.db.image.insert(NODE_NAME, 1, 1) - with RBD(_cfg.fs, _cfg.iscsi.password) as fs: - fs.clone(_cfg.bmi.uid + "img1", constants.DEFAULT_SNAPSHOT_NAME, - _cfg.bmi.uid + "img2") - self.iscsi = TGT(_cfg.fs.conf_file, - _cfg.fs.id, - _cfg.fs.pool) - self.iscsi.add_target(_cfg.bmi.uid + "img2") + + self.good_bmi.fs.clone(_cfg.bmi.uid + "img1", + constants.DEFAULT_SNAPSHOT_NAME, + _cfg.bmi.uid + "img2") + self.good_bmi.iscsi.add_target(_cfg.bmi.uid + "img2") + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def runTest(self): response = self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) self.assertEqual(response[constants.STATUS_CODE_KEY], 200) - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) def tearDown(self): self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) @@ -235,4 +235,116 @@ def tearDown(self): self.db.project.delete_with_name(PROJECT) self.db.close() self.good_bmi.shutdown() - time.sleep(constants.HAAS_CALL_TIMEOUT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) + + +class TestDeprovisionHILDetached(TestCase): + """ Tries Deprovisioning after node is detached """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + + self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) + self.good_bmi.hil.detach_node_from_project_network(NODE_NAME, NETWORK, + NIC) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) + + def runTest(self): + response = self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + + def tearDown(self): + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) + + +class TestDeprovisionDBDeleted(TestCase): + """ Tries Deprovisioning after db is deleted """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + + self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) + self.db.image.delete_with_name_from_project(NODE_NAME, PROJECT) + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) + + def runTest(self): + response = self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 404) + + def tearDown(self): + self.good_bmi.iscsi.remove_target(_cfg.bmi.uid + "img2") + self.good_bmi.fs.remove(_cfg.bmi.uid + "img2") + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) + + +class TestDeprovisionISCSIDeleted(TestCase): + """ Tries Deprovisioning after target is removed """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + + self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) + self.good_bmi.iscsi.remove_target(_cfg.bmi.uid + "img2") + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) + + def runTest(self): + response = self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + + def tearDown(self): + self.good_bmi.remove_image(EXIST_IMG_NAME) + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) + + +class TestDeprovisionCephDeleted(TestCase): + """ Tries Deprovisioning after clone is removed """ + @trace + def setUp(self): + self.db = Database() + self.db.project.insert(PROJECT, NETWORK) + + self.good_bmi = BMI(CORRECT_HIL_USERNAME, CORRECT_HIL_PASSWORD, + PROJECT) + self.good_bmi.import_ceph_image(EXIST_IMG_NAME) + + self.good_bmi.provision(NODE_NAME, EXIST_IMG_NAME, NETWORK, NIC) + self.good_bmi.iscsi.remove_target(_cfg.bmi.uid + "img2") + self.good_bmi.fs.remove(_cfg.bmi.uid + "img2") + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC) + + def runTest(self): + response = self.good_bmi.deprovision(NODE_NAME, NETWORK, NIC) + self.assertEqual(response[constants.STATUS_CODE_KEY], 200) + + def tearDown(self): + self.db.project.delete_with_name(PROJECT) + self.db.close() + self.good_bmi.shutdown() + self.good_bmi.hil.wait(NODE_NAME, NETWORK, NIC, False) From 57b2ed3c314756245174588ed2334ff114eb0fac Mon Sep 17 00:00:00 2001 From: chemistry_sourabh Date: Mon, 15 May 2017 01:46:46 -0400 Subject: [PATCH 5/5] fixes to hil logs and wait For --- ims/einstein/hil.py | 2 +- ims/einstein/operations.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ims/einstein/hil.py b/ims/einstein/hil.py index 274cdb6..3ada997 100644 --- a/ims/einstein/hil.py +++ b/ims/einstein/hil.py @@ -156,5 +156,5 @@ def wait(self, node, network, nic, attaching=True): else: self.detach_node_from_project_network(node, network, nic) break - except HaaSException: + except haas_exceptions.UnknownException: time.sleep(0) diff --git a/ims/einstein/operations.py b/ims/einstein/operations.py index c7deacb..9380beb 100755 --- a/ims/einstein/operations.py +++ b/ims/einstein/operations.py @@ -250,6 +250,7 @@ def deprovision(self, node_name, network, nic): self.db.image.delete_with_name_from_project(node_name, self.proj) return self.__return_success(ret) except BMIException as e: + logger.exception('') return self.__return_error(e) # Creates snapshot for the given image with snap_name as given name