Skip to content

Commit

Permalink
Support development-mode resources in model
Browse files Browse the repository at this point in the history
This commit makes sure that activation, projection, and delta execution
are skipped for non-production projections when running in "production
configuration" mode.

Work in progress.
  • Loading branch information
mederly committed Dec 8, 2022
1 parent de46a89 commit 91b46b0
Show file tree
Hide file tree
Showing 18 changed files with 730 additions and 476 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.schema.VirtualAssignmentSpecification;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LifecycleStateModelType;
Expand Down Expand Up @@ -74,22 +73,6 @@ public static <R extends AbstractRoleType> VirtualAssignmentSpecification<R> get
return virtualAssignmentSpecification;
}

/**
* Returns true if the specified configuration item (e.g. resource, object class, object type, item, mapping, ...)
* is in "production" lifecycle state.
*
* The idea is that configuration items in `active` and `deprecated` states will have a different behavior
* than the ones in `proposed` state. (The behavior of other states is going to be determined later.)
*
* TODO Preliminary code.
*/
@Experimental
public static boolean isInProduction(String lifecycleState) {
return lifecycleState == null
|| SchemaConstants.LIFECYCLE_ACTIVE.equals(lifecycleState)
|| SchemaConstants.LIFECYCLE_DEPRECATED.equals(lifecycleState);
}

// public static <T extends AbstractRoleType> Collection<T> getListOfForcedRoles(LifecycleStateModelType lifecycleModel,
// String targetLifecycleState, PrismContext prismContext, ObjectResolver resolver, Task task, OperationResult result) {
// ObjectFilter filter = getForcedAssignmentFilter(lifecycleModel, targetLifecycleState, prismContext);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2010-2022 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.schema.util;

