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()
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()
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)
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.')