def setup_build(self, build_id, project_type_params):
        """
        Usually called once per build to do build-specific setup. Will block any subjobs from executing until setup
        completes. The actual setup is performed on another thread and will unblock subjobs (via an Event) once it
        finishes.

        :param build_id: The id of the build to run setup on
        :type build_id: int
        :param project_type_params: The parameters that define the project_type this build will execute in
        :type project_type_params: dict
        """
        self._logger.info('Executing setup for build {} (type: {}).', build_id, project_type_params.get('type'))
        self._setup_complete_event.clear()
        self._current_build_id = build_id

        # create an project_type instance for build-level operations
        self._project_type = util.create_project_type(project_type_params)

        # verify all executors are idle
        if not self._idle_executors.full():
            raise RuntimeError('Slave tried to setup build but not all executors are idle. ({}/{} executors idle.)'
                               .format(self._idle_executors.qsize(), self._num_executors))

        # Collect all the executors to pass to project_type.setup_build(). This will create a new project_type for
        # each executor (for subjob-level operations).
        executors = list(self._idle_executors.queue)
        SafeThread(target=self._async_setup_build, args=(executors, project_type_params)).start()
示例#2
0
    def setup_build(self, build_id, project_type_params, build_executor_start_index):
        """
        Usually called once per build to do build-specific setup. Will block any subjobs from executing until setup
        completes. The actual setup is performed on another thread and will unblock subjobs (via an Event) once it
        finishes.

        :param build_id: The id of the build to run setup on
        :type build_id: int
        :param project_type_params: The parameters that define the project_type this build will execute in
        :type project_type_params: dict
        :param build_executor_start_index: How many executors have alreayd been allocated on other slaves for
        this build
        :type build_executor_start_index: int
        """
        self._logger.info('Executing setup for build {} (type: {}).', build_id, project_type_params.get('type'))
        self._current_build_id = build_id
        self._build_teardown_coin = SingleUseCoin()  # protects against build_teardown being executed multiple times

        # create an project_type instance for build-level operations
        self._project_type = util.create_project_type(project_type_params)

        # verify all executors are idle
        if not self._idle_executors.full():
            raise RuntimeError('Slave tried to setup build but not all executors are idle. ({}/{} executors idle.)'
                               .format(self._idle_executors.qsize(), self._num_executors))

        # Collect all the executors to pass to project_type.fetch_project(). This will create a new project_type for
        # each executor (for subjob-level operations).
        executors = list(self._idle_executors.queue)
        SafeThread(
            target=self._async_setup_build,
            name='Bld{}-Setup'.format(build_id),
            args=(executors, project_type_params, build_executor_start_index)
        ).start()
    def handle_request(self, build):
        """
        Prepare a Build to be distributed across slaves.

        # Fetch the repo/container/execute commands
        # Get the cluster_runner.yaml file
        # Pull all of the atoms by running the atomizer
        # Group the atoms into groupings
        # Generate subjobs
        # Prepare the build

        :param build: the Build instance to be prepared to be distributed across slaves
        :type build: Build
        """
        build_id = build.build_id()
        build_request = build.build_request
        if not isinstance(build_request, BuildRequest):
            raise RuntimeError(
                'Build {} has no associated request object.'.format(build_id))

        # Generate a unique project build directory name that will be symlinked to the actual project directory
        # later on when the project gets fetched.
        build_specific_project_directory = self._generate_unique_symlink_path_for_build_repo(
        )

        # Because build_specific_project_directory is entirely internal and generated by ClusterRunner (it is a
        # build-unique generated symlink), we must manually add it to the project_type_params
        # @TODO: directly passing around the user-specified project_type_params may no longer be the right approach as
        # @TODO: we get more and more internal clusterrunner-specific arguments such as build_project_directory
        # todo(joey): we should move/refactor the concurrency protection in build.prepare() to also protect this path
        project_type_params = build_request.build_parameters()
        project_type_params.update(
            {'build_project_directory': build_specific_project_directory})
        project_type = util.create_project_type(project_type_params)

        if project_type is None:
            raise BuildProjectError(
                'Build failed due to an invalid build type.')

        self._logger.info('Fetching project for build {}.', build_id)
        project_type.fetch_project()

        self._logger.info('Successfully fetched project for build {}.',
                          build_id)
        job_config = project_type.job_config()

        if job_config is None:
            # @TODO: need to be able to dump applicable information from project_type for helpful error message
            build.mark_failed(
                'Build failed while trying to parse cluster_runner.yaml.')
            return

        subjobs = self._compute_subjobs_for_build(build_id, job_config,
                                                  project_type)
        build.prepare(subjobs, project_type, job_config)
    def configure_project_type(self, project_type_params):
        """
        Configure the project_type that this executor will use to execute subjobs. If there is alredy a previous
        project_type configured, tear it down.

        :type project_type_params: dict[str, str]
        """
        if self._project_type:
            self._project_type.teardown_executor()

        self._project_type = util.create_project_type(project_type_params)
        self._project_type.setup_executor()
