if (settings.getMinWaitInInstanceRunningMs() < 0) {
return invalidResponse("minWaitInInstanceRunningMs must be non-negative.");
}
final SessionContext context;
final IJobUpdateRequest request;
try {
context = sessionValidator.checkAuthenticated(session, ImmutableSet.of(job.getRole()));
request = IJobUpdateRequest.build(new JobUpdateRequest(mutableRequest).setTaskConfig(
ConfigurationManager.validateAndPopulate(
ITaskConfig.build(mutableRequest.getTaskConfig())).newBuilder()));
if (cronJobManager.hasJob(job)) {
return invalidResponse("Cron jobs may only be updated by calling replaceCronTemplate.");
}
} catch (AuthFailedException e) {
return errorResponse(AUTH_FAILED, e);
} catch (TaskDescriptionException e) {
return errorResponse(INVALID_REQUEST, e);
}
return storage.write(new MutateWork.Quiet<Response>() {
@Override
public Response apply(MutableStoreProvider storeProvider) {
String updateId = uuidGenerator.createNew().toString();
IJobUpdateSettings settings = request.getSettings();
JobDiff diff = JobDiff.compute(
storeProvider.getTaskStore(),
job,
JobDiff.asMap(request.getTaskConfig(), request.getInstanceCount()),
settings.getUpdateOnlyTheseInstances());
if (diff.isNoop()) {
return addMessage(emptyResponse(), OK, NOOP_JOB_UPDATE_MESSAGE);
}
Set<Integer> invalidScope = diff.getOutOfScopeInstances(
Numbers.rangesToInstanceIds(settings.getUpdateOnlyTheseInstances()));
if (!invalidScope.isEmpty()) {
return invalidResponse(
"updateOnlyTheseInstances contains instances irrelevant to the update: "
+ invalidScope);
}
JobUpdateInstructions instructions = new JobUpdateInstructions()
.setSettings(settings.newBuilder())
.setInitialState(buildInitialState(diff.getReplacedInstances()));
if (!diff.getReplacementInstances().isEmpty()) {
instructions.setDesiredState(
new InstanceTaskConfig()
.setTask(request.getTaskConfig().newBuilder())
.setInstances(convertRanges(Numbers.toRanges(diff.getReplacementInstances()))));
}
IJobUpdate update = IJobUpdate.build(new JobUpdate()
.setSummary(new JobUpdateSummary()
.setJobKey(job.newBuilder())
.setUpdateId(updateId)
.setUser(context.getIdentity()))
.setInstructions(instructions));
try {
validateTaskLimits(
request.getTaskConfig(),
request.getInstanceCount(),
quotaManager.checkJobUpdate(update));
jobUpdateController.start(update, context.getIdentity());
return okResponse(Result.startJobUpdateResult(new StartJobUpdateResult(updateId)));
} catch (UpdateStateException | TaskValidationException e) {
return errorResponse(INVALID_REQUEST, e);
}
}