def get_slave(self, slave_id=None, slave_url=None):
        """
        Get the instance of given slave by either the slave's id or url. Only one of slave_id or slave_url should be
        specified.

        :param slave_id: The id of the slave to return
        :type slave_id: int
        :param slave_url: The url of the slave to return
        :type slave_url: str
        :return: The instance of the slave
        :rtype: Slave
        """
        if (slave_id is None) == (slave_url is None):
            raise ValueError(
                'Only one of slave_id or slave_url should be specified to get_slave().'
            )

        if slave_id is not None:
            for slave in self._all_slaves_by_url.values():
                if slave.id == slave_id:
                    return slave
        else:
            if slave_url in self._all_slaves_by_url:
                return self._all_slaves_by_url[slave_url]

        raise ItemNotFoundError(
            'Requested slave ({}) does not exist.'.format(slave_id))
Exemple #2
0
 def subjob(self, subjob_id):
     """
     Returns a single subjob
     :type subjob_id: int
     :rtype: Subjob
     """
     subjob = self._all_subjobs_by_id.get(subjob_id)
     if subjob is None:
         raise ItemNotFoundError('Invalid subjob id.')
     return subjob
Exemple #3
0
    def get(cls, build_id: int) -> Build:
        """
        Returns a build by id
        :param build_id: The id for the build whose status we are getting
        """
        build = cls._all_builds_by_id.get(build_id)
        if build is None:
            raise ItemNotFoundError('Invalid build id: {}.'.format(build_id))

        return build
    def get_build(self, build_id):
        """
        Returns a build by id
        :param build_id: The id for the build whose status we are getting
        :type build_id: int
        :rtype: Build
        """
        build = self._all_builds_by_id.get(build_id)
        if build is None:
            raise ItemNotFoundError('Invalid build id.')

        return build
    def get_build(self, build_id):
        """
        Returns a build by id
        :param build_id: The id for the build whose status we are getting
        :type build_id: int
        :rtype: Build
        """
        build = BuildStore.get(build_id)
        if build is None:
            raise ItemNotFoundError('Invalid build id: {}.'.format(build_id))

        return build
Exemple #6
0
    def get_console_output(
        self,
        build_id: int,
        subjob_id: int,
        atom_id: int,
        result_root: str,
        max_lines: int = 50,
        offset_line: Optional[int] = None,
    ):
        """
        Return the console output if it exists, raises an ItemNotFound error if not.

        On success, the response contains keys: offset_line, num_lines, total_num_lines, and content.

        e.g.:
        {
            'offset_line': 0,
            'num_lines': 50,
            'total_num_lines': 167,
            'content': 'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\n...',
        }

        :param build_id: build id
        :param subjob_id: subjob id
        :param atom_id: atom id
        :param result_root: the sys path to either the results or artifacts directory where results are stored.
        :param max_lines: The maximum total number of lines to return. If this max_lines + offset_line lines do not
            exist in the output file, just return what there is.
        :param offset_line: The line number (0-indexed) to start reading content for. If none is specified, we will
            return the console output starting from the end of the file.
        """
        if offset_line is not None and offset_line < 0:
            raise BadRequestError(
                '\'offset_line\' must be greater than or equal to zero.')
        if max_lines <= 0:
            raise BadRequestError('\'max_lines\' must be greater than zero.')

        segment = BuildArtifact.get_console_output(build_id, subjob_id,
                                                   atom_id, result_root,
                                                   max_lines, offset_line)

        if not segment:
            raise ItemNotFoundError(
                'Console output does not exist on this host for '
                'build {}, subjob {}, atom {}.'.format(build_id, subjob_id,
                                                       atom_id))
        return {
            'offset_line': segment.offset_line,
            'num_lines': segment.num_lines,
            'total_num_lines': segment.total_num_lines,
            'content': segment.content,
        }
    def get_console_output(self, build_id, subjob_id, atom_id, result_root, max_lines=50, offset_line=None):
        """
        Return the console output if it exists, raises an ItemNotFound error if not.

        On success, the response contains keys: offset_line, num_lines, total_num_lines, and content.

        e.g.:
        {
            'offset_line': 0,
            'num_lines': 50,
            'total_num_lines': 167,
            'content': 'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\n...',
        }

        :type build_id: int
        :type subjob_id: int
        :type atom_id: int
        :param result_root: the sys path to either the results or artifacts directory where results are stored.
        :type result_root: str
        :param max_lines: The maximum total number of lines to return. If this max_lines + offset_line lines do not
            exist in the output file, just return what there is.
        :type max_lines: int
        :param offset_line: The line number (0-indexed) to start reading content for. If none is specified, we will
            return the console output starting from the end of the file.
        :type offset_line: int | None
        """
        if offset_line is not None and offset_line < 0:
            raise BadRequestError('\'offset_line\' must be greater than or equal to zero.')
        if max_lines <= 0:
            raise BadRequestError('\'max_lines\' must be greater than zero.')

        artifact_dir = BuildArtifact.atom_artifact_directory(build_id, subjob_id, atom_id, result_root=result_root)
        output_file = os.path.join(artifact_dir, BuildArtifact.OUTPUT_FILE)

        if not os.path.isfile(output_file):
            raise ItemNotFoundError('Output file doesn\'t exist for build_id: {} subjob_id: {} atom_id: {}'.format(
                build_id, subjob_id, atom_id))

        try:
            console_output = ConsoleOutput(output_file)
            segment = console_output.segment(max_lines, offset_line)
        except ValueError as e:
            raise BadRequestError(e)

        return {
            'offset_line': segment.offset_line,
            'num_lines': segment.num_lines,
            'total_num_lines': segment.total_num_lines,
            'content': segment.content,
        }
