Ejemplo n.º 1
0
    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()
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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