From 878e4d3e59b8796c5337e35db3a24ad0a88d21f4 Mon Sep 17 00:00:00 2001 From: Roque <roqueporchetto@gmail.com> Date: Thu, 19 Apr 2018 10:26:48 +0200 Subject: [PATCH] scalability: reinstall software during tests - allow slapos master communicator to supply software destruction - runner reinstalls software on every commit (temporarily) - refactor in software profile construction - some try controls added /reviewed-on https://lab.nexedi.com/nexedi/erp5/merge_requests/644 --- erp5/util/testnode/ScalabilityTestRunner.py | 73 ++++++++++--------- .../util/testnode/SlapOSMasterCommunicator.py | 9 ++- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/erp5/util/testnode/ScalabilityTestRunner.py b/erp5/util/testnode/ScalabilityTestRunner.py index b9535010ec..5ebd689865 100644 --- a/erp5/util/testnode/ScalabilityTestRunner.py +++ b/erp5/util/testnode/ScalabilityTestRunner.py @@ -133,7 +133,7 @@ class ScalabilityTestRunner(): self.last_slapos_answer_request = [] self.frontend_instance_guid = None - def _prepareSlapOS(self, software_path, computer_guid, create_partition=0): + def _prepareSlapOS(self, software_path, computer_guid, create_partition=0, state="available"): # create_partition is kept for compatibility """ A proxy to supply : Install a software on a specific node @@ -141,7 +141,7 @@ class ScalabilityTestRunner(): logger.info("testnode, supply : %s %s", software_path, computer_guid) if self.authorize_supply : self.remaining_software_installation_dict[computer_guid] = software_path - self.slapos_communicator.supply(software_path, computer_guid) + self.slapos_communicator.supply(software_path, computer_guid, state) return {'status_code' : 0} else: raise ValueError("Too late to supply now. ('self.authorize_supply' is False)") @@ -212,7 +212,7 @@ class ScalabilityTestRunner(): else: raise ValueError("Softwares release not ready yet to launch instan\ ces or already launched.") - return {'status_code' : 1} + return {'status_code' : 1} def prepareSlapOSForTestNode(self, test_node_slapos=None): """ @@ -336,12 +336,9 @@ Require valid-user htaccess_file.write(file_content) htaccess_file.close() password_path = testsuite_directory + PASSWORD_FILE - password_file = open(password_path, "r+") if os.path.isfile(password_path) else open(password_path, "w+") - password = password_file.read() - if len(password) != PASSWORD_LENGTH: + with open(password_path, "w") as password_file: password = ''.join(random.choice(string.digits + string.letters) for i in xrange(PASSWORD_LENGTH)) password_file.write(password) - password_file.close() user = TESTNODE_USER command = [apache_htpasswd, "-bc", testsuite_directory + HTPASSWD, user, password] self.testnode.process_manager.spawn(*command) @@ -374,22 +371,8 @@ Require valid-user os.path.join("["+self.testnode.config['httpd_ip']+"]"+":"+self.testnode.config['httpd_software_access_port'], "software",self.randomized_path)) self.reachable_profile = os.path.join(self.reachable_address, "software.cfg") - # Write the reachable address in the software.cfg file, - # by replacing <obfuscated_url> occurences by the current reachable address. - software_file = open(node_test_suite.custom_profile_path, "r") - file_content = software_file.readlines() - new_file_content = [] - for line in file_content: - new_file_content.append(line.replace('<obfuscated_url>', self.reachable_address)) - software_file.close() - os.remove(node_test_suite.custom_profile_path) - software_file = open(node_test_suite.custom_profile_path, "w") - for line in new_file_content: - software_file.write(line) - software_file.close() def newFrontendMasterSoftware(self, frontend_master_reference, frontend_software): - frontend_master_reference = frontend_master_reference.replace(";",",") slappart_directory = self.testnode.config['srv_directory'].rsplit("srv", 1)[0] software_dict_file = slappart_directory + "var/" + SR_DICT software_dict = self.getDictionaryFromFile(software_dict_file) @@ -488,6 +471,7 @@ Require valid-user supply, self.reachable_profile, computer_guid=self.launcher_nodes_computer_guid[0]) + # Ask for SR installation for computer_guid in self.involved_nodes_computer_guid: self._prepareSlapOS(self.reachable_profile, computer_guid) @@ -507,15 +491,20 @@ Require valid-user # Ask for frontend SR installation and instance request # XXX TODO: frontend software url will come from test_configuration soon self.frontend_software = FRONTEND_SOFTWARE - self.frontend_instance_guid = self.prepareFrontendMasterInstance(self.launcher_nodes_computer_guid[0], - self.frontend_software, - node_test_suite.test_suite_title) + try: + self.frontend_instance_guid = self.prepareFrontendMasterInstance(self.launcher_nodes_computer_guid[0], + self.frontend_software, + node_test_suite.test_suite_title) + except Exception as e: + logger.error("Error preparing frontend master instance: " + str(e)) + return {'status_code' : 1} if self.remainSoftwareToInstall() : # All softwares are not installed, however maxtime is elapsed, that's a failure. logger.error("All softwares are not installed.") return {'status_code' : 1} self.authorize_request = True logger.debug("Softwares installed.") + # Launch instance try: self._createInstance(self.reachable_profile, @@ -525,11 +514,10 @@ Require valid-user self.frontend_software, self.frontend_instance_guid) logger.debug("Scalability instance requested.") - except Exception: - msg = "Unable to launch instance" - logger.exception(msg) - raise ValueError(msg) - self._waitInstanceCreation(self.instance_title) + self._waitInstanceCreation(self.instance_title) + except Exception as e: + logger.error("Error creating instance: " + str(e)) + return {'status_code' : 1} return {'status_code' : 0} return {'status_code' : 1} @@ -577,9 +565,9 @@ Require valid-user else: response_dict = json.loads(result['stdout']) if response_dict["status_code"] != 0: - error_message = "Error while bootstrapping: " + response_dict["error_message"] + error_message = "Error while bootstrapping: " + str(response_dict["error_message"]) bootstrap_password = response_dict["password"] - logger.info("Bootstrap password: " + bootstrap_password) + logger.info("Bootstrap password: " + str(bootstrap_password)) except Exception as e: error_message = "Error while bootstrapping: " + str(e) return bootstrap_password, error_message @@ -642,6 +630,7 @@ Require valid-user suite, repo_location = self.makeSuite(node_test_suite.test_suite, self.testnode.config['repository_path_list']) if suite == None: error_message = "Could not find test suite %s in the repositories" % node_test_suite.test_suite + test_result_proxy.reportFailure(stdout=error_message) return {'status_code' : 1, 'error_message': error_message } # Each cluster configuration is tested @@ -649,10 +638,18 @@ Require valid-user # First configuration doesn't need XML configuration update. if count > 0: logger.info("Requesting instance with configuration %d" % count) - self._updateInstanceXML(configuration, self.instance_title, - node_test_suite.test_result, node_test_suite.test_suite, self.frontend_software, self.frontend_instance_guid) - - self.slapos_communicator.waitInstanceStarted(self.instance_title) + try: + self._updateInstanceXML(configuration, self.instance_title, + node_test_suite.test_result, node_test_suite.test_suite, self.frontend_software, self.frontend_instance_guid) + except Exception as e: + error_message = "Error updating instance configuration: " + str(e) + try: + self.slapos_communicator.waitInstanceStarted(self.instance_title) + except Exception as e: + error_message = "Error starting instance: " + str(e) + if error_message: + test_result_proxy.reportFailure(stdout=error_message) + return {'status_code' : 1, 'error_message': error_message } logger.debug("INSTANCE CORRECTLY STARTED") # Start only the current test @@ -740,6 +737,12 @@ Require valid-user error_message = "Error in communication with master: " + str(e) break + # Remove installed software + self.authorize_supply = True + logger.info("Removing installed software") + for computer_guid in self.involved_nodes_computer_guid: + self._prepareSlapOS(self.reachable_profile, computer_guid, state="destroyed") + # If error appears then that's a test failure. if error_message: logger.info("There was an error during the testsuite run: " + str(error_message)) diff --git a/erp5/util/testnode/SlapOSMasterCommunicator.py b/erp5/util/testnode/SlapOSMasterCommunicator.py index ff997b5ba0..728fe766f2 100644 --- a/erp5/util/testnode/SlapOSMasterCommunicator.py +++ b/erp5/util/testnode/SlapOSMasterCommunicator.py @@ -81,12 +81,12 @@ class SlapOSMasterCommunicator(object): self.url = url @retryOnNetworkFailure - def _supply(self): + def _supply(self, state="available"): if self.computer_guid is None: logger.info('Nothing to supply for %s.', self.name) return None logger.info('Supply %s@%s', self.url, self.computer_guid) - return self.slap_supply.supply(self.url, self.computer_guid) + return self.slap_supply.supply(self.url, self.computer_guid, state) @retryOnNetworkFailure def _request(self, state, instance_title=None, request_kw=None, shared=False, software_type="RootSoftwareInstance"): @@ -401,12 +401,12 @@ class SlapOSTester(SlapOSMasterCommunicator): info += "Instance Requested (Parameters): %s\n" % self.request_kw return info - def supply(self, software_path=None, computer_guid=None): + def supply(self, software_path=None, computer_guid=None, state="available"): if software_path is not None: self.url = software_path if computer_guid is not None: self.computer_guid = computer_guid - self._supply() + self._supply(state) def requestInstanceStart(self, instance_title=None, request_kw=None, shared=False, software_type="RootSoftwareInstance"): self.instance = self._request(INSTANCE_STATE_STARTED, instance_title, request_kw, shared, software_type) @@ -494,6 +494,7 @@ class SlapOSTester(SlapOSMasterCommunicator): self._request(INSTANCE_STATE_DESTROYED, instance["title"]) else: root_instance = instance + logger.info("Going to destroy root partition: " + str(instance_title)) self._request(INSTANCE_STATE_DESTROYED, root_instance["title"]) else: logger.info("Instance not found") -- 2.30.9