Exemple #8
0
    def get_path_for_build_results_archive(self, build_id: int, is_tar_request: bool=False) -> str:
        """
        Given a build id, get the absolute file path for the archive file containing the build results.

        :param build_id: The build id for which to retrieve the artifacts archive file
        :param is_tar_request: If true, download the tar.gz archive instead of a zip.
        :return: The path to the archived results file
        """
        build = self._all_builds_by_id.get(build_id)  # type: Build
        if build is None:
            raise ItemNotFoundError('Invalid build id.')

        archive_file = build.artifacts_tar_file if is_tar_request else build.artifacts_zip_file
        if archive_file is None:
            raise ItemNotReadyError('Build artifact file is not yet ready. Try again later.')

        return archive_file
    def handle_request_to_update_build(self, build_id, update_params):
        """
        Updates the state of a build with the values passed in.  Used for cancelling running builds.

        :type build_id: int
        :param update_params: The fields that should be updated and their new values
        :type update_params: dict [str, str]
        :return: The success/failure and the response we want to send to the requestor
        :rtype: tuple [bool, dict [str, str]]
        """
        build = self._all_builds_by_id.get(int(build_id))
        if build is None:
            raise ItemNotFoundError('Invalid build id.')

        success, response = build.validate_update_params(update_params)
        if not success:
            return success, response
        return build.update_state(update_params), {}
    def get_path_for_build_results_archive(self, build_id):
        """
        Given a build id, get the absolute file path for the archive file containing the build results.

        :param build_id: The build id for which to retrieve the artifacts archive file
        :type build_id: int
        :return: The path to the archived results file
        :rtype: str
        """
        build = self._all_builds_by_id.get(build_id)
        if build is None:
            raise ItemNotFoundError('Invalid build id.')

        archive_file = build.artifacts_archive_file
        if archive_file is None:
            raise ItemNotReadyError('Build artifact file is not yet ready. Try again later.')

        return archive_file
    def get_slave(self, slave_id: int=None, slave_url: str=None) -> Slave:
        """
        Look for a slave in the registry and if not found raise "ItemNotFoundError" exception.

        :raises ItemNotFoundError when slave does not exists in Registry.
        """
        if (slave_id is None) == (slave_url is None):
            raise ValueError('Only one of slave_id or slave_url should be specified to get_slave().')

        if slave_id is not None:
            if slave_id in self._all_slaves_by_id:
                return self._all_slaves_by_id[slave_id]
        else:
            if slave_url in self._all_slaves_by_url:
                return self._all_slaves_by_url[slave_url]
        if slave_id is not None:
            error_msg = 'Requested slave (slave_id={}) does not exist.'.format(slave_id)
        else:
            error_msg = 'Requested slave (slave_url={}) does not exist.'.format(slave_url)
        raise ItemNotFoundError(error_msg)
