Search in sources :

Example 1 with RefreshShadowOperation

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;
}
Also used : ArrayList(java.util.ArrayList) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) AsynchronousOperationResult(com.evolveum.midpoint.schema.result.AsynchronousOperationResult) GenericFrameworkException(com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException) RefreshShadowOperation(com.evolveum.midpoint.schema.RefreshShadowOperation) Duration(javax.xml.datatype.Duration) XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) ObjectDeltaType(com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType) ObjectDeltaOperation(com.evolveum.midpoint.schema.ObjectDeltaOperation) ItemPath(com.evolveum.midpoint.prism.path.ItemPath)

Example 2 with RefreshShadowOperation

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;
}
Also used : ProvisioningContext(com.evolveum.midpoint.provisioning.impl.ProvisioningContext) XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) RefreshShadowOperation(com.evolveum.midpoint.schema.RefreshShadowOperation) Nullable(org.jetbrains.annotations.Nullable)

Example 3 with 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);
}
Also used : RefreshShadowOperation(com.evolveum.midpoint.schema.RefreshShadowOperation)

Example 4 with RefreshShadowOperation

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();
}
Also used : PendingOperationType(com.evolveum.midpoint.xml.ns._public.common.common_3.PendingOperationType) ShadowType(com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType) RefreshShadowOperation(com.evolveum.midpoint.schema.RefreshShadowOperation) EncryptionException(com.evolveum.midpoint.prism.crypto.EncryptionException) GenericFrameworkException(com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException) OperationResultStatus(com.evolveum.midpoint.schema.result.OperationResultStatus) XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) Collection(java.util.Collection) PropertyDelta(com.evolveum.midpoint.prism.delta.PropertyDelta) ConnectorOperationOptions(com.evolveum.midpoint.provisioning.ucf.api.ConnectorOperationOptions) PrismPropertyValue(com.evolveum.midpoint.prism.PrismPropertyValue)

Aggregations

RefreshShadowOperation (com.evolveum.midpoint.schema.RefreshShadowOperation)4 XMLGregorianCalendar (javax.xml.datatype.XMLGregorianCalendar)3 GenericFrameworkException (com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException)2 PrismPropertyValue (com.evolveum.midpoint.prism.PrismPropertyValue)1 EncryptionException (com.evolveum.midpoint.prism.crypto.EncryptionException)1 PropertyDelta (com.evolveum.midpoint.prism.delta.PropertyDelta)1 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)1 ProvisioningContext (com.evolveum.midpoint.provisioning.impl.ProvisioningContext)1 ConnectorOperationOptions (com.evolveum.midpoint.provisioning.ucf.api.ConnectorOperationOptions)1 ObjectDeltaOperation (com.evolveum.midpoint.schema.ObjectDeltaOperation)1 AsynchronousOperationResult (com.evolveum.midpoint.schema.result.AsynchronousOperationResult)1 OperationResult (com.evolveum.midpoint.schema.result.OperationResult)1 OperationResultStatus (com.evolveum.midpoint.schema.result.OperationResultStatus)1 PendingOperationType (com.evolveum.midpoint.xml.ns._public.common.common_3.PendingOperationType)1 ShadowType (com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType)1 ObjectDeltaType (com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 Duration (javax.xml.datatype.Duration)1 Nullable (org.jetbrains.annotations.Nullable)1