requireNonNull(mutableRequest);
requireNonNull(session);
// TODO(maxim): Switch to key field instead when AURORA-749 is fixed.
final IJobKey job = JobKeys.assertValid(IJobKey.build(new JobKey()
.setRole(mutableRequest.getTaskConfig().getOwner().getRole())
.setEnvironment(mutableRequest.getTaskConfig().getEnvironment())
.setName(mutableRequest.getTaskConfig().getJobName())));
JobUpdateSettings settings = requireNonNull(mutableRequest.getSettings());
if (settings.getUpdateGroupSize() <= 0) {
return invalidResponse("updateGroupSize must be positive.");
}
if (settings.getMaxPerInstanceFailures() < 0) {
return invalidResponse("maxPerInstanceFailures must be non-negative.");
}
if (settings.getMaxFailedInstances() < 0) {
return invalidResponse("maxFailedInstances must be non-negative.");
}
if (settings.getMaxWaitToInstanceRunningMs() < 0) {
return invalidResponse("maxWaitToInstanceRunningMs must be non-negative.");
}
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(