def test_batch_jobs(self, **kwargs): client = self.create_sharedkey_client(**kwargs) # Test Create Job auto_pool = models.AutoPoolSpecification( pool_lifetime_option=models.PoolLifetimeOption.job, pool=models.PoolSpecification( vm_size='small', cloud_service_configuration=models.CloudServiceConfiguration( os_family='5' ) ) ) job_prep = models.JobPreparationTask(command_line="cmd /c \"echo hello world\"") job_release = models.JobReleaseTask(command_line="cmd /c \"echo goodbye world\"") job_param = models.JobAddParameter( id=self.get_resource_name('batch_job1_'), pool_info=models.PoolInformation( auto_pool_specification=auto_pool ), job_preparation_task=job_prep, job_release_task=job_release ) response = client.job.add(job_param) self.assertIsNone(response) # Test Update Job constraints = models.JobConstraints(max_task_retry_count=3) options = models.JobUpdateParameter( priority=500, constraints=constraints, pool_info=models.PoolInformation( auto_pool_specification=auto_pool ) ) response = client.job.update(job_param.id, options) self.assertIsNone(response) # Test Patch Job options = models.JobPatchParameter(priority=900) response = client.job.patch(job_param.id, options) self.assertIsNone(response) job = client.job.get(job_param.id) self.assertIsInstance(job, models.CloudJob) self.assertEqual(job.id, job_param.id) self.assertEqual(job.constraints.max_task_retry_count, 3) self.assertEqual(job.priority, 900) # Test Create Job with Auto Complete job_auto_param = models.JobAddParameter( id=self.get_resource_name('batch_job2_'), on_all_tasks_complete=models.OnAllTasksComplete.terminate_job, on_task_failure=models.OnTaskFailure.perform_exit_options_job_action, pool_info=models.PoolInformation( auto_pool_specification=auto_pool ) ) response = client.job.add(job_auto_param) self.assertIsNone(response) job = client.job.get(job_auto_param.id) self.assertIsInstance(job, models.CloudJob) self.assertEqual(job.on_all_tasks_complete, models.OnAllTasksComplete.terminate_job) self.assertEqual(job.on_task_failure, models.OnTaskFailure.perform_exit_options_job_action) # Test List Jobs jobs = client.job.list() self.assertIsInstance(jobs, models.CloudJobPaged) self.assertEqual(len(list(jobs)), 2) # Test Disable Job response = client.job.disable(job_param.id, models.DisableJobOption.requeue) self.assertIsNone(response) # Test Enable Job response = client.job.enable(job_param.id) self.assertIsNone(response) # Prep and release task status task_status = client.job.list_preparation_and_release_task_status(job_param.id) self.assertIsInstance(task_status, models.JobPreparationAndReleaseTaskExecutionInformationPaged) self.assertEqual(list(task_status), []) # Test Terminate Job response = client.job.terminate(job_param.id) self.assertIsNone(response) # Test Delete Job response = client.job.delete(job_auto_param.id) self.assertIsNone(response) # Test Job Lifetime Statistics stats = client.job.get_all_lifetime_statistics() self.assertIsInstance(stats, models.JobStatistics) self.assertEqual(stats.num_succeeded_tasks, 0) self.assertEqual(stats.num_failed_tasks, 0)
def retarget_job_to_new_pool(batch_service_client: batch.BatchExtensionsClient, job_id: str, new_pool_id: str): """ Disables a job with task requeue, then patches it to target a new pool. :param batch_service_client: The batch client used for making batch operations :type batch_service_client: `azure.batch.BatchExtensionsClient` :param job_id: The job to retarget :type job_id: str :param new_pool_id: The id of the new pool :type new_pool_id: str """ logger.info("Retargeting job [{}] to new pool [{}]".format( job_id, new_pool_id)) try: batch_service_client.job.disable(job_id, "requeue") except batchmodels.BatchErrorException as batch_exception: # potential race condition where the nodes have gone idle and the job has 'Completed' between our internal # node-idle-timeout check and the call to disable the job. Just return in this case if expected_exception(batch_exception, "The specified job does not exist"): logger.info( "The specified Job [{}] did not exist when we tried to delete it." .format(job_id)) raise ex.JobAlreadyCompleteException( job_id, "Job already complete and deleted.") if expected_exception( batch_exception, "The specified job is already in a completed state"): logger.info( "The specified Job [{}] was already in completed state when we tried to delete it." .format(job_id)) raise ex.JobAlreadyCompleteException(job_id, "Job already complete.") raise # give the job time to move to disabled state before we try Patch it time.sleep(service_state_transition_seconds) looping_job_patch = True job_patch_retry_count = 0 while looping_job_patch: try: batch_service_client.job.patch( job_id, batchmodels.JobPatchParameter( pool_info=batchmodels.PoolInformation( pool_id=new_pool_id))) looping_job_patch = False except batchmodels.BatchErrorException as batch_exception: if expected_exception( batch_exception, "The specified operation is not valid for the current state of the resource" ): if job_patch_retry_count > 10: logger.error( "Exhausted retries and Failed to patch job [{}] due to the current state of the resource" .format(job_id)) raise logger.info( "Failed to patch job [{}] due to the current state of the resource, retrying...." .format(job_id)) time.sleep(5) job_patch_retry_count = job_patch_retry_count + 1 logger.info("Successfully retargeted job [{}] to pool [{}]".format( job_id, new_pool_id))