From 330562a93b6fc15ea5f0cb327fbf1320b050e0f1 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Thu, 26 Sep 2024 16:45:21 +0200 Subject: [PATCH] Implements #1611 in OST --- IM/connectors/OpenStack.py | 101 +++++++++++++++++++++++------- test/unit/connectors/OpenStack.py | 46 ++++++++++++++ 2 files changed, 126 insertions(+), 21 deletions(-) diff --git a/IM/connectors/OpenStack.py b/IM/connectors/OpenStack.py index 1b58635c..c3d38fb9 100644 --- a/IM/connectors/OpenStack.py +++ b/IM/connectors/OpenStack.py @@ -1653,6 +1653,24 @@ def _get_security_group(self, driver, sg_name): self.log_exception("Error getting security groups.") return None + def add_security_group_rules(self, driver, outports, sg): + """Add the security group rules to the security group""" + for outport in outports: + if outport.is_range(): + to_port = outport.get_port_end() + from_port = outport.get_port_init() + else: + to_port = from_port = outport.get_remote_port() + + try: + driver.ex_create_security_group_rule(sg, outport.get_protocol(), + from_port, to_port, + outport.get_remote_cidr()) + except Exception as ex: + self.log_warn("Exception adding SG rules: %s" % get_ex_error(ex)) + self.error_messages += ("Exception adding port range: %s-%s to SG rules.\n" % + (from_port, to_port)) + def create_security_groups(self, driver, inf, radl): res = [] system = radl.systems[0] @@ -1709,27 +1727,7 @@ def create_security_groups(self, driver, inf, radl): if network.isPublic() or network.getValue("proxy_host"): outports = self.add_ssh_port(outports) - for outport in outports: - if outport.is_range(): - try: - driver.ex_create_security_group_rule(sg, outport.get_protocol(), - outport.get_port_init(), - outport.get_port_end(), - outport.get_remote_cidr()) - except Exception as ex: - self.log_warn("Exception adding SG rules: %s" % get_ex_error(ex)) - self.error_messages += ("Exception adding port range: %s-%s to SG rules.\n" % - (outport.get_port_init(), outport.get_port_end())) - else: - try: - driver.ex_create_security_group_rule(sg, outport.get_protocol(), - outport.get_remote_port(), - outport.get_remote_port(), - outport.get_remote_cidr()) - except Exception as ex: - self.log_warn("Exception adding SG rules: %s" % get_ex_error(ex)) - self.error_messages += ("Exception adding port %s to SG rules.\n" % - outport.get_remote_port()) + self.add_security_group_rules(driver, outports, sg) return res @@ -1958,6 +1956,67 @@ def alterVM(self, vm, radl, auth_data): if not success: return (success, msg) + success, msg = self.alter_security_groups(vm, radl, auth_data) + if not success: + return (success, msg) + + return (True, "") + + def alter_security_groups(self, vm, radl, auth_data): + driver = self.get_driver(auth_data) + + # First check if the node is "routed" + for network in radl.networks: + if network.getValue('router'): + self.log_info("Network has a router set. Skip SG rules modification.") + return (True, "") + + for network in radl.networks: + outports = network.getOutPorts() or [] + + old_network = vm.info.get_network_by_id(network.id) + old_outports = [] + if old_network: + old_outports = old_network.getOutPorts() or [] + + if old_outports == outports: + self.log_debug("No changes in the SG rules for network %s." % network.id) + break + + # open always SSH port on public nets or private with proxy host + if old_network and old_network.isPublic() or old_network.getValue("proxy_host"): + old_outports = self.add_ssh_port(old_outports) + if network.isPublic() or network.getValue("proxy_host"): + outports = self.add_ssh_port(outports) + + sg_name = network.getValue("sg_name") + if not sg_name: + sg_name = "im-%s-%s" % (str(vm.inf.id), network.id) + + sg = self._get_security_group(driver, sg_name) + if not sg: + self.log_error("Error updating security group: %s. It does not exist." % sg_name) + break + + # Delete old SG rules + for rule in sg.rules: + # For each rule in the SG, check if it is in the old_outports and remove it + for outport in old_outports: + protocol = outport.get_protocol() + if outport.is_range(): + to_port = outport.get_port_end() + from_port = outport.get_port_init() + else: + to_port = from_port = outport.get_remote_port() + if rule.from_port == from_port and rule.to_port == to_port and rule.ip_protocol == protocol: + try: + driver.ex_delete_security_group_rule(rule) + except Exception as ex: + self.log_warn("Exception removing old SG rules: %s" % get_ex_error(ex)) + + # Add new SG rules + self.add_security_group_rules(driver, outports, sg) + return (True, "") def resizeVM(self, vm, radl, auth_data): diff --git a/test/unit/connectors/OpenStack.py b/test/unit/connectors/OpenStack.py index 4995cf60..f74cca4c 100644 --- a/test/unit/connectors/OpenStack.py +++ b/test/unit/connectors/OpenStack.py @@ -636,6 +636,7 @@ def test_55_alter(self, add_elastic_ip_from_pool, get_driver): ost_cloud = self.get_ost_cloud() inf = MagicMock() + inf.id = "infid" vm = VirtualMachine(inf, "1", ost_cloud.cloud, radl, radl, ost_cloud, 1) vm.volumes = [] @@ -737,6 +738,51 @@ def test_55_alter(self, add_elastic_ip_from_pool, get_driver): self.assertEqual(driver.ex_detach_floating_ip_from_node.call_args_list[0][0], (node, fip)) self.assertIsNone(vm.requested_radl.systems[0].getValue('net_interface.0.ip')) + radl_data = """ + network net (outbound = 'yes' and outports = '8080') + system test ( + cpu.arch='x86_64' and + cpu.count=1 and + memory.size=512m and + net_interface.0.connection = 'net' and + net_interface.0.ip = '8.8.8.8' and + net_interface.0.dns_name = 'test' and + disk.0.os.name = 'linux' and + disk.0.image.url = 'one://server.com/1' and + disk.0.os.credentials.username = 'user' and + disk.0.os.credentials.password = 'pass' + )""" + radl = radl_parse.parse_radl(radl_data) + vm = VirtualMachine(inf, "1", ost_cloud.cloud, radl, radl, ost_cloud, 1) + + new_radl_data = """ + network net (outbound = 'yes' and outports = '8081') + system test ( + net_interface.0.connection = 'net' + )""" + new_radl = radl_parse.parse_radl(new_radl_data) + + sg = MagicMock() + sg.name = "im-infid-net" + rule = MagicMock() + rule.id = "rid" + rule.from_port = 8080 + rule.to_port = 8080 + rule.ip_protocol = 'tcp' + sg.rules = [rule] + driver.ex_list_security_groups.return_value = [sg] + driver.ex_delete_security_group_rule.return_value = True + driver.ex_create_security_group_rule.return_value = True + + success, _ = ost_cloud.alterVM(vm, new_radl, auth) + self.assertTrue(success, msg="ERROR: modifying VM info.") + self.assertEqual(driver.ex_delete_security_group_rule.call_count, 1) + self.assertEqual(driver.ex_delete_security_group_rule.call_args_list[0][0], (rule,)) + self.assertEqual(driver.ex_create_security_group_rule.call_count, 2) + self.assertEqual(driver.ex_create_security_group_rule.call_args_list[0][0], + (sg, 'tcp', 8081, 8081, '0.0.0.0/0')) + self.assertEqual(driver.ex_create_security_group_rule.call_args_list[1][0], + (sg, 'tcp', 22, 22, '0.0.0.0/0')) self.assertNotIn("ERROR", self.log.getvalue(), msg="ERROR found in log: %s" % self.log.getvalue()) @patch('libcloud.compute.drivers.openstack.OpenStackNodeDriver')