use of com.evolveum.midpoint.schema.RefreshShadowOperation in project midpoint by Evolveum.
the class RefreshHelper method refreshShadowRetryOperations.
private RefreshShadowOperation refreshShadowRetryOperations(ProvisioningContext ctx, PrismObject<ShadowType> repoShadow, List<PendingOperationType> sortedOperations, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException {
ShadowType shadowType = repoShadow.asObjectable();
OperationResult retryResult = new OperationResult(OP_REFRESH_RETRY);
if (ShadowUtil.isDead(shadowType)) {
RefreshShadowOperation rso = new RefreshShadowOperation();
retryResult.recordSuccess();
rso.setRefreshedShadow(repoShadow);
rso.setRefreshResult(retryResult);
return rso;
}
Duration retryPeriod = ProvisioningUtil.getRetryPeriod(ctx);
Collection<ObjectDeltaOperation<ShadowType>> executedDeltas = new ArrayList<>();
for (PendingOperationType pendingOperation : sortedOperations) {
if (!needsRetry(pendingOperation)) {
continue;
}
// We really want to get "now" here. Retrying operation may take some time. We want good timestamps that do not lie.
XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar();
if (!isAfterRetryPeriod(pendingOperation, retryPeriod, now)) {
if (PendingOperationTypeType.RETRY != pendingOperation.getType()) {
continue;
}
if (!ProvisioningOperationOptions.isForceRetry(options)) {
continue;
}
}
LOGGER.trace("Going to retry operation {} on {}", pendingOperation, repoShadow);
// Record attempt number and timestamp before the operation
// TODO: later use this as an optimistic lock to make sure that two threads won't retry the operation at the same time
// TODO: move to a better place
ObjectDelta<ShadowType> shadowDelta = repoShadow.createModifyDelta();
ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath();
int attemptNumber = pendingOperation.getAttemptNumber() + 1;
PropertyDelta<Integer> attemptNumberDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_ATTEMPT_NUMBER));
attemptNumberDelta.setRealValuesToReplace(attemptNumber);
shadowDelta.addModification(attemptNumberDelta);
PropertyDelta<XMLGregorianCalendar> lastAttemptTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_LAST_ATTEMPT_TIMESTAMP));
lastAttemptTimestampDelta.setRealValuesToReplace(now);
shadowDelta.addModification(lastAttemptTimestampDelta);
PropertyDelta<OperationResultStatusType> resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS));
resultStatusDelta.setRealValuesToReplace(OperationResultStatusType.IN_PROGRESS);
shadowDelta.addModification(resultStatusDelta);
shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult);
shadowDelta.applyTo(repoShadow);
ObjectDeltaType pendingDeltaType = pendingOperation.getDelta();
ObjectDelta<ShadowType> pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext);
ProvisioningOperationState<? extends AsynchronousOperationResult> opState = ProvisioningOperationState.fromPendingOperation(repoShadow, pendingOperation);
LOGGER.debug("Retrying operation {} on {}, attempt #{}", pendingDelta, repoShadow, attemptNumber);
ObjectDeltaOperation<ShadowType> objectDeltaOperation = new ObjectDeltaOperation<>(pendingDelta);
OperationResult result = parentResult.createSubresult(OP_OPERATION_RETRY);
try {
retryOperation(ctx, pendingDelta, opState, task, result);
repoShadow = opState.getRepoShadow();
result.computeStatus();
if (result.isError()) {
retryResult.setStatus(result.getStatus());
}
// TODO maybe add whole "result" as subresult to the retryResult?
result.muteError();
} catch (CommunicationException | GenericFrameworkException | ObjectAlreadyExistsException | SchemaException | ObjectNotFoundException | ConfigurationException | SecurityViolationException e) {
// This is final failure: the error is not handled.
// Therefore the operation is now completed - finished with an error.
// But we do not want to stop the task. Just log the error.
LOGGER.error("Operation {} on {} ended up with an error after {} retries: {}", pendingDelta, repoShadow, attemptNumber, e.getMessage(), e);
// The retry itself was a success. Operation that was retried might have failed.
// And that is recorded in the shadow. But we have successfully retried the operation.
result.recordHandledError(e);
retryResult.recordFatalError("Operation " + pendingDelta + " on " + repoShadow + " ended with an error after " + attemptNumber + " retries: " + e.getMessage());
} catch (Throwable e) {
// This is unexpected error during retry. This means that there was other
// failure that we did not expected. This is likely to be bug - or maybe wrong
// error handling. This means that the retry was a failure.
result.recordFatalError(e);
retryResult.recordFatalError(e);
} finally {
// Status should be set by now, we just want to close the result
result.computeStatusIfUnknown();
}
objectDeltaOperation.setExecutionResult(result);
executedDeltas.add(objectDeltaOperation);
}
RefreshShadowOperation rso = new RefreshShadowOperation();
rso.setExecutedDeltas(executedDeltas);
rso.setRefreshedShadow(repoShadow);
parentResult.computeStatus();
rso.setRefreshResult(retryResult);
LOGGER.trace("refreshShadowOperation {}", rso.debugDumpLazily());
return rso;
}
use of com.evolveum.midpoint.schema.RefreshShadowOperation in project midpoint by Evolveum.
the class RefreshHelper method refreshShadow.
@Nullable
public RefreshShadowOperation refreshShadow(PrismObject<ShadowType> repoShadow, ProvisioningOperationOptions options, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException {
LOGGER.trace("Refreshing {}", repoShadow);
ProvisioningContext ctx = ctxFactory.createForShadow(repoShadow, task, result);
ctx.assertDefinition();
shadowCaretaker.applyAttributesDefinition(ctx, repoShadow);
repoShadow = shadowManager.refreshProvisioningIndexes(ctx, repoShadow, task, result);
RefreshShadowOperation refreshShadowOperation = refreshShadowPendingOperations(ctx, repoShadow, options, task, result);
XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar();
PrismObject<ShadowType> shadowAfterCleanup = deleteDeadShadowIfPossible(ctx, repoShadow, now, task, result);
if (shadowAfterCleanup == null) {
refreshShadowOperation.setRefreshedShadow(null);
}
return refreshShadowOperation;
}
use of com.evolveum.midpoint.schema.RefreshShadowOperation in project midpoint by Evolveum.
the class RefreshHelper method refreshShadowPendingOperations.
private RefreshShadowOperation refreshShadowPendingOperations(ProvisioningContext ctx, PrismObject<ShadowType> repoShadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException {
ShadowType shadowType = repoShadow.asObjectable();
List<PendingOperationType> pendingOperations = shadowType.getPendingOperation();
boolean isDead = ShadowUtil.isDead(shadowType);
if (!isDead && pendingOperations.isEmpty()) {
LOGGER.trace("Skipping refresh of {} pending operations because shadow is not dead and there are no pending operations", repoShadow);
RefreshShadowOperation rso = new RefreshShadowOperation();
rso.setRefreshedShadow(repoShadow);
return rso;
}
if (ResourceTypeUtil.isInMaintenance(ctx.getResource())) {
LOGGER.trace("Skipping refresh of {} pending operations because resource shadow is in the maintenance.", repoShadow);
RefreshShadowOperation rso = new RefreshShadowOperation();
rso.setRefreshedShadow(repoShadow);
return rso;
}
LOGGER.trace("Pending operations refresh of {}, dead={}, {} pending operations", repoShadow, isDead, pendingOperations.size());
ctx.assertDefinition();
List<PendingOperationType> sortedOperations = shadowCaretaker.sortPendingOperations(shadowType.getPendingOperation());
refreshShadowAsyncStatus(ctx, repoShadow, sortedOperations, task, parentResult);
return refreshShadowRetryOperations(ctx, repoShadow, sortedOperations, options, task, parentResult);
}
use of com.evolveum.midpoint.schema.RefreshShadowOperation in project midpoint by Evolveum.
the class ModifyHelper method modifyShadowAttempt.
/**
* @param inRefresh True if we are already in refresh shadow method. This means we shouldn't refresh ourselves!
*/
String modifyShadowAttempt(ProvisioningContext ctx, Collection<? extends ItemDelta<?, ?>> modifications, OperationProvisioningScriptsType scripts, ProvisioningOperationOptions options, ProvisioningOperationState<AsynchronousOperationReturnValue<Collection<PropertyDelta<PrismPropertyValue>>>> opState, boolean inRefresh, Task task, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, ObjectNotFoundException, SchemaException, ConfigurationException, SecurityViolationException, PolicyViolationException, ExpressionEvaluationException, EncryptionException, ObjectAlreadyExistsException {
PrismObject<ShadowType> repoShadow = opState.getRepoShadow();
XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar();
PendingOperationType duplicateOperation = shadowManager.checkAndRecordPendingModifyOperationBeforeExecution(ctx, modifications, opState, parentResult);
if (duplicateOperation != null) {
parentResult.setInProgress();
return repoShadow.getOid();
}
shadowCaretaker.applyAttributesDefinition(ctx, repoShadow);
accessChecker.checkModify(ctx, modifications, parentResult);
entitlementsHelper.preprocessEntitlements(ctx, modifications, "delta for shadow " + repoShadow.getOid(), parentResult);
OperationResultStatus finalOperationStatus = null;
if (shadowManager.isRepositoryOnlyModification(modifications)) {
opState.setExecutionStatus(PendingOperationExecutionStatusType.COMPLETED);
LOGGER.debug("MODIFY {}: repository-only modification", repoShadow);
} else {
if (shouldExecuteResourceOperationDirectly(ctx)) {
LOGGER.trace("MODIFY {}: resource modification, execution starting\n{}", repoShadow, DebugUtil.debugDumpLazily(modifications));
RefreshShadowOperation refreshShadowOperation = null;
if (!inRefresh && Util.shouldRefresh(repoShadow)) {
refreshShadowOperation = refreshHelper.refreshShadow(repoShadow, options, task, parentResult);
}
if (refreshShadowOperation != null) {
repoShadow = refreshShadowOperation.getRefreshedShadow();
}
if (repoShadow == null) {
LOGGER.trace("Shadow is gone. Nothing more to do");
parentResult.recordPartialError("Shadow disappeared during modify.");
throw new ObjectNotFoundException("Shadow is gone.");
}
ConnectorOperationOptions connOptions = commonHelper.createConnectorOperationOptions(ctx, options, parentResult);
try {
if (ResourceTypeUtil.isInMaintenance(ctx.getResource())) {
throw new MaintenanceException("Resource " + ctx.getResource() + " is in the maintenance");
}
if (!shouldExecuteModify(refreshShadowOperation)) {
ProvisioningUtil.postponeModify(ctx, repoShadow, modifications, opState, refreshShadowOperation.getRefreshResult(), parentResult);
shadowManager.recordModifyResult(ctx, repoShadow, modifications, opState, now, parentResult);
return repoShadow.getOid();
} else {
LOGGER.trace("Shadow exists: {}", repoShadow.debugDump());
}
AsynchronousOperationReturnValue<Collection<PropertyDelta<PrismPropertyValue>>> asyncReturnValue = resourceObjectConverter.modifyResourceObject(ctx, repoShadow, scripts, connOptions, modifications, now, parentResult);
opState.processAsyncResult(asyncReturnValue);
Collection<PropertyDelta<PrismPropertyValue>> knownExecutedDeltas = asyncReturnValue.getReturnValue();
if (knownExecutedDeltas != null) {
ItemDeltaCollectionsUtil.addNotEquivalent(modifications, knownExecutedDeltas);
}
} catch (Exception ex) {
LOGGER.debug("Provisioning exception: {}:{}, attempting to handle it", ex.getClass(), ex.getMessage(), ex);
finalOperationStatus = handleModifyError(ctx, repoShadow, modifications, options, opState, ex, parentResult.getLastSubresult(), task, parentResult);
}
LOGGER.debug("MODIFY {}: resource operation executed, operation state: {}", repoShadow, opState.shortDumpLazily());
} else {
opState.setExecutionStatus(PendingOperationExecutionStatusType.EXECUTION_PENDING);
// Create dummy subresult with IN_PROGRESS state.
// This will force the entire result (parent) to be IN_PROGRESS rather than SUCCESS.
parentResult.createSubresult(OP_DELAYED_OPERATION).recordInProgress();
LOGGER.debug("MODIFY {}: Resource operation NOT executed, execution pending", repoShadow);
}
}
shadowManager.recordModifyResult(ctx, repoShadow, modifications, opState, now, parentResult);
notifyAfterModify(ctx, repoShadow, modifications, opState, task, parentResult);
setParentOperationStatus(parentResult, opState, finalOperationStatus);
return repoShadow.getOid();
}
Aggregations