diff --git a/IM/connectors/OpenStack.py b/IM/connectors/OpenStack.py index 3f8aca0fb..657010a83 100644 --- a/IM/connectors/OpenStack.py +++ b/IM/connectors/OpenStack.py @@ -117,7 +117,8 @@ def get_driver(self, auth_data): "image_url": None, "volume_url": None, "api_version": "2.0", - "domain": None} + "domain": None, + "tenant_domain_id": None} if 'username' in auth and 'password' in auth and 'tenant' in auth: username = auth['username'] @@ -161,6 +162,8 @@ def get_driver(self, auth_data): key = 'ex_force_%s' % key elif key == 'domain': key = 'ex_domain_name' + elif key == 'tenant_domain_id': + key = 'ex_tenant_domain_id' kwargs[key] = value # Workaround to OTC to enable to set service_name as None @@ -1301,6 +1304,21 @@ def finalize(self, vm, last, auth_data): success = [] msgs = [] if node: + # First try to detach the volumes and the SGs + for vol_id in vm.volumes: + try: + volume = node.driver.ex_get_volume(vol_id) + node.driver.detach_volume(volume) + except Exception as ex: + self.log_exception("Error dettaching volume %s." % vol_id) + + try: + for sg_name in self._get_security_names(vm.inf): + security_group = OpenStackSecurityGroup(None, None, sg_name, "", node.driver) + node.driver.ex_remove_security_group_from_node(security_group, node) + except Exception as ex: + self.log_exception("Error dettaching volume %s." % vol_id) + res = node.destroy() success.append(res) @@ -1358,9 +1376,9 @@ def finalize(self, vm, last, auth_data): return (all(success), "\n ".join(msgs)) - def delete_security_groups(self, driver, inf, timeout=180, delay=10): + def _get_security_names(self, inf): """ - Delete the SG of this inf + Get the list of SGs for this infra """ sg_names = ["im-%s" % inf.id] for net in inf.radl.networks: @@ -1369,6 +1387,14 @@ def delete_security_groups(self, driver, inf, timeout=180, delay=10): sg_name = "im-%s-%s" % (inf.id, net.id) sg_names.append(sg_name) + return sg_names + + def delete_security_groups(self, driver, inf, timeout=180, delay=10): + """ + Delete the SG of this inf + """ + sg_names = self._get_security_names(inf) + msg = "" deleted = True for sg_name in sg_names: diff --git a/doc/source/client.rst b/doc/source/client.rst index 957a5780a..fca142eda 100644 --- a/doc/source/client.rst +++ b/doc/source/client.rst @@ -292,6 +292,9 @@ OpenStack has a set of additional fields to access a cloud site: flow involves hitting the auth service (Keystone) with the provided username and password and requesting an authentication token. +* ``tenant_domain_id`` tenant domain id to set to the identity service. Some cloud providers require the tenant + domain id to be provided at authentication time. Others will use a default tenant domain id if none is provided. + OpenID Connect OpenStack sites ++++++++++++++++++++++++++++++ diff --git a/docker-py3/Dockerfile b/docker-py3/Dockerfile index e91f501e9..9a6cc96f6 100644 --- a/docker-py3/Dockerfile +++ b/docker-py3/Dockerfile @@ -14,8 +14,6 @@ RUN apt-get update && apt-get install --no-install-recommends -y git python3-pip pip3 install pip setuptools --upgrade && \ /usr/local/bin/pip3 install msrest msrestazure azure-common azure-mgmt-storage azure-mgmt-compute azure-mgmt-network azure-mgmt-resource azure-mgmt-dns && \ /usr/local/bin/pip3 install pyOpenSSL cheroot xmltodict pymongo ansible==2.7.16 && \ - # Install github version until the v 3.0 is released - cd /tmp && git clone https://github.com/apache/libcloud && /usr/local/bin/pip3 install /tmp/libcloud && \ /usr/local/bin/pip3 install IM==1.9.2 && \ /usr/local/bin/pip3 uninstall pip -y && \ apt-get purge -y git python3-pip && \ diff --git a/test/unit/connectors/OpenStack.py b/test/unit/connectors/OpenStack.py old mode 100755 new mode 100644 index 001590764..8874be310 --- a/test/unit/connectors/OpenStack.py +++ b/test/unit/connectors/OpenStack.py @@ -736,6 +736,11 @@ def test_60_finalize(self, sleep, get_driver): driver.ex_list_routers.return_value = [router] driver.ex_add_router_subnet.return_value = True + volume = MagicMock() + driver.ex_get_volume.return_value = volume + driver.detach_volume.return_value = True + driver.ex_remove_security_group_from_node.return_value = True + vm.volumes = ['volid'] success, _ = ost_cloud.finalize(vm, True, auth) @@ -743,6 +748,10 @@ def test_60_finalize(self, sleep, get_driver): self.assertNotIn("ERROR", self.log.getvalue(), msg="ERROR found in log: %s" % self.log.getvalue()) self.assertEqual(node.destroy.call_args_list, [call()]) + self.assertEqual(driver.detach_volume.call_args_list[0][0][0], volume) + self.assertEqual(driver.ex_remove_security_group_from_node.call_args_list[0][0][0].name, "im-infid") + self.assertEqual(driver.ex_remove_security_group_from_node.call_args_list[1][0][0].name, "im-infid-public") + self.assertEqual(driver.ex_remove_security_group_from_node.call_args_list[2][0][0].name, "im-infid-private") self.assertEqual(driver.ex_del_router_subnet.call_args_list[0][0][0], router) self.assertEqual(driver.ex_del_router_subnet.call_args_list[0][0][1].id, "subnet1") self.assertEqual(driver.ex_delete_network.call_args_list[0][0][0], net1) @@ -786,7 +795,7 @@ def test_70_create_snapshot(self, get_driver): @patch('libcloud.compute.drivers.openstack.OpenStackNodeDriver') def test_80_delete_image(self, get_driver): - auth = Authentication([{'id': 'ost', 'type': 'OpenStack', 'username': 'user', + auth = Authentication([{'id': 'ost', 'type': 'OpenStack', 'username': 'user', 'tenant_domain_id': "tdi", 'password': 'pass', 'tenant': 'tenant', 'host': 'https://server.com:5000'}]) ost_cloud = self.get_ost_cloud() @@ -802,6 +811,7 @@ def test_80_delete_image(self, get_driver): self.assertTrue(success, msg="ERROR: deleting image. %s" % msg) self.assertEqual(driver.delete_image.call_args_list, [call(image)]) + self.assertEqual(get_driver.call_args_list[0][1]["ex_tenant_domain_id"], "tdi") self.assertNotIn("ERROR", self.log.getvalue(), msg="ERROR found in log: %s" % self.log.getvalue()) def test_get_networks(self):