示例#5
0
    def configure_project_type(self, project_type_params):
        """
        Configure the project_type that this executor will use to execute subjobs. If there is alredy a previous
        project_type configured, tear it down.

        :type project_type_params: dict[str, str]
        """
        if self._project_type:
            self._project_type.teardown_executor()

        self._project_type = util.create_project_type(project_type_params)
        self._project_type.setup_executor()
    def handle_request(self, build):
        """
        Prepare a Build to be distributed across slaves.

        # Fetch the repo/container/execute commands
        # Get the cluster_runner.yaml file
        # Pull all of the atoms by running the atomizer
        # Group the atoms into groupings
        # Generate subjobs
        # Prepare the build

        :param build: the Build instance to be prepared to be distributed across slaves
        :type build: Build
        """
        build_id = build.build_id()
        build_request = build.build_request
        if not isinstance(build_request, BuildRequest):
            raise RuntimeError('Build {} has no associated request object.'.format(build_id))

        # Generate a unique project build directory name that will be symlinked to the actual project directory
        # later on when the project gets fetched.
        build_specific_project_directory = self._generate_unique_symlink_path_for_build_repo()

        # Because build_specific_project_directory is entirely internal and generated by ClusterRunner (it is a
        # build-unique generated symlink), we must manually add it to the project_type_params
        # @TODO: directly passing around the user-specified project_type_params may no longer be the right approach as
        # @TODO: we get more and more internal clusterrunner-specific arguments such as build_project_directory
        # todo(joey): we should move/refactor the concurrency protection in build.prepare() to also protect this path
        project_type_params = build_request.build_parameters()
        project_type_params.update({'build_project_directory': build_specific_project_directory})
        project_type = util.create_project_type(project_type_params)

        if project_type is None:
            raise BuildProjectError('Build failed due to an invalid build type.')

        self._logger.info('Fetching project for build {}.', build_id)
        project_type.setup_build()

        self._logger.info('Successfully fetched project for build {}.', build_id)
        job_config = project_type.job_config()

        if job_config is None:
            # @TODO: need to be able to dump applicable information from project_type for helpful error message
            build.mark_failed('Build failed while trying to parse cluster_runner.yaml.')
            return

        subjobs = self._compute_subjobs_for_build(build_id, job_config, project_type)
        build.prepare(subjobs, project_type, job_config)
示例#7
0
    def generate_project_type(self):
        """
        Instantiate the project type for this build, populating the self._project_type instance variable.

        As a side effect, this method also updates the build request's build_parameters dictionary
        with the unique workspace directory path for this build.

        :raises BuildProjectError when failed to instantiate project type
        """
        # Generate a unique project build directory name that will be symlinked to the actual project directory
        # later on when the project gets fetched.
        build_specific_project_directory = self._generate_unique_symlink_path_for_build_repo()

        # Because build_specific_project_directory is entirely internal and generated by ClusterRunner (it is a
        # build-unique generated symlink), we must manually add it to the project_type_params
        project_type_params = self.build_request.build_parameters()
        project_type_params.update({'build_project_directory': build_specific_project_directory})
        self._project_type = util.create_project_type(project_type_params)
        if self._project_type is None:
            raise BuildProjectError('Build failed due to an invalid project type.')
示例#8
0
    def generate_project_type(self):
        """
        Instantiate the project type for this build, populating the self._project_type instance variable.

        As a side effect, this method also updates the build request's build_parameters dictionary
        with the unique workspace directory path for this build.

        :raises BuildProjectError when failed to instantiate project type
        """
        # Generate a unique project build directory name that will be symlinked to the actual project directory
        # later on when the project gets fetched.
        build_specific_project_directory = self._generate_unique_symlink_path_for_build_repo()

        # Because build_specific_project_directory is entirely internal and generated by ClusterRunner (it is a
        # build-unique generated symlink), we must manually add it to the project_type_params
        project_type_params = self.build_request.build_parameters()
        project_type_params.update({'build_project_directory': build_specific_project_directory})
        self._project_type = util.create_project_type(project_type_params)
        if self._project_type is None:
            raise BuildProjectError('Build failed due to an invalid project type.')