import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.processor.ResourceObjectClassDefinition;
import com.evolveum.midpoint.schema.processor.ResourceObjectDefinition;
import com.evolveum.midpoint.schema.processor.ResourceObjectTypeDefinition;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Temporary
*/
public class SimulationUtil {

/**
* Returns true if the specified configuration item (e.g. resource, object class, object type, item, mapping, ...)
* is in "production" lifecycle state.
*
* The idea is that configuration items in `active` and `deprecated` states will have a different behavior
* than the ones in `proposed` state. (The behavior of other states is going to be determined later.)
*
* TODO Preliminary code.
*/
@Experimental
private static boolean isInProduction(String lifecycleState) {
return lifecycleState == null
|| SchemaConstants.LIFECYCLE_ACTIVE.equals(lifecycleState)
|| SchemaConstants.LIFECYCLE_DEPRECATED.equals(lifecycleState);
}

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean isInProduction(@NotNull ResourceType resource) {
return isInProduction(resource.getLifecycleState());
}

public static boolean isInProduction(@NotNull ResourceObjectDefinition objectDefinition) {
// Object class
ResourceObjectClassDefinition classDefinition = objectDefinition.getObjectClassDefinition();
if (!SimulationUtil.isInProduction(classDefinition.getLifecycleState())) {
return false;
}
// Object type (if there's any)
ResourceObjectTypeDefinition typeDefinition = objectDefinition.getTypeDefinition();
return typeDefinition == null || SimulationUtil.isInProduction(typeDefinition.getLifecycleState());
}

/** TODO description */
public static boolean isInProduction(@NotNull ResourceType resource, @Nullable ResourceObjectDefinition objectDefinition) {
if (!isInProduction(resource)) {
// The whole resource is in development mode. We ignore any object class/type level settings in this case.
return false;
} else {
// If there is an object class, it must be in production
return objectDefinition == null || isInProduction(objectDefinition);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,4 @@ SimulationResultContext newSimulationResult(@Nullable SimulationResultType confi

SimulationResultType newConfiguration();




}
Original file line number Diff line number Diff line change
Expand Up @@ -1672,7 +1672,7 @@ void unregisterConflictWatcher(RepositoryService repositoryService) {
}

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean hasProjectionChange() {
public boolean hasProjectionChange() throws SchemaException, ConfigurationException {
for (LensProjectionContext projectionContext : getProjectionContexts()) {
if (projectionContext.getWave() != getExecutionWave()) {
continue;
Expand All @@ -1686,6 +1686,12 @@ public boolean hasProjectionChange() {
if (projectionContext.isGone()) {
continue;
}
if (!projectionContext.isVisible()) {
// Maybe we should act on really executed deltas. But adding a linkRef to development-mode resource
// is a real primary delta, even if not executed. That's why we check the visibility here. Later we
// should remove this hack.
continue;
}
if (projectionContext.hasPrimaryDelta() || projectionContext.hasSecondaryDelta()) {
return true;
}
Expand Down Expand Up @@ -2007,6 +2013,11 @@ public enum ExportType {
MINIMAL, REDUCED, OPERATIONAL, TRACE
}

/** Returns true if the current task should see the production configuration, false if it should see development config. */
boolean isProductionConfigurationTask() {
return taskExecutionMode.isProductionConfiguration();
}

// FIXME temporary solution
public static class GetOrCreateProjectionContextResult {
public final LensProjectionContext context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1855,4 +1855,15 @@ public boolean isDefaultForKind(@NotNull ShadowKindType kind) {
public boolean isInMaintenance() {
return ResourceTypeUtil.isInMaintenance(resource);
}

/** Is the resource or object class/type visible for the current task execution mode? */
public boolean isVisible() throws SchemaException, ConfigurationException {
if (!lensContext.isProductionConfigurationTask()) {
return true; // temporary (in the future, not all the elements will be visible in non-production configuration)
}
if (resource == null) {
throw new IllegalStateException("No resource"); // temporary
}
return SimulationUtil.isInProduction(resource, getStructuralObjectDefinition());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ private void removeOrHashCredentialsDeltas() throws SchemaException {
}
}

private void applyLastProvisioningTimestamp() throws SchemaException {
private void applyLastProvisioningTimestamp() throws SchemaException, ConfigurationException {
if (!context.hasProjectionChange()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,13 @@ public void execute(OperationResult parentResult) throws SchemaException, Object
try {
LOGGER.trace("Executing projection context {}", projCtx.toHumanReadableString());

context.reportProgress(new ProgressInformation(RESOURCE_OBJECT_OPERATION,
projCtx.getKey(), ENTERING));
if (!projCtx.isVisible()) {
LOGGER.trace("Resource object definition is not visible; skipping change execution (if there's any)");
result.recordNotApplicable("Not visible");
return;
}

context.reportProgress(new ProgressInformation(RESOURCE_OBJECT_OPERATION, projCtx.getKey(), ENTERING));

ScriptExecutor<O> scriptExecutor = new ScriptExecutor<>(context, projCtx, task, b);
scriptExecutor.executeReconciliationScripts(BeforeAfterType.BEFORE, result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ class ScriptExecutor<O extends ObjectType> {
@NotNull private final Task task;
@NotNull private final ModelBeans b;

ScriptExecutor(@NotNull LensContext<O> context, @NotNull LensProjectionContext projCtx, @NotNull Task task, @NotNull ModelBeans beans) {
ScriptExecutor(
@NotNull LensContext<O> context,
@NotNull LensProjectionContext projCtx,
@NotNull Task task,
@NotNull ModelBeans beans) {
this.context = context;
this.projCtx = projCtx;
this.task = task;
Expand All @@ -83,6 +87,16 @@ void executeReconciliationScripts(BeforeAfterType order, OperationResult result)
return;
}

if (!projCtx.isVisible()) {
LOGGER.trace("Resource object definition is not visible. Skipping processing reconciliation scripts.");
return;
}

if (!task.isPersistentExecution()) {
LOGGER.trace("Not a persistent execution. Skipping processing reconciliation scripts.");
return;
}

OperationProvisioningScriptsType resourceScripts = projCtx.getResource().getScripts();
if (resourceScripts == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,16 @@ private <O extends ObjectType, F extends FocusType> void processActivation(LensC
.build();
try {

if (!projectionContext.isVisible()) {
LOGGER.trace("Projection {} is not visible for this task execution mode, skipping activation processing",
projectionContext.getHumanReadableName());
result.recordNotApplicable("Not visible");
return;
}

if (!projectionContext.isCurrentForProjection()) {
LOGGER.trace("Projection {} is not current, skipping activation processing", projectionContext.getHumanReadableName());
result.recordNotApplicable();
result.recordNotApplicable("Not current");
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,13 @@ private <F extends ObjectType> void projectProjection(LensContext<F> context, Le
return;
}

if (!projectionContext.isVisible()) {
recordSkipReason(parentResult,
"Skipping projection because the resource or object definition is not visible in current task"
+ " execution mode");
return;
}

if (projectionContext.isCompleted()) {
recordSkipReason(parentResult, "Skipping projection because the projection context is already completed");
return;
Expand Down

0 comments on commit 91b46b0

Please sign in to comment.