def _processMessage(self, node, message): event_type = message['event_type'] origin = message['origin'] activity_name = message['name'] description = message['description'] result = message.get('result', None) # Add this event to the node event log. add_event_to_node_event_log(node, origin, activity_name, description, result, message['timestamp']) # Group files together with the ScriptResult they belong. results = {} for sent_file in message.get('files', []): # Set the result type according to the node's status. if node.status in (NODE_STATUS.TESTING, NODE_STATUS.FAILED_TESTING): script_set = node.current_testing_script_set elif (node.status in (NODE_STATUS.COMMISSIONING, NODE_STATUS.FAILED_COMMISSIONING) or node.node_type != NODE_TYPE.MACHINE): script_set = node.current_commissioning_script_set elif node.status in (NODE_STATUS.DEPLOYING, NODE_STATUS.DEPLOYED, NODE_STATUS.FAILED_DEPLOYMENT): script_set = node.current_installation_script_set else: raise ValueError("Invalid status for saving files: %d" % node.status) script_name = sent_file['path'] content = self._retrieve_content(compression=sent_file.get( 'compression', None), encoding=sent_file['encoding'], content=sent_file['content']) process_file(results, script_set, script_name, content, sent_file) # Commit results to the database. for script_result, args in results.items(): script_result.store_result(**args) # At the end of a top-level event, we change the node status. save_node = False if self._is_top_level(activity_name) and event_type == 'finish': if node.status == NODE_STATUS.COMMISSIONING: if result in ['FAIL', 'FAILURE']: node.status = NODE_STATUS.FAILED_COMMISSIONING save_node = True elif node.status == NODE_STATUS.DEPLOYING: if result in ['FAIL', 'FAILURE']: node.mark_failed( comment="Installation failed (refer to the " "installation log for more information).") save_node = True elif node.status == NODE_STATUS.DISK_ERASING: if result in ['FAIL', 'FAILURE']: node.mark_failed(comment="Failed to erase disks.") save_node = True # Deallocate the node if we enter any terminal state. if node.node_type == NODE_TYPE.MACHINE and node.status in [ NODE_STATUS.READY, NODE_STATUS.FAILED_COMMISSIONING ]: node.status_expires = None node.owner = None node.error = 'failed: %s' % description save_node = True elif self._is_top_level(activity_name) and event_type == 'start': if (node.status == NODE_STATUS.DEPLOYING and activity_name == 'cmd-install' and origin == 'curtin'): script_set = node.current_installation_script_set script_result = script_set.find_script_result( script_name=CURTIN_INSTALL_LOG) script_result.status = SCRIPT_STATUS.RUNNING script_result.save(update_fields=['status']) if save_node: node.save()
def _processMessage(self, node, message): # Validate that the node still exists since this is a new transaction. try: node = Node.objects.get(id=node.id) except Node.DoesNotExist: return False event_type = message["event_type"] origin = message["origin"] activity_name = message["name"] description = message["description"] result = message.get("result", None) # LP:1701352 - If no exit code is given by the client default to # 0(pass) unless the signal is fail then set to 1(failure). This allows # a Curtin failure to cause the ScriptResult to fail. failed = result in ["FAIL", "FAILURE"] default_exit_status = 1 if failed else 0 # Add this event to the node event log if 'start' or a 'failure'. if event_type == "start" or failed: add_event_to_node_event_log( node, origin, activity_name, description, event_type, result, message["timestamp"], ) # Group files together with the ScriptResult they belong. results = {} for sent_file in message.get("files", []): # Set the result type according to the node's status. if node.status in ( NODE_STATUS.TESTING, NODE_STATUS.FAILED_TESTING, ): script_set = node.current_testing_script_set elif ( node.status in ( NODE_STATUS.COMMISSIONING, NODE_STATUS.FAILED_COMMISSIONING, ) or node.node_type != NODE_TYPE.MACHINE ): script_set = node.current_commissioning_script_set elif node.status in ( NODE_STATUS.DEPLOYING, NODE_STATUS.DEPLOYED, NODE_STATUS.FAILED_DEPLOYMENT, ): script_set = node.current_installation_script_set else: raise ValueError( "Invalid status for saving files: %d" % node.status ) script_name = sent_file["path"] encoding = sent_file.get("encoding") content = sent_file.get("content") compression = sent_file.get("compression") # Only capture files which has sent content. This occurs when # Curtin is instructed to post the error_tarfile and no error # has occured(LP:1772118). Empty files are still captured as # they are sent as the empty string if content is not None: content = self._retrieve_content( compression, encoding, content ) process_file( results, script_set, script_name, content, sent_file, default_exit_status, ) # Commit results to the database. for script_result, args in results.items(): script_result.store_result(**args) # At the end of a top-level event, we change the node status. save_node = False if self._is_top_level(activity_name) and event_type == "finish": if node.status == NODE_STATUS.COMMISSIONING: # cloud-init may send a failure message if a script reboots # the system. If a script is running which may_reboot ignore # the signal. if failed: script_set = node.current_commissioning_script_set if ( script_set is None or not script_set.scriptresult_set.filter( status=SCRIPT_STATUS.RUNNING, script__may_reboot=True, ).exists() ): node.mark_failed( comment="Commissioning failed, cloud-init " "reported a failure (refer to the event log for " "more information)", commit=False, script_result_status=SCRIPT_STATUS.ABORTED, ) save_node = True elif node.status == NODE_STATUS.DEPLOYING: # XXX: when activity_name == moudles-config, this currently # /always/ fails, since MAAS passes two different versions # for the apt configuration. The only reason why we don't # see additional issues because of this is due to the node # already being marked "Deployed". Right now this is prevented # only in the install_kvm case, but we should make this check # more general when time allows. if failed and not node.install_kvm: node.mark_failed( comment="Installation failed (refer to the " "installation log for more information).", commit=False, ) save_node = True elif ( not failed and activity_name == "modules-final" and node.install_kvm and node.agent_name == "maas-kvm-pod" ): save_node = True _create_pod_for_deployment(node) elif node.status == NODE_STATUS.DISK_ERASING: if failed: node.mark_failed( comment="Failed to erase disks.", commit=False ) save_node = True # Deallocate the node if we enter any terminal state. if node.node_type == NODE_TYPE.MACHINE and node.status in [ NODE_STATUS.READY, NODE_STATUS.FAILED_COMMISSIONING, ]: node.status_expires = None node.owner = None node.error = "failed: %s" % description save_node = True elif self._is_top_level(activity_name) and event_type == "start": if ( node.status == NODE_STATUS.DEPLOYING and activity_name == "cmd-install" and origin == "curtin" ): script_set = node.current_installation_script_set script_result = script_set.find_script_result( script_name=CURTIN_INSTALL_LOG ) script_result.status = SCRIPT_STATUS.RUNNING script_result.save(update_fields=["status"]) # Reset status_expires when Curtin signals its starting or finishing # early commands. This allows users to define early or late commands # which take up to 40 minutes to run. if ( origin == "curtin" and event_type in ["start", "finish"] and activity_name in [ "cmd-install/stage-early", "cmd-install", "cmd-install/stage-late", ] ): node.reset_status_expires() save_node = True if save_node: node.save() return True
def _processMessage(self, node, message): # Validate that the node still exists since this is a new transaction. try: node = Node.objects.get(id=node.id) except Node.DoesNotExist: return False event_type = message['event_type'] origin = message['origin'] activity_name = message['name'] description = message['description'] result = message.get('result', None) # LP:1701352 - If no exit code is given by the client default to # 0(pass) unless the signal is fail then set to 1(failure). This allows # a Curtin failure to cause the ScriptResult to fail. default_exit_status = 1 if result in ['FAIL', 'FAILURE'] else 0 # Add this event to the node event log. add_event_to_node_event_log(node, origin, activity_name, description, result, message['timestamp']) # Group files together with the ScriptResult they belong. results = {} for sent_file in message.get('files', []): # Set the result type according to the node's status. if node.status in (NODE_STATUS.TESTING, NODE_STATUS.FAILED_TESTING): script_set = node.current_testing_script_set elif (node.status in (NODE_STATUS.COMMISSIONING, NODE_STATUS.FAILED_COMMISSIONING) or node.node_type != NODE_TYPE.MACHINE): script_set = node.current_commissioning_script_set elif node.status in (NODE_STATUS.DEPLOYING, NODE_STATUS.DEPLOYED, NODE_STATUS.FAILED_DEPLOYMENT): script_set = node.current_installation_script_set else: raise ValueError("Invalid status for saving files: %d" % node.status) script_name = sent_file['path'] encoding = sent_file.get('encoding') content = sent_file.get('content') compression = sent_file.get('compression') # Only capture files which has sent content. This occurs when # Curtin is instructed to post the error_tarfile and no error # has occured(LP:1772118). Empty files are still captured as # they are sent as the empty string if content is not None: content = self._retrieve_content(compression, encoding, content) process_file(results, script_set, script_name, content, sent_file, default_exit_status) # Commit results to the database. for script_result, args in results.items(): script_result.store_result(**args) # At the end of a top-level event, we change the node status. save_node = False if self._is_top_level(activity_name) and event_type == 'finish': if node.status == NODE_STATUS.COMMISSIONING: # cloud-init may send a failure message if a script reboots # the system. If a script is running which may_reboot ignore # the signal. if result in ['FAIL', 'FAILURE']: script_set = node.current_commissioning_script_set if (script_set is None or not script_set.scriptresult_set.filter( status=SCRIPT_STATUS.RUNNING, script__may_reboot=True).exists()): node.mark_failed( comment="Commissioning failed, cloud-init " "reported a failure (refer to the event log for " "more information)", commit=False, script_result_status=SCRIPT_STATUS.ABORTED) save_node = True elif node.status == NODE_STATUS.DEPLOYING: if result in ['FAIL', 'FAILURE']: node.mark_failed( comment="Installation failed (refer to the " "installation log for more information).", commit=False) save_node = True elif node.status == NODE_STATUS.DISK_ERASING: if result in ['FAIL', 'FAILURE']: node.mark_failed(comment="Failed to erase disks.", commit=False) save_node = True # Deallocate the node if we enter any terminal state. if node.node_type == NODE_TYPE.MACHINE and node.status in [ NODE_STATUS.READY, NODE_STATUS.FAILED_COMMISSIONING ]: node.status_expires = None node.owner = None node.error = 'failed: %s' % description save_node = True elif self._is_top_level(activity_name) and event_type == 'start': if (node.status == NODE_STATUS.DEPLOYING and activity_name == 'cmd-install' and origin == 'curtin'): script_set = node.current_installation_script_set script_result = script_set.find_script_result( script_name=CURTIN_INSTALL_LOG) script_result.status = SCRIPT_STATUS.RUNNING script_result.save(update_fields=['status']) if save_node: node.save() return True