use of com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions in project midpoint by Evolveum.
the class ReconciliationTaskHandler method scanForUnfinishedOperations.
/**
* Scans shadows for unfinished operations and tries to finish them.
* Returns false if the reconciliation was interrupted.
*/
private boolean scanForUnfinishedOperations(Task task, String resourceOid, ReconciliationTaskResult reconResult, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, CommunicationException, ObjectNotFoundException, ConfigurationException, SecurityViolationException {
LOGGER.trace("Scan for unfinished operations starting");
OperationResult opResult = result.createSubresult(OperationConstants.RECONCILIATION + ".repoReconciliation");
opResult.addParam("reconciled", true);
ObjectQuery query = QueryBuilder.queryFor(ShadowType.class, prismContext).block().not().item(ShadowType.F_FAILED_OPERATION_TYPE).isNull().endBlock().and().item(ShadowType.F_RESOURCE_REF).ref(resourceOid).build();
List<PrismObject<ShadowType>> shadows = repositoryService.searchObjects(ShadowType.class, query, null, opResult);
// for this phase, obviously
task.setExpectedTotal((long) shadows.size());
LOGGER.trace("Found {} accounts that were not successfully processed.", shadows.size());
reconResult.setUnOpsCount(shadows.size());
long startedAll = System.currentTimeMillis();
int processedSuccess = 0, processedFailure = 0;
for (PrismObject<ShadowType> shadow : shadows) {
long started = System.currentTimeMillis();
task.recordIterativeOperationStart(shadow.asObjectable());
OperationResult provisioningResult = new OperationResult(OperationConstants.RECONCILIATION + ".finishOperation");
try {
RepositoryCache.enter();
ProvisioningOperationOptions options = ProvisioningOperationOptions.createCompletePostponed(false);
Utils.clearRequestee(task);
provisioningService.refreshShadow(shadow, options, task, provisioningResult);
// retryFailedOperation(shadow.asObjectable(), opResult);
task.recordIterativeOperationEnd(shadow.asObjectable(), started, null);
processedSuccess++;
} catch (Throwable ex) {
task.recordIterativeOperationEnd(shadow.asObjectable(), started, ex);
processedFailure++;
opResult.recordFatalError("Failed to finish operation with shadow: " + ObjectTypeUtil.toShortString(shadow.asObjectable()) + ". Reason: " + ex.getMessage(), ex);
Collection<? extends ItemDelta> modifications = PropertyDelta.createModificationReplacePropertyCollection(ShadowType.F_ATTEMPT_NUMBER, shadow.getDefinition(), shadow.asObjectable().getAttemptNumber() + 1);
try {
repositoryService.modifyObject(ShadowType.class, shadow.getOid(), modifications, provisioningResult);
task.recordObjectActionExecuted(shadow, null, null, ChangeType.MODIFY, SchemaConstants.CHANGE_CHANNEL_RECON_URI, null);
} catch (Exception e) {
task.recordObjectActionExecuted(shadow, null, null, ChangeType.MODIFY, SchemaConstants.CHANGE_CHANNEL_RECON_URI, e);
LoggingUtils.logException(LOGGER, "Failed to record finish operation failure with shadow: " + ObjectTypeUtil.toShortString(shadow.asObjectable()), e);
}
} finally {
task.markObjectActionExecutedBoundary();
RepositoryCache.exit();
}
// TODO record statistics as well
incrementAndRecordProgress(task, opResult);
if (!task.canRun()) {
break;
}
}
// for next phases, it looks strangely to see progress e.g. 2/1
task.setExpectedTotal(null);
// for each try the operation again
String message = "Processing unfinished operations done. Out of " + shadows.size() + " objects, " + processedSuccess + " were processed successfully and processing of " + processedFailure + " resulted in failure. " + "Total time spent: " + (System.currentTimeMillis() - startedAll) + " ms. " + (!task.canRun() ? "Was interrupted during processing." : "");
opResult.computeStatus();
result.createSubresult(opResult.getOperation() + ".statistics").recordStatus(opResult.getStatus(), message);
LOGGER.debug("{}. Result: {}", message, opResult.getStatus());
return task.canRun();
}
use of com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions in project midpoint by Evolveum.
the class ChangeExecutor method executeAddition.
private <T extends ObjectType, F extends ObjectType> void executeAddition(ObjectDelta<T> change, final LensContext<F> context, LensElementContext<T> objectContext, ModelExecuteOptions options, ResourceType resource, Task task, OperationResult result) throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
PrismObject<T> objectToAdd = change.getObjectToAdd();
if (change.getModifications() != null) {
for (ItemDelta delta : change.getModifications()) {
delta.applyTo(objectToAdd);
}
change.getModifications().clear();
}
OwnerResolver ownerResolver = createOwnerResolver(context, task, result);
try {
securityEnforcer.authorize(ModelAuthorizationAction.ADD.getUrl(), AuthorizationPhaseType.EXECUTION, objectToAdd, null, null, ownerResolver, result);
T objectTypeToAdd = objectToAdd.asObjectable();
metadataManager.applyMetadataAdd(context, objectToAdd, clock.currentTimeXMLGregorianCalendar(), task, result);
if (options == null && context != null) {
options = context.getOptions();
}
String oid;
if (objectTypeToAdd instanceof TaskType) {
oid = addTask((TaskType) objectTypeToAdd, result);
} else if (objectTypeToAdd instanceof NodeType) {
throw new UnsupportedOperationException("NodeType cannot be added using model interface");
} else if (ObjectTypes.isManagedByProvisioning(objectTypeToAdd)) {
ProvisioningOperationOptions provisioningOptions = getProvisioningOptions(context, options);
oid = addProvisioningObject(objectToAdd, context, objectContext, provisioningOptions, resource, task, result);
if (oid == null) {
throw new SystemException("Provisioning addObject returned null OID while adding " + objectToAdd);
}
result.addReturn("createdAccountOid", oid);
} else {
FocusConstraintsChecker.clearCacheFor(objectToAdd.asObjectable().getName());
RepoAddOptions addOpt = new RepoAddOptions();
if (ModelExecuteOptions.isOverwrite(options)) {
addOpt.setOverwrite(true);
}
if (ModelExecuteOptions.isNoCrypt(options)) {
addOpt.setAllowUnencryptedValues(true);
}
oid = cacheRepositoryService.addObject(objectToAdd, addOpt, result);
if (oid == null) {
throw new SystemException("Repository addObject returned null OID while adding " + objectToAdd);
}
}
change.setOid(oid);
task.recordObjectActionExecuted(objectToAdd, objectToAdd.getCompileTimeClass(), oid, ChangeType.ADD, context.getChannel(), null);
} catch (Throwable t) {
task.recordObjectActionExecuted(objectToAdd, objectToAdd.getCompileTimeClass(), null, ChangeType.ADD, context.getChannel(), t);
throw t;
}
}
use of com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions in project midpoint by Evolveum.
the class ChangeExecutor method executeDeletion.
private <T extends ObjectType, F extends ObjectType> void executeDeletion(ObjectDelta<T> change, LensContext<F> context, LensElementContext<T> objectContext, ModelExecuteOptions options, ResourceType resource, Task task, OperationResult result) throws ObjectNotFoundException, ObjectAlreadyExistsException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
String oid = change.getOid();
Class<T> objectTypeClass = change.getObjectTypeClass();
PrismObject<T> objectOld = objectContext.getObjectOld();
OwnerResolver ownerResolver = createOwnerResolver(context, task, result);
try {
securityEnforcer.authorize(ModelAuthorizationAction.DELETE.getUrl(), AuthorizationPhaseType.EXECUTION, objectOld, null, null, ownerResolver, result);
if (TaskType.class.isAssignableFrom(objectTypeClass)) {
taskManager.deleteTask(oid, result);
} else if (NodeType.class.isAssignableFrom(objectTypeClass)) {
taskManager.deleteNode(oid, result);
} else if (ObjectTypes.isClassManagedByProvisioning(objectTypeClass)) {
ProvisioningOperationOptions provisioningOptions = getProvisioningOptions(context, options);
try {
deleteProvisioningObject(objectTypeClass, oid, context, objectContext, provisioningOptions, resource, task, result);
} catch (ObjectNotFoundException e) {
// Object that we wanted to delete is already gone. This can
// happen in some race conditions.
// As the resulting state is the same as we wanted it to be
// we will not complain and we will go on.
LOGGER.trace("Attempt to delete object {} ({}) that is already gone", oid, objectTypeClass);
result.muteLastSubresultError();
}
} else {
try {
cacheRepositoryService.deleteObject(objectTypeClass, oid, result);
} catch (ObjectNotFoundException e) {
// Object that we wanted to delete is already gone. This can
// happen in some race conditions.
// As the resulting state is the same as we wanted it to be
// we will not complain and we will go on.
LOGGER.trace("Attempt to delete object {} ({}) that is already gone", oid, objectTypeClass);
result.muteLastSubresultError();
}
}
task.recordObjectActionExecuted(objectOld, objectTypeClass, oid, ChangeType.DELETE, context.getChannel(), null);
} catch (Throwable t) {
task.recordObjectActionExecuted(objectOld, objectTypeClass, oid, ChangeType.DELETE, context.getChannel(), t);
throw t;
}
}
use of com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions in project midpoint by Evolveum.
the class ChangeExecutor method copyFromModelOptions.
private ProvisioningOperationOptions copyFromModelOptions(ModelExecuteOptions options) {
ProvisioningOperationOptions provisioningOptions = new ProvisioningOperationOptions();
if (options == null) {
return provisioningOptions;
}
provisioningOptions.setForce(options.getForce());
provisioningOptions.setOverwrite(options.getOverwrite());
return provisioningOptions;
}
use of com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions in project midpoint by Evolveum.
the class ObjectNotFoundHandler method handleError.
@Override
public <T extends ShadowType> T handleError(T shadow, FailedOperation op, Exception ex, boolean doDiscovery, boolean compensate, Task task, OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
if (!doDiscovery) {
parentResult.recordFatalError(ex);
if (ex instanceof ObjectNotFoundException) {
throw (ObjectNotFoundException) ex;
} else {
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
}
OperationResult result = parentResult.createSubresult("com.evolveum.midpoint.provisioning.consistency.impl.ObjectNotFoundHandler.handleError." + op.name());
result.addParam("shadow", shadow);
result.addParam("currentOperation", op);
if (ex.getMessage() != null) {
result.addParam("exception", ex.getMessage());
}
LOGGER.trace("Start compensating object not found situation while execution operation: {}", op.name(), ex);
// Task task = taskManager.createTaskInstance();
ObjectDelta delta = null;
switch(op) {
case DELETE:
LOGGER.debug("DISCOVERY: cannot find object {}. The operation in progress is DELETE, therefore just deleting the shadow", shadow);
LOGGER.trace("Deleting shadow from the repository.");
for (OperationResult subResult : parentResult.getSubresults()) {
subResult.muteError();
}
try {
cacheRepositoryService.deleteObject(ShadowType.class, shadow.getOid(), result);
} catch (ObjectNotFoundException e) {
LOGGER.debug("Cannot delete {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
String message = "Object was not found on the " + ObjectTypeUtil.toShortString(shadow.getResource()) + ". Shadow deleted from the repository to equalize the state on the resource and in the repository.";
parentResult.recordHandledError(message);
LOGGER.trace("Shadow deleted from the repository. Inconsistencies are now removed.");
result.computeStatus();
// parentResult status can be recomputed by the caller method
result.setStatus(OperationResultStatus.HANDLED_ERROR);
delta = ObjectDelta.createDeleteDelta(shadow.getClass(), shadow.getOid(), prismContext);
ResourceOperationDescription operationDescritpion = createOperationDescription(shadow, ex, shadow.getResource(), delta, task, result);
changeNotificationDispatcher.notifySuccess(operationDescritpion, task, result);
LOGGER.debug("DISCOVERY: cannot find object {}: DELETE operation handler done", shadow);
return shadow;
case MODIFY:
LOGGER.debug("DISCOVERY: cannot find object {}. The operation in progress is MODIFY, therefore initiating synchronization", shadow);
LOGGER.trace("Starting discovery to find out if the object should exist or not.");
OperationResult handleErrorResult = result.createSubresult("com.evolveum.midpoint.provisioning.consistency.impl.ObjectNotFoundHandler.handleError.discovery");
handleErrorResult.addContext(OperationResult.CONTEXT_RESOURCE, shadow.getResource());
ObjectDeltaType shadowModifications = shadow.getObjectChange();
Collection<? extends ItemDelta> modifications = DeltaConvertor.toModifications(shadowModifications.getItemDelta(), shadow.asPrismObject().getDefinition());
shadow.setDead(true);
Collection<? extends ItemDelta> deadDeltas = PropertyDelta.createModificationReplacePropertyCollection(ShadowType.F_DEAD, shadow.asPrismObject().getDefinition(), true);
ConstraintsChecker.onShadowModifyOperation(deadDeltas);
cacheRepositoryService.modifyObject(ShadowType.class, shadow.getOid(), deadDeltas, result);
ResourceObjectShadowChangeDescription change = createResourceObjectShadowChangeDescription(shadow, result);
try {
changeNotificationDispatcher.notifyChange(change, task, handleErrorResult);
} catch (RuntimeException e) {
handleErrorResult.recordFatalError(e);
result.computeStatus();
throw e;
}
handleErrorResult.computeStatus();
String oidVal = null;
String oid = findCreatedAccountOid(handleErrorResult, oidVal);
if (oid != null) {
LOGGER.trace("Found new oid {} as a return param from model. Probably the new shadow was created.", oid);
LOGGER.debug("DISCOVERY: object {} re-created, applying pending changes", shadow);
LOGGER.trace("Modifying re-created object by applying pending changes:\n{}", DebugUtil.debugDump(modifications));
try {
ProvisioningOperationOptions options = new ProvisioningOperationOptions();
options.setCompletePostponed(false);
options.setDoNotDiscovery(true);
provisioningService.modifyObject(ShadowType.class, oid, modifications, null, options, task, result);
parentResult.recordHandledError("Object was recreated and modifications were applied to newly created object.");
} catch (ObjectNotFoundException e) {
parentResult.recordHandledError("Modifications were not applied, because shadow was deleted by discovery. Repository state were refreshed and unused shadow was deleted.");
}
} else {
LOGGER.debug("DISCOVERY: object {} deleted, application of pending changes skipped", shadow);
parentResult.recordHandledError("Object was deleted by discovery. Modification were not applied.");
}
// We do not need the old shadow any more. Even if the object was re-created it has a new shadow now.
try {
cacheRepositoryService.deleteObject(ShadowType.class, shadow.getOid(), parentResult);
} catch (ObjectNotFoundException e) {
// delete the old shadow that was probably deleted from the
// user, or the new one was assigned
LOGGER.debug("Cannot delete {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
result.computeStatus();
if (parentResult.isHandledError()) {
// Ugly hack. We shouldn't set parentResult status in the first place, as it can be overriden by computeStatus/recomputeStatus called in the parent.
result.setStatus(OperationResultStatus.HANDLED_ERROR);
}
if (oid != null) {
shadowModifications.setOid(oid);
shadow.setOid(oid);
}
LOGGER.debug("DISCOVERY: cannot find object {}: MODIFY operation handler done", shadow);
return shadow;
case GET:
if (!compensate) {
LOGGER.trace("DISCOVERY: cannot find object {}, GET operation: handling skipped because discovery is disabled", shadow);
result.recordFatalError(ex.getMessage(), ex);
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
LOGGER.debug("DISCOVERY: cannot find object {}. The operation in progress is GET, therefore initiating synchronization", shadow);
OperationResult handleGetErrorResult = result.createSubresult("com.evolveum.midpoint.provisioning.consistency.impl.ObjectNotFoundHandler.handleError.discovery");
handleGetErrorResult.addContext(OperationResult.CONTEXT_RESOURCE, shadow.getResource());
Collection<? extends ItemDelta> deadModification = PropertyDelta.createModificationReplacePropertyCollection(ShadowType.F_DEAD, shadow.asPrismObject().getDefinition(), true);
ConstraintsChecker.onShadowModifyOperation(deadModification);
try {
cacheRepositoryService.modifyObject(ShadowType.class, shadow.getOid(), deadModification, result);
} catch (ObjectNotFoundException e) {
// The shadow is not there. So we cannot mark it as dead.
LOGGER.debug("Cannot modify shadow {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
shadow.setDead(true);
ResourceObjectShadowChangeDescription getChange = createResourceObjectShadowChangeDescription(shadow, result);
if (task == null) {
task = taskManager.createTaskInstance();
}
try {
changeNotificationDispatcher.notifyChange(getChange, task, handleGetErrorResult);
} catch (RuntimeException e) {
LOGGER.trace("DISCOVERY: synchronization invoked for {} ended with an error {}", shadow, e);
handleGetErrorResult.recordFatalError(e);
result.computeStatus();
throw e;
}
// String oidVal = null;
handleGetErrorResult.computeStatus();
LOGGER.trace("DISCOVERY: synchronization invoked for {} finished with status {}", shadow, handleGetErrorResult.getStatus());
oid = findCreatedAccountOid(handleGetErrorResult, null);
try {
LOGGER.trace("DISCOVERY: deleting {}", shadow);
cacheRepositoryService.deleteObject(ShadowType.class, shadow.getOid(), result);
} catch (ObjectNotFoundException e) {
// delete the old shadow that was probably deleted from the
// user, or the new one was assigned
LOGGER.debug("Cannot delete {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
for (OperationResult subResult : parentResult.getSubresults()) {
subResult.muteError();
}
if (oid != null) {
PrismObject newShadow;
try {
LOGGER.trace("DISCOVERY: retrieving shadow {}", oid);
Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions.createCollection(GetOperationOptions.createDoNotDiscovery());
newShadow = provisioningService.getObject(shadow.getClass(), oid, options, task, result);
LOGGER.trace("DISCOVERY: retrieved {}", newShadow);
} catch (ObjectNotFoundException e) {
String msg = "Strange thing did happen: new shadow (" + oid + ") was supposedly created for old shadow " + shadow + ", however the new shadow was not found: " + e.getMessage();
LOGGER.error(msg);
result.recordFatalError(msg, e);
parentResult.recordFatalError(msg);
throw new ObjectNotFoundException(msg, ex);
} finally {
result.computeStatus();
}
LOGGER.debug("DISCOVERY: object {} re-created as {}. GET operation handler done: returning new shadow", shadow, newShadow);
shadow = (T) newShadow.asObjectable();
parentResult.recordHandledError("Object was re-created by the discovery.");
// parentResult status can be recomputed by the caller method
result.setStatus(OperationResultStatus.HANDLED_ERROR);
return shadow;
} else {
parentResult.recordHandledError("Object was deleted by the discovery and the invalid link was removed from the user.");
result.computeStatus();
// parentResult status can be recomputed by the caller method
result.setStatus(OperationResultStatus.HANDLED_ERROR);
LOGGER.debug("DISCOVERY: object {} was deleted. GET operation handler done: throwing ObjectNotFoundException", shadow);
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
default:
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
}
Aggregations