Exemple #12
0
    def save(self):
        """Serialize the Build object and update all of the parts to the database."""
        with Connection.get() as session:
            build_schema = session.query(BuildSchema).filter(BuildSchema.build_id == self._build_id).first()
            failed_artifact_directories_schema = session.query(FailedArtifactDirectoriesSchema) \
                .filter(FailedArtifactDirectoriesSchema.build_id == self._build_id) \
                .all()
            failed_subjob_atom_pairs_schema = session.query(FailedSubjobAtomPairsSchema) \
                .filter(FailedSubjobAtomPairsSchema.build_id == self._build_id) \
                .all()
            atoms_schema = session.query(AtomsSchema).filter(AtomsSchema.build_id == self._build_id).all()
            subjobs_schema = session.query(SubjobsSchema).filter(SubjobsSchema.build_id == self._build_id).all()

            # If this wasn't found, it's safe to assume that the build doesn't exist within the database
            if build_schema is None:
                raise ItemNotFoundError('Unable to find build (id: {}) in database.'.format(self._build_id))

            build_schema.artifacts_tar_file = self._artifacts_tar_file
            build_schema.artifacts_zip_file = self._artifacts_zip_file
            build_schema.error_message = self._error_message
            build_schema.postbuild_tasks_are_finished = self._postbuild_tasks_are_finished
            build_schema.setup_failures = self.setup_failures
            build_schema.timing_file_path = self._timing_file_path

            build_artifact_dir = None
            if self._build_artifact is not None:
                build_artifact_dir = self._build_artifact.build_artifact_dir

            build_schema.build_artifact_dir = build_artifact_dir

            if self._build_artifact is not None:
                # Clear all old directories
                session.query(FailedArtifactDirectoriesSchema) \
                    .filter(FailedArtifactDirectoriesSchema.build_id == self._build_id) \
                    .delete()

                # Commit changes so we don't delete the newly added rows later
                session.commit()

                # Add all the updated versions of the directories
                for directory in self._build_artifact._get_failed_artifact_directories():
                    failed_artifact_directory = FailedArtifactDirectoriesSchema(
                        build_id=self._build_id,
                        failed_artifact_directory=directory
                    )
                    session.add(failed_artifact_directory)

            if self._build_artifact is not None:
                # Clear all old directories
                session.query(FailedSubjobAtomPairsSchema) \
                    .filter(FailedSubjobAtomPairsSchema.build_id == self._build_id) \
                    .delete()

                # Commit changes so we don't delete the newly added rows later
                session.commit()

                # Add all the updated versions of the data
                for subjob_id, atom_id in self._build_artifact.get_failed_subjob_and_atom_ids():
                    failed_subjob_and_atom_ids = FailedSubjobAtomPairsSchema(
                        build_id=self._build_id,
                        subjob_id=subjob_id,
                        atom_id=atom_id
                    )
                    session.add(failed_subjob_and_atom_ids)

            build_schema.build_parameters = json.dumps(self._build_request.build_parameters())

            fsm_timestamps = {state.lower(): timestamp for state, timestamp in self._state_machine.transition_timestamps.items()}
            build_schema.state = self._status()
            build_schema.queued_ts = fsm_timestamps['queued']
            build_schema.finished_ts = fsm_timestamps['finished']
            build_schema.prepared_ts = fsm_timestamps['prepared']
            build_schema.preparing_ts = fsm_timestamps['preparing']
            build_schema.error_ts = fsm_timestamps['error']
            build_schema.canceled_ts = fsm_timestamps['canceled']
            build_schema.building_ts = fsm_timestamps['building']

            # Subjobs
            # Clear all old Subjobs and Atoms
            session.query(SubjobsSchema) \
                .filter(SubjobsSchema.build_id == self._build_id) \
                .delete()
            session.query(AtomsSchema) \
                .filter(AtomsSchema.build_id == self._build_id) \
                .delete()

            # Commit changes so we don't delete the newly added rows later
            session.commit()

            # Add all the updated versions of Subjobs and Atoms
            subjobs = self._all_subjobs_by_id
            for subjob_id in subjobs:
                subjob = self._all_subjobs_by_id[subjob_id]
                subjob_schema = SubjobsSchema(
                    subjob_id=subjob_id,
                    build_id=self._build_id,
                    completed=subjob.completed
                )
                session.add(subjob_schema)

                # Atoms
                for atom in subjob._atoms:
                    atom_schema = AtomsSchema(
                        atom_id=atom.id,
                        build_id=self._build_id,
                        subjob_id=subjob_id,
                        command_string=atom.command_string,
                        expected_time=atom.expected_time,
                        actual_time=atom.actual_time,
                        exit_code=atom.exit_code,
                        state=atom.state
                    )
                    session.add(atom_schema)
Exemple #13
0
 def subjob(self, subjob_id: int) -> Subjob:
     """Return the subjob for this build with the specified id."""
     subjob = self._all_subjobs_by_id.get(subjob_id)
     if subjob is None:
         raise ItemNotFoundError('Invalid subjob id.')
     return subjob