From 8ff1517683fda71296efc91351143f0db39334f2 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 09:39:46 +0200 Subject: [PATCH 01/30] Add EstimateResources function --- IM/InfrastructureManager.py | 195 ++++++++++++++++++++++++++++------- IM/REST.py | 38 ++++--- IM/ServiceRequests.py | 14 +++ im_service.py | 7 ++ test/unit/REST.py | 10 ++ test/unit/ServiceRequests.py | 7 ++ test/unit/test_im_logic.py | 35 +++++++ 7 files changed, 257 insertions(+), 49 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index ee17e6834..cf963145a 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -518,6 +518,52 @@ def sort_by_score(sel_inf, concrete_systems, cloud_list, deploy_groups, auth): return deploys_group_cloud + @staticmethod + def add_app_reqs(radl, inf_id=None): + """ Add apps requirements to the RADL. """ + for radl_system in radl.systems: + apps_to_install = radl_system.getApplications() + for app_to_install in apps_to_install: + for app_avail, _, _, _, requirements in Recipe.getInstallableApps(): + if requirements and app_avail.isNewerThan(app_to_install): + # This app must be installed and it has special + # requirements + try: + requirements_radl = radl_parse.parse_radl(requirements).systems[0] + radl_system.applyFeatures(requirements_radl, conflict="other", missing="other") + except Exception: + InfrastructureManager.logger.exception( + "Inf ID: " + inf_id + ": Error in the requirements of the app: " + + app_to_install.getValue("name") + ". Ignore them.") + InfrastructureManager.logger.debug("Inf ID: " + inf_id + ": " + str(requirements)) + break + + @staticmethod + def get_deploy_groups(cloud_list, radl, systems_with_iis, sel_inf, auth): + # Concrete systems with cloud providers and select systems with the greatest score + # in every cloud + concrete_systems = {} + for cloud_id, cloud in cloud_list.items(): + for system_id, systems in systems_with_iis.items(): + s1 = [InfrastructureManager._compute_score(s.clone().applyFeatures(s0, + conflict="other", + missing="other").concrete(), + radl.get_system_by_name(system_id)) + for s in systems for s0 in cloud.concreteSystem(s, auth)] + # Store the concrete system with largest score + concrete_systems.setdefault(cloud_id, {})[system_id] = max(s1, key=lambda x: x[1]) if s1 else (None, -1e9) + + # Group virtual machines to deploy by network dependencies + deploy_groups = InfrastructureManager._compute_deploy_groups(radl) + InfrastructureManager.logger.debug("Inf ID: " + sel_inf.id + ": Groups of VMs with dependencies") + InfrastructureManager.logger.debug("Inf ID: " + sel_inf.id + "\n" + str(deploy_groups)) + + # Sort by score the cloud providers + deploys_group_cloud = InfrastructureManager.sort_by_score(sel_inf, concrete_systems, cloud_list, + deploy_groups, auth) + + return concrete_systems, deploy_groups, deploys_group_cloud + @staticmethod def AddResource(inf_id, radl_data, auth, context=True): """ @@ -571,23 +617,7 @@ def AddResource(inf_id, radl_data, auth, context=True): InfrastructureManager.logger.exception("Inf ID: " + sel_inf.id + " error parsing RADL") raise ex - for radl_system in radl.systems: - # Add apps requirements to the RADL - apps_to_install = radl_system.getApplications() - for app_to_install in apps_to_install: - for app_avail, _, _, _, requirements in Recipe.getInstallableApps(): - if requirements and app_avail.isNewerThan(app_to_install): - # This app must be installed and it has special - # requirements - try: - requirements_radl = radl_parse.parse_radl(requirements).systems[0] - radl_system.applyFeatures(requirements_radl, conflict="other", missing="other") - except Exception: - InfrastructureManager.logger.exception( - "Inf ID: " + sel_inf.id + ": Error in the requirements of the app: " + - app_to_install.getValue("name") + ". Ignore them.") - InfrastructureManager.logger.debug("Inf ID: " + sel_inf.id + ": " + str(requirements)) - break + InfrastructureManager.add_app_reqs(radl, sel_inf.id) # Concrete systems using VMRC try: @@ -601,26 +631,11 @@ def AddResource(inf_id, radl_data, auth, context=True): # Concrete systems with cloud providers and select systems with the greatest score # in every cloud cloud_list = dict([(c.id, c.getCloudConnector(sel_inf)) for c in CloudInfo.get_cloud_list(auth)]) - concrete_systems = {} - for cloud_id, cloud in cloud_list.items(): - for system_id, systems in systems_with_iis.items(): - s1 = [InfrastructureManager._compute_score(s.clone().applyFeatures(s0, - conflict="other", - missing="other").concrete(), - radl.get_system_by_name(system_id)) - for s in systems for s0 in cloud.concreteSystem(s, auth)] - # Store the concrete system with largest score - concrete_systems.setdefault(cloud_id, {})[system_id] = ( - max(s1, key=lambda x: x[1]) if s1 else (None, -1e9)) - - # Group virtual machines to deploy by network dependencies - deploy_groups = InfrastructureManager._compute_deploy_groups(radl) - InfrastructureManager.logger.debug("Inf ID: " + sel_inf.id + ": Groups of VMs with dependencies") - InfrastructureManager.logger.debug("Inf ID: " + sel_inf.id + "\n" + str(deploy_groups)) - - # Sort by score the cloud providers - deploys_group_cloud = InfrastructureManager.sort_by_score(sel_inf, concrete_systems, cloud_list, - deploy_groups, auth) + concrete_systems, deploy_groups, deploys_group_cloud = InfrastructureManager.get_deploy_groups(cloud_list, + radl, + systems_with_iis, + sel_inf, + auth) # We are going to start adding resources sel_inf.set_adding() @@ -1869,3 +1884,109 @@ def GetInfrastructureOwners(inf_id, auth): res.append(im_auth['username']) return res + + @staticmethod + def EstimateResouces(radl_data, auth): + """ + Get the estimated amount of resources needed to deploy the infrastructure. + + Args: + + - radl(str): RADL description. + - auth(Authentication): parsed authentication tokens. + + Return(dict): dict with the estimated amount of needed to deploy the infrastructure + with the following structure: + { + 'compute': [ + {'cpu': 2, 'memory': 4096, 'disk': 20}, + {'cpu': 1, 'memory': 2048, 'disk': 10} + ], + 'storage': [ + {'size': 100} + ] + } + + """ + res = {"compute": [], "storage": []} + InfrastructureManager.logger.info("Getting the cost of the infrastructure") + + # First check the auth data + auth = InfrastructureManager.check_auth_data(auth) + + try: + if isinstance(radl_data, RADL): + radl = radl_data + else: + radl = radl_parse.parse_radl(radl_data) + + radl.check() + + inf = IM.InfrastructureInfo.InfrastructureInfo() + inf.radl = radl + + # If any deploy is defined, only update definitions. + if not radl.deploys: + InfrastructureManager.logger.warn("Getting cost of and infrastructure without any deploy.") + return res + except Exception as ex: + InfrastructureManager.logger.exception("Error getting cost of and infrastructure when parsing RADL") + raise ex + + InfrastructureManager.add_app_reqs(radl, inf.id) + + # Concrete systems using VMRC + try: + systems_with_iis = InfrastructureManager.systems_with_iis(inf, radl, auth) + except Exception as ex: + InfrastructureManager.logger.exception("Error getting cost of and infrastructure error getting VM images") + raise ex + + # Concrete systems with cloud providers and select systems with the greatest score + # in every cloud + cloud_list = dict([(c.id, c.getCloudConnector(inf)) for c in CloudInfo.get_cloud_list(auth)]) + concrete_systems, deploy_groups, deploys_group_cloud = InfrastructureManager.get_deploy_groups(cloud_list, + radl, + systems_with_iis, + inf, + auth) + + # Launch every group in the same cloud provider + deploy_items = [] + for deploy_group in deploy_groups: + if not deploy_group: + InfrastructureManager.logger.warning("Error getting cost of and infrastructure: No VMs to deploy!") + + cloud_id = deploys_group_cloud[id(deploy_group)] + cloud = cloud_list[cloud_id] + + for d in deploy_group: + deploy_items.append((d, cloud_id, cloud)) + + # Get the cost of the infrastructure + for deploy, cloud_id, cloud in deploy_items: + + if not deploy.id.startswith(IM.InfrastructureInfo.InfrastructureInfo.FAKE_SYSTEM): + concrete_system = concrete_systems[cloud_id][deploy.id][0] + + if not concrete_system: + InfrastructureManager.logger.warn("Error getting cost of and infrastructure:" + + "Error, no concrete system to deploy: " + + deploy.id + " in cloud: " + cloud_id + + ". Check if a correct image is being used") + else: + vm = {"cpu": concrete_system.getValue("cpu.count"), + "memory": concrete_system.getFeature("memory.size").getValue("M")} + + if concrete_system.getValue("disk.0.free_size"): + vm['disk'] = concrete_system.getFeature("disk.0.free_size").getValue('G') + + res["compute"].append(vm) + + cont = 1 + while (concrete_system.getValue("disk." + str(cont) + ".size")): + volume_size = concrete_system.getFeature("disk." + str(cont) + ".size").getValue('G') + res["storage"].append({"size": volume_size}) + cont += 1 + + return res \ No newline at end of file diff --git a/IM/REST.py b/IM/REST.py index 1c1eca247..6c8928d35 100644 --- a/IM/REST.py +++ b/IM/REST.py @@ -534,14 +534,24 @@ def RESTCreateInfrastructure(): async_call = False if "async" in bottle.request.params.keys(): - str_ctxt = bottle.request.params.get("async").lower() - if str_ctxt in ['yes', 'true', '1']: + str_async = bottle.request.params.get("async").lower() + if str_async in ['yes', 'true', '1']: async_call = True - elif str_ctxt in ['no', 'false', '0']: + elif str_async in ['no', 'false', '0']: async_call = False else: return return_error(400, "Incorrect value in async parameter") + dry_run = False + if "dry_run" in bottle.request.params.keys(): + str_dry_run = bottle.request.params.get("dry_run").lower() + if str_dry_run in ['yes', 'true', '1']: + dry_run = True + elif str_dry_run in ['no', 'false', '0']: + dry_run = False + else: + return return_error(400, "Incorrect value in dry_run parameter") + if content_type: if "application/json" in content_type: radl_data = parse_radl_json(radl_data) @@ -553,18 +563,22 @@ def RESTCreateInfrastructure(): else: return return_error(415, "Unsupported Media Type %s" % content_type) - inf_id = InfrastructureManager.CreateInfrastructure(radl_data, auth, async_call) + if dry_run: + res = InfrastructureManager.EstimateResouces(radl_data, auth) + return format_output(res, "application/json") + else: + inf_id = InfrastructureManager.CreateInfrastructure(radl_data, auth, async_call) - # Store the TOSCA document - if tosca_data: - sel_inf = InfrastructureManager.get_infrastructure(inf_id, auth) - sel_inf.extra_info['TOSCA'] = tosca_data + # Store the TOSCA document + if tosca_data: + sel_inf = InfrastructureManager.get_infrastructure(inf_id, auth) + sel_inf.extra_info['TOSCA'] = tosca_data - bottle.response.headers['InfID'] = inf_id - bottle.response.content_type = "text/uri-list" - res = get_full_url('/infrastructures/%s' % inf_id) + bottle.response.headers['InfID'] = inf_id + bottle.response.content_type = "text/uri-list" + res = get_full_url('/infrastructures/%s' % inf_id) - return format_output(res, "text/uri-list", "uri") + return format_output(res, "text/uri-list", "uri") except InvaliddUserException as ex: return return_error(401, "Error Getting Inf. info: %s" % get_ex_error(ex)) except DisabledFunctionException as ex: diff --git a/IM/ServiceRequests.py b/IM/ServiceRequests.py index 501349d91..0f8cfad19 100644 --- a/IM/ServiceRequests.py +++ b/IM/ServiceRequests.py @@ -59,6 +59,7 @@ class IMBaseRequest(AsyncRequest): GET_CLOUD_QUOTAS = "GetCloudQuotas" CHANGE_INFRASTRUCTURE_AUTH = "ChangeInfrastructureAuth" GET_INFRASTRUCTURE_OWNERS = "GetInfrastructureOwners" + ESTIMATE_RESOURCES = "EstimateResouces" @staticmethod def create_request(function, arguments=()): @@ -116,6 +117,8 @@ def create_request(function, arguments=()): return Request_ChangeInfrastructureAuth(arguments) elif function == IMBaseRequest.GET_INFRASTRUCTURE_OWNERS: return Request_GetInfrastructureOwners(arguments) + elif function == IMBaseRequest.ESTIMATE_RESOURCES: + return Request_EstimateResouces(arguments) else: raise NotImplementedError("Function not Implemented") @@ -459,3 +462,14 @@ def _call_function(self): self._error_mesage = "Error getting the Inf. owners" (inf_id, auth_data) = self.arguments return IM.InfrastructureManager.InfrastructureManager.GetInfrastructureOwners(inf_id, Authentication(auth_data)) + + +class Request_EstimateResouces(IMBaseRequest): + """ + Request class for the EstimateResouces function + """ + + def _call_function(self): + self._error_mesage = "Error getting the resources estimation" + (radl_data, auth_data) = self.arguments + return IM.InfrastructureManager.InfrastructureManager.EstimateResouces(radl_data, Authentication(auth_data)) diff --git a/im_service.py b/im_service.py index bb5ae135a..a242e56ea 100755 --- a/im_service.py +++ b/im_service.py @@ -226,6 +226,12 @@ def GetInfrastructureOwners(inf_id, auth_data): return WaitRequest(request) +def EstimateResources(radl_data, auth_data): + request = IMBaseRequest.create_request( + IMBaseRequest.ESTIMATE_RESOURCES, (radl_data, auth_data)) + return WaitRequest(request) + + def launch_daemon(): """ Launch the IM daemon @@ -286,6 +292,7 @@ def launch_daemon(): server.register_function(GetCloudQuotas) server.register_function(ChangeInfrastructureAuth) server.register_function(GetInfrastructureOwners) + server.register_function(EstimateResources) # Launch the API XMLRPC thread server.serve_forever_in_thread() diff --git a/test/unit/REST.py b/test/unit/REST.py index d5354a622..5342de798 100755 --- a/test/unit/REST.py +++ b/test/unit/REST.py @@ -323,6 +323,16 @@ def test_CreateInfrastructure(self, bottle_request, get_infrastructure, CreateIn res = RESTCreateInfrastructure() self.assertEqual(res, "Error Creating Inf.: Access to this infrastructure not granted.") + # Test the dry_run option to get the estimation of the resources + bottle_request.headers = {"AUTHORIZATION": ("type = InfrastructureManager; username = user; password = pass\\n" + "id = one; type = OpenNebula; host = ramses.i3m.upv.es:2633; " + "username = user; password = pass"), + "Content-Type": "application/json"} + bottle_request.body = read_file_as_bytes("../files/test_simple.json") + bottle_request.params = {"dry_run": "yes"} + res = RESTCreateInfrastructure() + self.assertEqual(res, '{"compute": [{"cpu": 1, "memory": 512}, {"cpu": 1, "memory": 512}], "storage": []}') + @patch("IM.InfrastructureManager.InfrastructureManager.CreateInfrastructure") @patch("bottle.request") def test_CreateInfrastructureWithErrors(self, bottle_request, CreateInfrastructure): diff --git a/test/unit/ServiceRequests.py b/test/unit/ServiceRequests.py index d865147f5..4bf16b980 100755 --- a/test/unit/ServiceRequests.py +++ b/test/unit/ServiceRequests.py @@ -207,6 +207,13 @@ def test_get_owners(self, inflist): IM.ServiceRequests.IMBaseRequest.GET_INFRASTRUCTURE_OWNERS, ("", "")) req._call_function() + @patch('IM.InfrastructureManager.InfrastructureManager') + def test_estimate_resources(self, inflist): + import IM.ServiceRequests + req = IM.ServiceRequests.IMBaseRequest.create_request( + IM.ServiceRequests.IMBaseRequest.ESTIMATE_RESOURCES, ("", "")) + req._call_function() + if __name__ == '__main__': unittest.main() diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index 7450f4aa4..86eda6c15 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -1488,6 +1488,41 @@ def test_translate_egi_to_ost(self, appdb): 'host': 'https://ostsite.com:5000', 'domain': 'projectid'}, res.auth_list) self.assertIn({'type': 'InfrastructureManager', 'token': 'atoken'}, res.auth_list) + def test_estimate_resources(self): + radl = """" + network publica (outbound = 'yes') + network privada + + system front ( + cpu.count>=2 and + memory.size>=4g and + net_interface.0.connection = 'publica' and + net_interface.1.connection = 'privada' and + disk.0.image.url = 'mock0://linux.for.ev.er' and + disk.0.free_size >= 20GB and + disk.0.os.name = 'linux' and + disk.1.size=100GB and + disk.1.device='hdb' and + disk.1.fstype='ext4' and + disk.1.mount_path='/mnt/disk' + ) + + system wn ( + cpu.count>=1 and + memory.size>=2g and + net_interface.0.connection = 'privada' and + disk.0.image.url = 'mock0://linux.for.ev.er' and + disk.0.free_size >= 10GB and + disk.0.os.name = 'linux' + ) + + deploy front 1 + deploy wn 1 + """ + res = IM.EstimateResouces(radl, self.getAuth([0], [], [("Dummy", 0)])) + self.assertEqual(res, {'compute': [{'cpu': 2, 'memory': 4096, 'disk': 20}, + {'cpu': 1, 'memory': 2048, 'disk': 10}], + 'storage': [{'size': 100}]}) if __name__ == "__main__": unittest.main() From b3a2a91b0fdcef0b1bc57f5348ca00caab545316 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 09:41:41 +0200 Subject: [PATCH 02/30] Fix style --- IM/InfrastructureManager.py | 15 ++++++++------- test/unit/test_im_logic.py | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index cf963145a..39d6a3f0f 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -551,7 +551,8 @@ def get_deploy_groups(cloud_list, radl, systems_with_iis, sel_inf, auth): radl.get_system_by_name(system_id)) for s in systems for s0 in cloud.concreteSystem(s, auth)] # Store the concrete system with largest score - concrete_systems.setdefault(cloud_id, {})[system_id] = max(s1, key=lambda x: x[1]) if s1 else (None, -1e9) + concrete_systems.setdefault(cloud_id, {})[system_id] = max(s1, key=lambda x: x[1]) if s1 else (None, + -1e9) # Group virtual machines to deploy by network dependencies deploy_groups = InfrastructureManager._compute_deploy_groups(radl) @@ -561,7 +562,7 @@ def get_deploy_groups(cloud_list, radl, systems_with_iis, sel_inf, auth): # Sort by score the cloud providers deploys_group_cloud = InfrastructureManager.sort_by_score(sel_inf, concrete_systems, cloud_list, deploy_groups, auth) - + return concrete_systems, deploy_groups, deploys_group_cloud @staticmethod @@ -1971,13 +1972,13 @@ def EstimateResouces(radl_data, auth): if not concrete_system: InfrastructureManager.logger.warn("Error getting cost of and infrastructure:" + - "Error, no concrete system to deploy: " + - deploy.id + " in cloud: " + cloud_id + - ". Check if a correct image is being used") + "Error, no concrete system to deploy: " + + deploy.id + " in cloud: " + cloud_id + + ". Check if a correct image is being used") else: vm = {"cpu": concrete_system.getValue("cpu.count"), "memory": concrete_system.getFeature("memory.size").getValue("M")} - + if concrete_system.getValue("disk.0.free_size"): vm['disk'] = concrete_system.getFeature("disk.0.free_size").getValue('G') @@ -1989,4 +1990,4 @@ def EstimateResouces(radl_data, auth): res["storage"].append({"size": volume_size}) cont += 1 - return res \ No newline at end of file + return res diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index 86eda6c15..18fc3d86b 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -1524,5 +1524,6 @@ def test_estimate_resources(self): {'cpu': 1, 'memory': 2048, 'disk': 10}], 'storage': [{'size': 100}]}) + if __name__ == "__main__": unittest.main() From 6f670d7a76031b2d5da80682447246c44fc45509 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 10:00:32 +0200 Subject: [PATCH 03/30] Update docs --- doc/source/REST.rst | 18 +++++++++++++++++- doc/source/xmlrpc.rst | 22 ++++++++++++++++++++++ doc/swagger_api.yaml | 18 +++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/doc/source/REST.rst b/doc/source/REST.rst index 3addcaf2d..9e322c2bc 100644 --- a/doc/source/REST.rst +++ b/doc/source/REST.rst @@ -108,7 +108,7 @@ GET ``http://imserver.com/infrastructures`` POST ``http://imserver.com/infrastructures`` :body: ``RADL or TOSCA document`` :body Content-type: text/plain, application/json or text/yaml - :input fields: ``async`` (optional) + :input fields: ``async`` (optional), ``dry_rum`` (optional) :Response Content-type: text/uri-list :ok response: 200 OK :fail response: 401, 400, 415 @@ -126,6 +126,22 @@ POST ``http://imserver.com/infrastructures`` "uri" : "http://server.com:8800/infrastructures/inf_id } + The ``dry_rum`` parameter is optional and is a flag to specify if the call will not create the VMs + and will only return the ammount of resources needed to deploy the infrastructure. + Acceptable values: yes, no, true, false, 1 or 0. If not specified the flag is set to False. + In this case no infrastructure ID is returned, only the ammount of resources needed to deploy + the infrastructure with the following format:: + + { + 'compute': [ + {'cpu': 2, 'memory': 4096, 'disk': 20}, + {'cpu': 1, 'memory': 2048, 'disk': 10} + ], + 'storage': [ + {'size': 100} + ] + } + PUT ``http://imserver.com/infrastructures`` :body: ``JSON data of the infrastructure`` :body Content-type: application/json diff --git a/doc/source/xmlrpc.rst b/doc/source/xmlrpc.rst index 9e65562cf..82b57226d 100644 --- a/doc/source/xmlrpc.rst +++ b/doc/source/xmlrpc.rst @@ -416,3 +416,25 @@ This is the list of method names: :fail response: [false, ``error``: string] Return the list of current owners of the infrastructure with ID ``infId``. + +.. _EstimateResouces-xmlrpc: + +``EstimateResouces`` + :parameter 0: ``radl``: string + :parameter 1: ``auth``: array of structs + :ok response: [true, struct] + :fail response: [false, ``error``: string] + + Get the estimated amount of resources needed to deploy the infrastructure + specified in the RADL document passed as string. The response is a struct + with the following format:: + + { + 'compute': [ + {'cpu': 2, 'memory': 4096, 'disk': 20}, + {'cpu': 1, 'memory': 2048, 'disk': 10} + ], + 'storage': [ + {'size': 100} + ] + } diff --git a/doc/swagger_api.yaml b/doc/swagger_api.yaml index 04fbbc390..03fe0cd9f 100644 --- a/doc/swagger_api.yaml +++ b/doc/swagger_api.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: description: Infrastructure Manager (IM) REST API. - version: 1.11.0 + version: 1.17.0 title: Infrastructure Manager (IM) REST API contact: email: products@grycap.upv.es @@ -111,6 +111,22 @@ paths: - '0' - '1' default: 'false' + - name: dry_run + in: query + description: >- + parameter is optional and is a flag to specify if the call will not create the VMs + and will only return the ammount of resources needed to deploy the infrastructure. + required: false + schema: + type: string + enum: + - 'yes' + - 'no' + - 'true' + - 'false' + - '0' + - '1' + default: 'false' requestBody: content: text/plain: From 80fb89396a4097a02df4e497a0e516f02207140b Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 10:28:07 +0200 Subject: [PATCH 04/30] Update docs --- doc/source/REST.rst | 2 +- doc/source/xmlrpc.rst | 2 +- doc/swagger_api.yaml | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/source/REST.rst b/doc/source/REST.rst index 9e322c2bc..e5a2de0c5 100644 --- a/doc/source/REST.rst +++ b/doc/source/REST.rst @@ -130,7 +130,7 @@ POST ``http://imserver.com/infrastructures`` and will only return the ammount of resources needed to deploy the infrastructure. Acceptable values: yes, no, true, false, 1 or 0. If not specified the flag is set to False. In this case no infrastructure ID is returned, only the ammount of resources needed to deploy - the infrastructure with the following format:: + the infrastructure with the following format (memory unit MB, disk and storage unit GB):: { 'compute': [ diff --git a/doc/source/xmlrpc.rst b/doc/source/xmlrpc.rst index 82b57226d..d1a9e4144 100644 --- a/doc/source/xmlrpc.rst +++ b/doc/source/xmlrpc.rst @@ -427,7 +427,7 @@ This is the list of method names: Get the estimated amount of resources needed to deploy the infrastructure specified in the RADL document passed as string. The response is a struct - with the following format:: + with the following format (memory unit MB, disk and storage unit GB):: { 'compute': [ diff --git a/doc/swagger_api.yaml b/doc/swagger_api.yaml index 03fe0cd9f..29cd84253 100644 --- a/doc/swagger_api.yaml +++ b/doc/swagger_api.yaml @@ -193,6 +193,17 @@ paths: { "uri": "http://server.com:8800/infrastructures/inf_id1" } + response_dry_run: + value: | + { + "compute": [ + {"cpu": 2, "memory": 4096, "disk": 20}, + {"cpu": 1, "memory": 2048, "disk": 10} + ], + "storage": [ + {"size": 100} + ] + } '400': description: Invalid status value '401': From 6e650d8bdc7019628d0d2055c54b4f7d50fdec76 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 12:54:14 +0200 Subject: [PATCH 05/30] Implements #1552 --- IM/InfrastructureManager.py | 24 +++++++++++++++++++----- IM/config.py | 1 + doc/source/manual.rst | 7 +++++++ etc/im.cfg | 2 ++ test/files/iam_user_info.json | 13 ++++--------- test/unit/test_im_logic.py | 30 +++++++++++++++++++++++++++++- 6 files changed, 62 insertions(+), 15 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 39d6a3f0f..b6e311cee 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1425,6 +1425,20 @@ def check_oidc_token(im_auth): if not issuer.endswith('/'): issuer += '/' im_auth['password'] = issuer + str(userinfo.get("sub")) + + + if Config.OIDC_GROUPS: + # Get user groups from any of the possible fields + user_groups = userinfo.get('groups', # Generic + userinfo.get('entitlements', # GEANT + userinfo.get('eduperson_entitlement', # EGI Check-in + []))) + + if not set(Config.OIDC_GROUPS).issubset(user_groups): + raise InvaliddUserException("Invalid InfrastructureManager credentials. " + + "User not in configured groups.") + + except Exception as ex: InfrastructureManager.logger.exception("Error trying to validate OIDC auth token: %s" % str(ex)) raise Exception("Error trying to validate OIDC auth token: %s" % str(ex)) @@ -1928,10 +1942,10 @@ def EstimateResouces(radl_data, auth): # If any deploy is defined, only update definitions. if not radl.deploys: - InfrastructureManager.logger.warn("Getting cost of and infrastructure without any deploy.") + InfrastructureManager.logger.warn("Getting cost of an infrastructure without any deploy.") return res except Exception as ex: - InfrastructureManager.logger.exception("Error getting cost of and infrastructure when parsing RADL") + InfrastructureManager.logger.exception("Error getting cost of an infrastructure when parsing RADL") raise ex InfrastructureManager.add_app_reqs(radl, inf.id) @@ -1940,7 +1954,7 @@ def EstimateResouces(radl_data, auth): try: systems_with_iis = InfrastructureManager.systems_with_iis(inf, radl, auth) except Exception as ex: - InfrastructureManager.logger.exception("Error getting cost of and infrastructure error getting VM images") + InfrastructureManager.logger.exception("Error getting cost of an infrastructure error getting VM images") raise ex # Concrete systems with cloud providers and select systems with the greatest score @@ -1956,7 +1970,7 @@ def EstimateResouces(radl_data, auth): deploy_items = [] for deploy_group in deploy_groups: if not deploy_group: - InfrastructureManager.logger.warning("Error getting cost of and infrastructure: No VMs to deploy!") + InfrastructureManager.logger.warning("Error getting cost of an infrastructure: No VMs to deploy!") cloud_id = deploys_group_cloud[id(deploy_group)] cloud = cloud_list[cloud_id] @@ -1971,7 +1985,7 @@ def EstimateResouces(radl_data, auth): concrete_system = concrete_systems[cloud_id][deploy.id][0] if not concrete_system: - InfrastructureManager.logger.warn("Error getting cost of and infrastructure:" + + InfrastructureManager.logger.warn("Error getting cost of an infrastructure:" + "Error, no concrete system to deploy: " + deploy.id + " in cloud: " + cloud_id + ". Check if a correct image is being used") diff --git a/IM/config.py b/IM/config.py index 18249f272..c259ceb37 100644 --- a/IM/config.py +++ b/IM/config.py @@ -107,6 +107,7 @@ class Config: OIDC_SCOPES = [] OIDC_USER_INFO_PATH = "/userinfo" OIDC_INSTROSPECT_PATH = "/introspect" + OIDC_GROUPS = [] VM_NUM_USE_CTXT_DIST = 30 DELAY_BETWEEN_VM_RETRIES = 5 VERIFI_SSL = False diff --git a/doc/source/manual.rst b/doc/source/manual.rst index bf1fe471a..aa13e5840 100644 --- a/doc/source/manual.rst +++ b/doc/source/manual.rst @@ -507,6 +507,13 @@ OPENID CONNECT OPTIONS Client ID and Secret must be provided to make it work. The default value is ``''``. +.. confval:: OIDC_GROUPS + + List of OIDC groups supported. + It must be a coma separated string of group names. + (see the `AARC guidelines for group names `_). + The default value is ``''``. + .. confval:: FORCE_OIDC_AUTH If ``True`` the IM will force the users to pass a valid OIDC token. diff --git a/etc/im.cfg b/etc/im.cfg index a6525ae4f..e84f33c85 100644 --- a/etc/im.cfg +++ b/etc/im.cfg @@ -146,6 +146,8 @@ OIDC_ISSUERS = https://aai.egi.eu/auth/realms/egi # Paths to the userinfo and introspection OIDC #OIDC_USER_INFO_PATH = "/userinfo" #OIDC_INSTROSPECT_PATH = "/introspect" +# List of OIDC groups that will be allowed to access the IM service +#OIDC_GROUPS = # Force the users to pass a valid OIDC token #FORCE_OIDC_AUTH = False diff --git a/test/files/iam_user_info.json b/test/files/iam_user_info.json index 7bc8b105c..848fde0ea 100644 --- a/test/files/iam_user_info.json +++ b/test/files/iam_user_info.json @@ -6,15 +6,10 @@ "email": "", "email_verified": true, "phone_number_verified": false, - "groups": [ - { - "id": "gid", - "name": "Users" - }, - { - "id": "gid", - "name": "Developers" - } + "eduperson_entitlement": [ + "urn:mace:egi.eu:group:demo.fedcloud.egi.eu:members:role=member#aai.egi.eu", + "urn:mace:egi.eu:group:demo.fedcloud.egi.eu:role=member#aai.egi.eu", + "urn:mace:egi.eu:group:demo.fedcloud.egi.eu:vm_operator:role=member#aai.egi.eu" ], "organisation_name": "indigo-dc" } \ No newline at end of file diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index 18fc3d86b..c8a2f461f 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -135,7 +135,7 @@ def get_cloud_connector_mock(self, name="MyMock0"): return cloud @staticmethod - def gen_token(aud=None, exp=None, user_sub="user_sub"): + def gen_token(aud=None, exp=None, user_sub="user_sub", groups=None): data = { "sub": user_sub, "iss": "https://iam-test.indigo-datacloud.eu/", @@ -147,6 +147,8 @@ def gen_token(aud=None, exp=None, user_sub="user_sub"): data["aud"] = aud if exp: data["exp"] = int(time.time()) + exp + if groups: + data["groups"] = groups return ("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.%s.ignored" % base64.urlsafe_b64encode(json.dumps(data).encode("utf-8")).decode("utf-8")) @@ -1126,6 +1128,32 @@ def test_check_oidc_valid_token(self, openidclient): self.assertEqual(im_auth['username'], InfrastructureInfo.OPENID_USER_PREFIX + "micafer") self.assertEqual(im_auth['password'], "https://iam-test.indigo-datacloud.eu/sub") + @patch('IM.InfrastructureManager.OpenIDClient') + def test_check_oidc_groups(self, openidclient): + im_auth = {"token": (self.gen_token())} + + user_info = json.loads(read_file_as_string('../files/iam_user_info.json')) + + openidclient.is_access_token_expired.return_value = False, "Valid Token for 100 seconds" + openidclient.get_user_info_request.return_value = True, user_info + + Config.OIDC_ISSUERS = ["https://iam-test.indigo-datacloud.eu/"] + Config.OIDC_AUDIENCE = None + Config.OIDC_GROUPS = ["urn:mace:egi.eu:group:demo.fedcloud.egi.eu:role=member#aai.egi.eu"] + + IM.check_oidc_token(im_auth) + + self.assertEqual(im_auth['username'], InfrastructureInfo.OPENID_USER_PREFIX + "micafer") + self.assertEqual(im_auth['password'], "https://iam-test.indigo-datacloud.eu/sub") + + Config.OIDC_GROUPS = ["urn:mace:egi.eu:group:demo.fedcloud.egi.eu:role=INVALID#aai.egi.eu"] + + with self.assertRaises(Exception) as ex: + IM.check_oidc_token(im_auth) + self.assertEqual(str(ex.exception), + "Error trying to validate OIDC auth token: Invalid InfrastructureManager" + + " credentials. User not in configured groups.") + def test_inf_auth_with_token(self): im_auth = {"token": (self.gen_token())} im_auth['username'] = InfrastructureInfo.OPENID_USER_PREFIX + "micafer" From 5f9a040bc11df6ea0f55d2d9f605a0b327af617a Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 12:55:17 +0200 Subject: [PATCH 06/30] Fix style --- IM/InfrastructureManager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index b6e311cee..1612fc27f 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1426,7 +1426,6 @@ def check_oidc_token(im_auth): issuer += '/' im_auth['password'] = issuer + str(userinfo.get("sub")) - if Config.OIDC_GROUPS: # Get user groups from any of the possible fields user_groups = userinfo.get('groups', # Generic @@ -1438,7 +1437,6 @@ def check_oidc_token(im_auth): raise InvaliddUserException("Invalid InfrastructureManager credentials. " + "User not in configured groups.") - except Exception as ex: InfrastructureManager.logger.exception("Error trying to validate OIDC auth token: %s" % str(ex)) raise Exception("Error trying to validate OIDC auth token: %s" % str(ex)) From d756ea2a4b118ee1febf142e865269f93509532a Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 13:07:13 +0200 Subject: [PATCH 07/30] Fix test --- test/unit/test_im_logic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index c8a2f461f..4e0b6dfbe 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -1153,6 +1153,8 @@ def test_check_oidc_groups(self, openidclient): self.assertEqual(str(ex.exception), "Error trying to validate OIDC auth token: Invalid InfrastructureManager" + " credentials. User not in configured groups.") + + Config.OIDC_GROUPS = [] def test_inf_auth_with_token(self): im_auth = {"token": (self.gen_token())} From 6e86125eeaa751a9c2640aa9f962a894093828ab Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 13:09:14 +0200 Subject: [PATCH 08/30] Fix style --- test/unit/test_im_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index 4e0b6dfbe..35d5b17f3 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -1153,7 +1153,7 @@ def test_check_oidc_groups(self, openidclient): self.assertEqual(str(ex.exception), "Error trying to validate OIDC auth token: Invalid InfrastructureManager" + " credentials. User not in configured groups.") - + Config.OIDC_GROUPS = [] def test_inf_auth_with_token(self): From 0714f3046fca5b9dd5d2e147546da68dd964afca Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 13:26:33 +0200 Subject: [PATCH 09/30] Auth change --- IM/InfrastructureManager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 1612fc27f..a4b8385b9 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1554,13 +1554,13 @@ def check_auth_data(auth): if im_auth_item['username'].startswith(IM.InfrastructureInfo.InfrastructureInfo.OPENID_USER_PREFIX): # This is a OpenID user do not enable to get data using user/pass creds raise InvaliddUserException("Invalid username used for the InfrastructureManager.") + + # Now check if the user is in authorized + if not InfrastructureManager.check_im_user(im_auth_item): + raise InvaliddUserException() else: raise InvaliddUserException("No username nor token for the InfrastructureManager.") - # Now check if the user is in authorized - if not InfrastructureManager.check_im_user(im_auth_item): - raise InvaliddUserException() - if Config.SINGLE_SITE: vmrc_auth = auth.getAuthInfo("VMRC") single_site_auth = auth.getAuthInfo(Config.SINGLE_SITE_TYPE) From ec9db0243c1fa4d41d4e41471cef7e68c9bad26c Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 13:29:00 +0200 Subject: [PATCH 10/30] Fix style --- IM/InfrastructureManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index a4b8385b9..1d63419a3 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1554,7 +1554,7 @@ def check_auth_data(auth): if im_auth_item['username'].startswith(IM.InfrastructureInfo.InfrastructureInfo.OPENID_USER_PREFIX): # This is a OpenID user do not enable to get data using user/pass creds raise InvaliddUserException("Invalid username used for the InfrastructureManager.") - + # Now check if the user is in authorized if not InfrastructureManager.check_im_user(im_auth_item): raise InvaliddUserException() From 6543cb7897a406df3f8a868146c8fbc58f12f15a Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 3 May 2024 13:31:27 +0200 Subject: [PATCH 11/30] Fix style --- IM/InfrastructureManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 1d63419a3..b87013516 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1554,7 +1554,7 @@ def check_auth_data(auth): if im_auth_item['username'].startswith(IM.InfrastructureInfo.InfrastructureInfo.OPENID_USER_PREFIX): # This is a OpenID user do not enable to get data using user/pass creds raise InvaliddUserException("Invalid username used for the InfrastructureManager.") - + # Now check if the user is in authorized if not InfrastructureManager.check_im_user(im_auth_item): raise InvaliddUserException() From 7a6b0c96438030e871499fd16eb49861a4bf9382 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Fernandez Date: Mon, 6 May 2024 08:04:18 +0200 Subject: [PATCH 12/30] Increase Ansible install timeout --- etc/im.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/im.cfg b/etc/im.cfg index e84f33c85..be1b5b90a 100644 --- a/etc/im.cfg +++ b/etc/im.cfg @@ -97,7 +97,7 @@ UPDATE_CTXT_LOG_INTERVAL = 20 # Interval to update the state of the processes of the ConfManager (in secs) CONFMAMAGER_CHECK_STATE_INTERVAL = 5 # Max time expected to install Ansible in the master node -ANSIBLE_INSTALL_TIMEOUT = 500 +ANSIBLE_INSTALL_TIMEOUT = 900 # Number of VMs in an infrastructure that will use the distributed version of the Ctxt Agent VM_NUM_USE_CTXT_DIST = 30 From fc66277fb701848d5cc2204518299132014e8727 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Wed, 8 May 2024 08:26:28 +0200 Subject: [PATCH 13/30] Change EstimateResources format --- IM/InfrastructureManager.py | 8 ++++---- test/unit/test_im_logic.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index b87013516..1edc4ac89 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1988,18 +1988,18 @@ def EstimateResouces(radl_data, auth): deploy.id + " in cloud: " + cloud_id + ". Check if a correct image is being used") else: - vm = {"cpu": concrete_system.getValue("cpu.count"), - "memory": concrete_system.getFeature("memory.size").getValue("M")} + vm = {"cpuCores": concrete_system.getValue("cpu.count"), + "memoryInMegabytes": concrete_system.getFeature("memory.size").getValue("M")} if concrete_system.getValue("disk.0.free_size"): - vm['disk'] = concrete_system.getFeature("disk.0.free_size").getValue('G') + vm['diskSizeInGigabytes'] = concrete_system.getFeature("disk.0.free_size").getValue('G') res["compute"].append(vm) cont = 1 while (concrete_system.getValue("disk." + str(cont) + ".size")): volume_size = concrete_system.getFeature("disk." + str(cont) + ".size").getValue('G') - res["storage"].append({"size": volume_size}) + res["storage"].append({"sizeInGigabytes": volume_size}) cont += 1 return res diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index 35d5b17f3..c16668674 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -1550,9 +1550,9 @@ def test_estimate_resources(self): deploy wn 1 """ res = IM.EstimateResouces(radl, self.getAuth([0], [], [("Dummy", 0)])) - self.assertEqual(res, {'compute': [{'cpu': 2, 'memory': 4096, 'disk': 20}, - {'cpu': 1, 'memory': 2048, 'disk': 10}], - 'storage': [{'size': 100}]}) + self.assertEqual(res, {'compute': [{'cpuCores': 2, 'memoryInMegabytes': 4096, 'diskSizeInGigabytes': 20}, + {'cpuCores': 1, 'memoryInMegabytes': 2048, 'diskSizeInGigabytes': 10}], + 'storage': [{'sizeInGigabytes': 100}]}) if __name__ == "__main__": From cced1d6bbd4de6ba29b7bd90aaaff29ec48ab4d9 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Wed, 8 May 2024 08:27:36 +0200 Subject: [PATCH 14/30] Change deprecated log warn --- IM/InfrastructureInfo.py | 6 +++--- IM/InfrastructureList.py | 2 +- IM/InfrastructureManager.py | 12 ++++++------ IM/config.py | 3 +-- IM/connectors/OpenNebula.py | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/IM/InfrastructureInfo.py b/IM/InfrastructureInfo.py index 4b2ad0b10..45f594c99 100644 --- a/IM/InfrastructureInfo.py +++ b/IM/InfrastructureInfo.py @@ -361,12 +361,12 @@ def update_radl(self, radl, deployed_vms, warn=True): # Add new networks ad ansible_hosts only for s in radl.networks + radl.ansible_hosts: if not self.radl.add(s.clone(), "ignore") and warn: - InfrastructureInfo.logger.warn("Ignoring the redefinition of %s %s" % (type(s), s.getId())) + InfrastructureInfo.logger.warning("Ignoring the redefinition of %s %s" % (type(s), s.getId())) # Add or update configures and systems for s in radl.configures + radl.systems: if self.radl.get(s) and warn: - InfrastructureInfo.logger.warn("(Re)definition of %s %s" % (type(s), s.getId())) + InfrastructureInfo.logger.warning("(Re)definition of %s %s" % (type(s), s.getId())) self.radl.add(s.clone(), "replace") # Append contextualize @@ -724,7 +724,7 @@ def _is_authorized(self, self_im_auth, auth): if (self_im_auth['username'].startswith(InfrastructureInfo.OPENID_USER_PREFIX) and 'token' not in other_im_auth): # This is a OpenID user do not enable to get data using user/pass creds - InfrastructureInfo.logger.warn("Inf ID %s: A non OpenID user tried to access it." % self.id) + InfrastructureInfo.logger.warning("Inf ID %s: A non OpenID user tried to access it." % self.id) res = False break diff --git a/IM/InfrastructureList.py b/IM/InfrastructureList.py index 8c8b371df..e24da4ff9 100644 --- a/IM/InfrastructureList.py +++ b/IM/InfrastructureList.py @@ -210,7 +210,7 @@ def _get_data_from_db(db_url, inf_id=None, auth=None): msg = "" if inf_id: msg = " for inf ID: %s" % inf_id - InfrastructureList.logger.warn("No data in database%s!." % msg) + InfrastructureList.logger.warning("No data in database%s!." % msg) db.close() return inf_list diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 1edc4ac89..6d90917f9 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -607,7 +607,7 @@ def AddResource(inf_id, radl_data, auth, context=True): # If any deploy is defined, only update definitions. if not radl.deploys: - InfrastructureManager.logger.warn("Inf ID: " + sel_inf.id + ": without any deploy. Exiting.") + InfrastructureManager.logger.warning("Inf ID: " + sel_inf.id + ": without any deploy. Exiting.") sel_inf.add_cont_msg("Infrastructure without any deploy. Exiting.") if sel_inf.configured is None: sel_inf.configured = False @@ -1940,7 +1940,7 @@ def EstimateResouces(radl_data, auth): # If any deploy is defined, only update definitions. if not radl.deploys: - InfrastructureManager.logger.warn("Getting cost of an infrastructure without any deploy.") + InfrastructureManager.logger.warning("Getting cost of an infrastructure without any deploy.") return res except Exception as ex: InfrastructureManager.logger.exception("Error getting cost of an infrastructure when parsing RADL") @@ -1983,10 +1983,10 @@ def EstimateResouces(radl_data, auth): concrete_system = concrete_systems[cloud_id][deploy.id][0] if not concrete_system: - InfrastructureManager.logger.warn("Error getting cost of an infrastructure:" + - "Error, no concrete system to deploy: " + - deploy.id + " in cloud: " + cloud_id + - ". Check if a correct image is being used") + InfrastructureManager.logger.warning("Error getting cost of an infrastructure:" + + "Error, no concrete system to deploy: " + + deploy.id + " in cloud: " + cloud_id + + ". Check if a correct image is being used") else: vm = {"cpuCores": concrete_system.getValue("cpu.count"), "memoryInMegabytes": concrete_system.getFeature("memory.size").getValue("M")} diff --git a/IM/config.py b/IM/config.py index c259ceb37..0429ae947 100644 --- a/IM/config.py +++ b/IM/config.py @@ -42,8 +42,7 @@ def parse_options(config, section_name, config_class): setattr(config_class, option, config.get(section_name, option)) else: logger = logging.getLogger('InfrastructureManager') - logger.warn( - "Unknown option in the IM config file. Ignoring it: " + option) + logger.warning("Unknown option in the IM config file. Ignoring it: " + option) class Config: diff --git a/IM/connectors/OpenNebula.py b/IM/connectors/OpenNebula.py index a3c84e363..06dc97610 100644 --- a/IM/connectors/OpenNebula.py +++ b/IM/connectors/OpenNebula.py @@ -1246,7 +1246,7 @@ def delete_image(self, image_url, auth_data): # Wait the image to be READY (not USED) success, msg = self.wait_image(image_id, auth_data) if not success: - self.logger.warn("Error waiting image to be READY: " + msg) + self.logger.warning("Error waiting image to be READY: " + msg) success, res_info = server.one.image.delete(session_id, image_id)[0:2] if success: From c7ec6b453897eb428717f8a5cdefa4ac10e19599 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Wed, 8 May 2024 08:35:33 +0200 Subject: [PATCH 15/30] Change deprecated log warn --- IM/REST.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IM/REST.py b/IM/REST.py index 6c8928d35..571bc433f 100644 --- a/IM/REST.py +++ b/IM/REST.py @@ -699,7 +699,7 @@ def RESTGetVMProperty(infid=None, vmid=None, prop=None): break if not sel_vm: # it sometimes happen when the VM is in creation state - logger.warn("Specified vmid in step2 is incorrect!!") + logger.warning("Specified vmid in step2 is incorrect!!") info = "wait" else: ssh = sel_vm.get_ssh_ansible_master(retry=False) From 08f5c0bef24b5cecb3375f8a3b1a8c3c24d4fe18 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Wed, 8 May 2024 08:51:48 +0200 Subject: [PATCH 16/30] Update VMI used in tests --- test/files/quick-test.radl | 2 +- test/files/reverse.radl | 2 +- test/files/test_ansible.radl | 2 +- test/files/test_simple.json | 4 ++-- test/files/tosca_ansible_host.yaml | 2 +- test/integration/TestIM.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/files/quick-test.radl b/test/files/quick-test.radl index ac15cc055..8297629a5 100644 --- a/test/files/quick-test.radl +++ b/test/files/quick-test.radl @@ -24,7 +24,7 @@ cpu.count>=1 and memory.size>=512m and net_interface.0.connection = 'privada' and disk.0.os.name='linux' and -disk.0.image.url = ['one://ramses.i3m.upv.es/1396', 'ost://horsemen.i3m.upv.es/609f8280-fbb6-46bd-84e2-5315b22414f1'] and +disk.0.image.url = ['one://ramses.i3m.upv.es/1593', 'ost://horsemen.i3m.upv.es/79095fa5-7baf-493c-9514-e24d52dd1527'] and disk.1.size=1GB and disk.1.device='hdb' and disk.1.fstype='ext4' and diff --git a/test/files/reverse.radl b/test/files/reverse.radl index ef413135c..4d4eb5bef 100644 --- a/test/files/reverse.radl +++ b/test/files/reverse.radl @@ -27,7 +27,7 @@ memory.size>=1024m and net_interface.0.connection = 'privada2' and disk.0.os.name='linux' and disk.0.os.flavour='ubuntu' and -disk.0.image.url = 'one://ramses.i3m.upv.es/1396' +disk.0.image.url = 'one://ramses.i3m.upv.es/1593' ) diff --git a/test/files/test_ansible.radl b/test/files/test_ansible.radl index cfc9fa5ea..5fa03d9f8 100644 --- a/test/files/test_ansible.radl +++ b/test/files/test_ansible.radl @@ -6,7 +6,7 @@ cpu.count>=1 and memory.size>=1g and net_interface.0.connection = 'publica' and disk.0.os.name='linux' and -disk.0.image.url = 'one://ramses.i3m.upv.es/1396' +disk.0.image.url = 'one://ramses.i3m.upv.es/1593' ) configure node ( diff --git a/test/files/test_simple.json b/test/files/test_simple.json index d8d5f128f..9d3a39f2a 100644 --- a/test/files/test_simple.json +++ b/test/files/test_simple.json @@ -12,7 +12,7 @@ "class": "system", "cpu.arch": "x86_64", "cpu.count_min": 1, - "disk.0.image.url": "one://ramses.i3m.upv.es/1396", + "disk.0.image.url": "one://ramses.i3m.upv.es/1593", "disk.0.os.credentials.password": "GRyCAP01", "disk.0.os.credentials.username": "ubuntu", "disk.0.os.name": "linux", @@ -25,7 +25,7 @@ "class": "system", "cpu.arch": "x86_64", "cpu.count_min": 1, - "disk.0.image.url": "one://ramses.i3m.upv.es/1129", + "disk.0.image.url": "one://ramses.i3m.upv.es/1396", "disk.0.os.name": "linux", "id": "wn", "memory.size_min": 536870912, diff --git a/test/files/tosca_ansible_host.yaml b/test/files/tosca_ansible_host.yaml index b471cd5eb..e30981a84 100644 --- a/test/files/tosca_ansible_host.yaml +++ b/test/files/tosca_ansible_host.yaml @@ -56,7 +56,7 @@ topology_template: mem_size: 1 GB os: properties: - image: 'one://ramses.i3m.upv.es/1396' + image: 'one://ramses.i3m.upv.es/1593' type: linux credential: token_type: password # or private_key diff --git a/test/integration/TestIM.py b/test/integration/TestIM.py index 9ad7b1ce9..e8eddb4fc 100755 --- a/test/integration/TestIM.py +++ b/test/integration/TestIM.py @@ -778,7 +778,7 @@ def test_98_proxy(self): memory.size>=1g and net_interface.0.connection = 'net' and disk.0.os.name='linux' and - disk.0.image.url = 'one://ramses.i3m.upv.es/1396' + disk.0.image.url = 'one://ramses.i3m.upv.es/1593' ) deploy test 1 From 4d8e0ea5d445882f1e06ae2f2a04b525253eee2b Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Wed, 8 May 2024 09:01:58 +0200 Subject: [PATCH 17/30] Fix test --- test/unit/REST.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/REST.py b/test/unit/REST.py index 5342de798..492b022c7 100755 --- a/test/unit/REST.py +++ b/test/unit/REST.py @@ -331,7 +331,8 @@ def test_CreateInfrastructure(self, bottle_request, get_infrastructure, CreateIn bottle_request.body = read_file_as_bytes("../files/test_simple.json") bottle_request.params = {"dry_run": "yes"} res = RESTCreateInfrastructure() - self.assertEqual(res, '{"compute": [{"cpu": 1, "memory": 512}, {"cpu": 1, "memory": 512}], "storage": []}') + self.assertEqual(res, ('{"compute": [{"cpuCores": 1, "memoryInMegabytes": 512},' + ' {"cpuCores": 1, "memoryInMegabytes": 512}], "storage": []}')) @patch("IM.InfrastructureManager.InfrastructureManager.CreateInfrastructure") @patch("bottle.request") From 5ec051bf6173561eb7c80c21169ea96be4d1dba3 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Thu, 9 May 2024 11:31:31 +0200 Subject: [PATCH 18/30] Add volume type in EstimateResources --- IM/InfrastructureManager.py | 5 ++++- IM/connectors/OpenStack.py | 3 +++ doc/source/REST.rst | 11 ++++++----- doc/source/xmlrpc.rst | 11 ++++++----- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 6d90917f9..f219d1f48 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1999,7 +1999,10 @@ def EstimateResouces(radl_data, auth): cont = 1 while (concrete_system.getValue("disk." + str(cont) + ".size")): volume_size = concrete_system.getFeature("disk." + str(cont) + ".size").getValue('G') - res["storage"].append({"sizeInGigabytes": volume_size}) + vol_info = {"sizeInGigabytes": volume_size} + if concrete_system.getValue("disk." + str(cont) + ".type"): + vol_info["type"] = concrete_system.getValue("disk." + str(cont) + ".type") + res["storage"].append(vol_info) cont += 1 return res diff --git a/IM/connectors/OpenStack.py b/IM/connectors/OpenStack.py index 135a3d8b7..c2e738827 100644 --- a/IM/connectors/OpenStack.py +++ b/IM/connectors/OpenStack.py @@ -494,6 +494,9 @@ def setVolumesInfo(self, vm, node): if 'attachments' in volume.extra and volume.extra['attachments']: vm.info.systems[0].setValue("disk." + str(cont) + ".device", os.path.basename(volume.extra['attachments'][0]['device'])) + if 'volume_type' in volume.extra and volume.extra['volume_type']: + vm.info.systems[0].setValue("disk." + str(cont) + ".type", volume.extra['volume_type']) + cont += 1 except Exception as ex: self.log_warn("Error getting volume info: %s" % get_ex_error(ex)) diff --git a/doc/source/REST.rst b/doc/source/REST.rst index e5a2de0c5..110c79f35 100644 --- a/doc/source/REST.rst +++ b/doc/source/REST.rst @@ -133,12 +133,13 @@ POST ``http://imserver.com/infrastructures`` the infrastructure with the following format (memory unit MB, disk and storage unit GB):: { - 'compute': [ - {'cpu': 2, 'memory': 4096, 'disk': 20}, - {'cpu': 1, 'memory': 2048, 'disk': 10} + "compute": [ + {"cpuCores": 2, "memoryInMegabytes": 4096, "diskSizeInGigabytes": 20}, + {"cpuCores": 1, "memoryInMegabytes": 2048, "diskSizeInGigabytes": 10} ], - 'storage': [ - {'size': 100} + "storage": [ + {"sizeInGigabytes": 100, "type": "lvm"}, + {"sizeInGigabytes": 200}, ] } diff --git a/doc/source/xmlrpc.rst b/doc/source/xmlrpc.rst index d1a9e4144..d1557653e 100644 --- a/doc/source/xmlrpc.rst +++ b/doc/source/xmlrpc.rst @@ -430,11 +430,12 @@ This is the list of method names: with the following format (memory unit MB, disk and storage unit GB):: { - 'compute': [ - {'cpu': 2, 'memory': 4096, 'disk': 20}, - {'cpu': 1, 'memory': 2048, 'disk': 10} + "compute": [ + {"cpuCores": 2, "memoryInMegabytes": 4096, "diskSizeInGigabytes": 20}, + {"cpuCores": 1, "memoryInMegabytes": 2048, "diskSizeInGigabytes": 10} ], - 'storage': [ - {'size': 100} + "storage": [ + {"sizeInGigabytes": 100, "type": "lvm"}, + {"sizeInGigabytes": 200}, ] } From f18b6ead73ecaac81a76ef959815eaf003612d01 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Thu, 9 May 2024 13:02:31 +0200 Subject: [PATCH 19/30] Fix test --- test/files/test_simple.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/files/test_simple.json b/test/files/test_simple.json index 9d3a39f2a..ad8046bc2 100644 --- a/test/files/test_simple.json +++ b/test/files/test_simple.json @@ -17,7 +17,7 @@ "disk.0.os.credentials.username": "ubuntu", "disk.0.os.name": "linux", "id": "front", - "memory.size_min": 536870912, + "memory.size_min": 1073741824, "net_interface.0.connection": "publica", "net_interface.1.connection": "privada" }, @@ -28,7 +28,7 @@ "disk.0.image.url": "one://ramses.i3m.upv.es/1396", "disk.0.os.name": "linux", "id": "wn", - "memory.size_min": 536870912, + "memory.size_min": 1073741824, "net_interface.0.connection": "privada" }, { From 64f00a4c00a2fcafef19f3b6267e77416899af1f Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Thu, 9 May 2024 13:11:32 +0200 Subject: [PATCH 20/30] Fix test --- test/unit/REST.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/REST.py b/test/unit/REST.py index 492b022c7..b646be51f 100755 --- a/test/unit/REST.py +++ b/test/unit/REST.py @@ -331,8 +331,8 @@ def test_CreateInfrastructure(self, bottle_request, get_infrastructure, CreateIn bottle_request.body = read_file_as_bytes("../files/test_simple.json") bottle_request.params = {"dry_run": "yes"} res = RESTCreateInfrastructure() - self.assertEqual(res, ('{"compute": [{"cpuCores": 1, "memoryInMegabytes": 512},' - ' {"cpuCores": 1, "memoryInMegabytes": 512}], "storage": []}')) + self.assertEqual(res, ('{"compute": [{"cpuCores": 1, "memoryInMegabytes": 1024},' + ' {"cpuCores": 1, "memoryInMegabytes": 1024}], "storage": []}')) @patch("IM.InfrastructureManager.InfrastructureManager.CreateInfrastructure") @patch("bottle.request") From de02b3dce9c818339da1f747181b1486fc4a5397 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Thu, 9 May 2024 17:13:09 +0200 Subject: [PATCH 21/30] Fix test --- test/files/test_simple.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/files/test_simple.json b/test/files/test_simple.json index ad8046bc2..c12648d99 100644 --- a/test/files/test_simple.json +++ b/test/files/test_simple.json @@ -13,8 +13,6 @@ "cpu.arch": "x86_64", "cpu.count_min": 1, "disk.0.image.url": "one://ramses.i3m.upv.es/1593", - "disk.0.os.credentials.password": "GRyCAP01", - "disk.0.os.credentials.username": "ubuntu", "disk.0.os.name": "linux", "id": "front", "memory.size_min": 1073741824, From 55e1f1fd69799d355269cd29186b955678d8dafc Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Thu, 9 May 2024 17:14:12 +0200 Subject: [PATCH 22/30] Change EstimateResouces return format --- IM/InfrastructureManager.py | 40 +++++++++++++++++++++++++++---------- doc/source/REST.rst | 29 +++++++++++++++++++-------- doc/source/xmlrpc.rst | 29 +++++++++++++++++++-------- test/unit/REST.py | 6 ++++-- test/unit/test_im_logic.py | 11 +++++++--- 5 files changed, 83 insertions(+), 32 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index f219d1f48..6db4d8702 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1908,20 +1908,34 @@ def EstimateResouces(radl_data, auth): - radl(str): RADL description. - auth(Authentication): parsed authentication tokens. - Return(dict): dict with the estimated amount of needed to deploy the infrastructure + Return(list): list with the estimated amount of needed to deploy the infrastructure with the following structure: + [ { - 'compute': [ - {'cpu': 2, 'memory': 4096, 'disk': 20}, - {'cpu': 1, 'memory': 2048, 'disk': 10} - ], - 'storage': [ - {'size': 100} - ] + "cloudType": "OpenStack", + "cloudEndpoint": "http://openstack.example.com:5000", + + "compute": [ + { + "cpuCores": 2, + "memoryInMegabytes": 4096, + "diskSizeInGigabytes": 20 + }, + { + "cpuCores": 1, + "memoryInMegabytes": 2048, + "diskSizeInGigabytes": 10 + } + ], + "storage": [ + {"sizeInGigabytes": 100, "type": "ceph"}, + {"sizeInGigabytes": 100} + ] } + ] """ - res = {"compute": [], "storage": []} + res = {} InfrastructureManager.logger.info("Getting the cost of the infrastructure") # First check the auth data @@ -1979,6 +1993,10 @@ def EstimateResouces(radl_data, auth): # Get the cost of the infrastructure for deploy, cloud_id, cloud in deploy_items: + if cloud_id not in res: + res[cloud_id] = {"cloudType": cloud.type, "cloudEndpoint": cloud.cloud.get_url(), + "compute": [], "storage": []} + if not deploy.id.startswith(IM.InfrastructureInfo.InfrastructureInfo.FAKE_SYSTEM): concrete_system = concrete_systems[cloud_id][deploy.id][0] @@ -1994,7 +2012,7 @@ def EstimateResouces(radl_data, auth): if concrete_system.getValue("disk.0.free_size"): vm['diskSizeInGigabytes'] = concrete_system.getFeature("disk.0.free_size").getValue('G') - res["compute"].append(vm) + res[cloud_id]["compute"].append(vm) cont = 1 while (concrete_system.getValue("disk." + str(cont) + ".size")): @@ -2002,7 +2020,7 @@ def EstimateResouces(radl_data, auth): vol_info = {"sizeInGigabytes": volume_size} if concrete_system.getValue("disk." + str(cont) + ".type"): vol_info["type"] = concrete_system.getValue("disk." + str(cont) + ".type") - res["storage"].append(vol_info) + res[cloud_id]["storage"].append(vol_info) cont += 1 return res diff --git a/doc/source/REST.rst b/doc/source/REST.rst index 110c79f35..d74284e29 100644 --- a/doc/source/REST.rst +++ b/doc/source/REST.rst @@ -133,14 +133,27 @@ POST ``http://imserver.com/infrastructures`` the infrastructure with the following format (memory unit MB, disk and storage unit GB):: { - "compute": [ - {"cpuCores": 2, "memoryInMegabytes": 4096, "diskSizeInGigabytes": 20}, - {"cpuCores": 1, "memoryInMegabytes": 2048, "diskSizeInGigabytes": 10} - ], - "storage": [ - {"sizeInGigabytes": 100, "type": "lvm"}, - {"sizeInGigabytes": 200}, - ] + "ost1": { + "cloudType": "OpenStack", + "cloudEndpoint": "http://openstack.example.com:5000", + + "compute": [ + { + "cpuCores": 2, + "memoryInMegabytes": 4096, + "diskSizeInGigabytes": 20 + }, + { + "cpuCores": 1, + "memoryInMegabytes": 2048, + "diskSizeInGigabytes": 10 + } + ], + "storage": [ + {"sizeInGigabytes": 100, "type": "ceph"}, + {"sizeInGigabytes": 100} + ] + } } PUT ``http://imserver.com/infrastructures`` diff --git a/doc/source/xmlrpc.rst b/doc/source/xmlrpc.rst index d1557653e..3bbb37c38 100644 --- a/doc/source/xmlrpc.rst +++ b/doc/source/xmlrpc.rst @@ -430,12 +430,25 @@ This is the list of method names: with the following format (memory unit MB, disk and storage unit GB):: { - "compute": [ - {"cpuCores": 2, "memoryInMegabytes": 4096, "diskSizeInGigabytes": 20}, - {"cpuCores": 1, "memoryInMegabytes": 2048, "diskSizeInGigabytes": 10} - ], - "storage": [ - {"sizeInGigabytes": 100, "type": "lvm"}, - {"sizeInGigabytes": 200}, - ] + "ost1": { + "cloudType": "OpenStack", + "cloudEndpoint": "http://openstack.example.com:5000", + + "compute": [ + { + "cpuCores": 2, + "memoryInMegabytes": 4096, + "diskSizeInGigabytes": 20 + }, + { + "cpuCores": 1, + "memoryInMegabytes": 2048, + "diskSizeInGigabytes": 10 + } + ], + "storage": [ + {"sizeInGigabytes": 100, "type": "ceph"}, + {"sizeInGigabytes": 100} + ] + } } diff --git a/test/unit/REST.py b/test/unit/REST.py index b646be51f..4b3ac4ec7 100755 --- a/test/unit/REST.py +++ b/test/unit/REST.py @@ -331,8 +331,10 @@ def test_CreateInfrastructure(self, bottle_request, get_infrastructure, CreateIn bottle_request.body = read_file_as_bytes("../files/test_simple.json") bottle_request.params = {"dry_run": "yes"} res = RESTCreateInfrastructure() - self.assertEqual(res, ('{"compute": [{"cpuCores": 1, "memoryInMegabytes": 1024},' - ' {"cpuCores": 1, "memoryInMegabytes": 1024}], "storage": []}')) + self.assertEqual(res, ('{"one": {"cloudType": "OpenNebula", "cloudEndpoint":' + ' "http://ramses.i3m.upv.es:2633",' + ' "compute": [{"cpuCores": 1, "memoryInMegabytes": 1024},' + ' {"cpuCores": 1, "memoryInMegabytes": 1024}], "storage": []}}')) @patch("IM.InfrastructureManager.InfrastructureManager.CreateInfrastructure") @patch("bottle.request") diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index c16668674..c2389b382 100644 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -1550,9 +1550,14 @@ def test_estimate_resources(self): deploy wn 1 """ res = IM.EstimateResouces(radl, self.getAuth([0], [], [("Dummy", 0)])) - self.assertEqual(res, {'compute': [{'cpuCores': 2, 'memoryInMegabytes': 4096, 'diskSizeInGigabytes': 20}, - {'cpuCores': 1, 'memoryInMegabytes': 2048, 'diskSizeInGigabytes': 10}], - 'storage': [{'sizeInGigabytes': 100}]}) + self.assertEqual(res, { + 'cloud0': { + 'cloudType': 'Dummy', + 'cloudEndpoint': 'http://server.com:80/path', + 'compute': [{'cpuCores': 2, 'memoryInMegabytes': 4096, 'diskSizeInGigabytes': 20}, + {'cpuCores': 1, 'memoryInMegabytes': 2048, 'diskSizeInGigabytes': 10}], + 'storage': [{'sizeInGigabytes': 100}] + }}) if __name__ == "__main__": From 449e8affbe66b70cefc0cc368eaa4301b85e6d59 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 10 May 2024 09:16:59 +0200 Subject: [PATCH 23/30] Add old galaxy sever in conf-ansible --- contextualization/conf-ansible.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contextualization/conf-ansible.yml b/contextualization/conf-ansible.yml index 5ea7096cb..1da87a2c8 100644 --- a/contextualization/conf-ansible.yml +++ b/contextualization/conf-ansible.yml @@ -232,3 +232,6 @@ - { section: 'defaults', option: 'ansible_python_interpreter', value: 'auto' } - { section: 'defaults', option: 'transport', value: 'ssh' } - { section: 'ssh_connection', option: 'ssh_args', value: '-o ControlMaster=auto -o ControlPersist=900s -o UserKnownHostsFile=/dev/null' } + - { section: 'galaxy', option: 'server_list', value: 'galaxy, oldgalaxy' } + - { section: 'galaxy_server.galaxy', option: 'url', value: 'https://galaxy.ansible.com/api/' } + - { section: 'galaxy_server.oldgalaxy', option: 'url', value: 'https://old-galaxy.ansible.com/api/' } From 904650cf3856a86089d6f229910ea064b81d8d03 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 10 May 2024 09:49:18 +0200 Subject: [PATCH 24/30] Update comment --- IM/InfrastructureManager.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 6db4d8702..ce043afb8 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -1908,31 +1908,31 @@ def EstimateResouces(radl_data, auth): - radl(str): RADL description. - auth(Authentication): parsed authentication tokens. - Return(list): list with the estimated amount of needed to deploy the infrastructure + Return(dict): dict with the estimated amount of needed to deploy the infrastructure with the following structure: - [ - { + { + "ost1": { "cloudType": "OpenStack", "cloudEndpoint": "http://openstack.example.com:5000", "compute": [ - { + { "cpuCores": 2, "memoryInMegabytes": 4096, "diskSizeInGigabytes": 20 - }, - { + }, + { "cpuCores": 1, "memoryInMegabytes": 2048, "diskSizeInGigabytes": 10 - } + } ], "storage": [ {"sizeInGigabytes": 100, "type": "ceph"}, {"sizeInGigabytes": 100} ] } - ] + } """ res = {} From cccb84cf1e0aaea92da89ff91bd231c3b41725e9 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Fri, 10 May 2024 11:35:00 +0200 Subject: [PATCH 25/30] Fix ansible_install script --- contextualization/ansible_install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contextualization/ansible_install.sh b/contextualization/ansible_install.sh index caea5aa8d..0ad3fce6a 100755 --- a/contextualization/ansible_install.sh +++ b/contextualization/ansible_install.sh @@ -1,6 +1,6 @@ #!/bin/sh -ANSIBLE_VERSION="2.9.21" +ANSIBLE_VERSION="4.10.0" distribution_id() { RETVAL="" @@ -71,7 +71,7 @@ else pip3 install "pip>=20.0" pip3 install -U "setuptools<66.0" - pip3 install "pyOpenSSL>20.0,<22.1.0" "cryptography>37.0.0,<39.0.0" pyyaml jmespath scp "paramiko>=2.9.5" --prefer-binary + pip3 install "pyOpenSSL>20.0,<22.1.0" "cryptography>37.0.0,<39.0.0" pyyaml jmespath scp "paramiko>=2.9.5" packaging --prefer-binary pip3 install ansible==$ANSIBLE_VERSION --prefer-binary fi From b9026d652dda77757bc9655c2a3ab9cf93862489 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Mon, 13 May 2024 08:12:15 +0200 Subject: [PATCH 26/30] Increase timeout in test --- test/integration/TestIM.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/TestIM.py b/test/integration/TestIM.py index e8eddb4fc..c1903dc39 100755 --- a/test/integration/TestIM.py +++ b/test/integration/TestIM.py @@ -272,7 +272,7 @@ def test_19_addresource(self): str(len(vm_ids)) + "). It must be 4")) all_configured = self.wait_inf_state( - self.inf_id, VirtualMachine.CONFIGURED, 1500) + self.inf_id, VirtualMachine.CONFIGURED, 2100) self.assertTrue( all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).") From ab4f6996b451a1db96293e473cd54e14b64f039a Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Mon, 13 May 2024 15:42:50 +0200 Subject: [PATCH 27/30] Fix error in reconfigure --- contextualization/ansible_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contextualization/ansible_install.sh b/contextualization/ansible_install.sh index 0ad3fce6a..fcdcbb3f1 100755 --- a/contextualization/ansible_install.sh +++ b/contextualization/ansible_install.sh @@ -76,7 +76,7 @@ else fi # Create the config file -mkdir /etc/ansible +ls /etc/ansible || mkdir /etc/ansible cat > /etc/ansible/ansible.cfg < Date: Mon, 13 May 2024 15:43:05 +0200 Subject: [PATCH 28/30] Increase timeout --- test/integration/TestIM.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/TestIM.py b/test/integration/TestIM.py index c1903dc39..d432c5f94 100755 --- a/test/integration/TestIM.py +++ b/test/integration/TestIM.py @@ -337,7 +337,7 @@ def test_22_removeresource(self): msg="ERROR unexpected state. Expected 'running' and obtained " + vm_state) all_configured = self.wait_inf_state( - self.inf_id, VirtualMachine.CONFIGURED, 1200) + self.inf_id, VirtualMachine.CONFIGURED, 1800) self.assertTrue( all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).") From 3f53c4d4be256350cfc94340584c017f041b0669 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Tue, 14 May 2024 09:28:48 +0200 Subject: [PATCH 29/30] Increase timeout --- test/integration/TestIM.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/integration/TestIM.py b/test/integration/TestIM.py index d432c5f94..c1b3aaaf6 100755 --- a/test/integration/TestIM.py +++ b/test/integration/TestIM.py @@ -635,7 +635,7 @@ def test_80_create_ansible_host(self): self.__class__.inf_id = [inf_id] all_configured = self.wait_inf_state( - inf_id, VirtualMachine.CONFIGURED, 900) + inf_id, VirtualMachine.CONFIGURED, 1200) self.assertTrue( all_configured, msg="ERROR waiting the ansible master to be configured (timeout).") @@ -672,7 +672,7 @@ def test_80_create_ansible_host(self): self.__class__.inf_id.append(inf_id) all_configured = self.wait_inf_state( - inf_id, VirtualMachine.CONFIGURED, 900) + inf_id, VirtualMachine.CONFIGURED, 1200) self.assertTrue( all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).") @@ -723,7 +723,7 @@ def test_96_create(self): success, msg="ERROR calling CreateInfrastructure: " + str(inf_id)) self.__class__.inf_id = [inf_id] - all_configured = self.wait_inf_state(inf_id, VirtualMachine.CONFIGURED, 900) + all_configured = self.wait_inf_state(inf_id, VirtualMachine.CONFIGURED, 1200) self.assertTrue( all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).") @@ -759,7 +759,7 @@ def test_98_proxy(self): self.assertTrue(success, msg="ERROR calling CreateInfrastructure: " + str(inf_id)) self.__class__.inf_id = [inf_id] - all_configured = self.wait_inf_state(inf_id, VirtualMachine.CONFIGURED, 900) + all_configured = self.wait_inf_state(inf_id, VirtualMachine.CONFIGURED, 1200) self.assertTrue(all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).") (success, vminfo) = self.server.GetVMInfo(inf_id, 0, self.auth_data) @@ -786,7 +786,7 @@ def test_98_proxy(self): (success, inf_id2) = self.server.CreateInfrastructure(radl, self.auth_data) self.__class__.inf_id.append(inf_id2) - all_configured = self.wait_inf_state(inf_id2, VirtualMachine.CONFIGURED, 900) + all_configured = self.wait_inf_state(inf_id2, VirtualMachine.CONFIGURED, 1200) self.assertTrue(all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).") def test_99_destroy(self): From 312f657597de9ba0c79fe1a64636006d10a8f1e6 Mon Sep 17 00:00:00 2001 From: Miguel Caballer Date: Tue, 14 May 2024 13:26:15 +0200 Subject: [PATCH 30/30] Increase timeout --- test/integration/TestIM.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/TestIM.py b/test/integration/TestIM.py index c1b3aaaf6..da9ef55ac 100755 --- a/test/integration/TestIM.py +++ b/test/integration/TestIM.py @@ -698,7 +698,7 @@ def test_90_create(self): self.__class__.inf_id = [inf_id] all_configured = self.wait_inf_state( - inf_id, VirtualMachine.CONFIGURED, 1800) + inf_id, VirtualMachine.CONFIGURED, 2100) self.assertTrue( all_configured, msg="ERROR waiting the infrastructure to be configured (timeout).")