Skip to content

Commit

Permalink
adding of testConnection method for resource object that isn't stored…
Browse files Browse the repository at this point in the history
… in the repository
  • Loading branch information
skublik committed Apr 29, 2022
1 parent 51a6a52 commit 8eb1c2f
Show file tree
Hide file tree
Showing 8 changed files with 405 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ public Object executeScript(String resourceOid, ProvisioningScriptType script, T
public OperationResult testResource(String resourceOid, Task task) {
return null;
}
@Override
public OperationResult testResource(PrismObject<ResourceType> resource, Task task) {
return null;
}

@Override
public Set<ConnectorType> discoverConnectors(ConnectorHostType hostType, OperationResult parentResult) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ Object executeScript(String resourceOid, ProvisioningScriptType script, Task tas
*/
OperationResult testResource(String resourceOid, Task task) throws ObjectNotFoundException;

OperationResult testResource(PrismObject<ResourceType> resource, Task task) throws ObjectNotFoundException;

/**
* Discovers local or remote connectors.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.provisioning.impl.operations.OperationsHelper;
import com.evolveum.midpoint.provisioning.impl.operations.ProvisioningGetOperation;
import com.evolveum.midpoint.provisioning.impl.operations.ProvisioningSearchLikeOperation;
Expand Down Expand Up @@ -608,6 +609,28 @@ public OperationResult testResource(String resourceOid, Task task) throws Object
return testResult;
}

@Override
public OperationResult testResource(@NotNull PrismObject<ResourceType> resource, Task task) throws ObjectNotFoundException {
// We are not going to create parent result here. We don't want to
// pollute the result with
// implementation details, as this will be usually displayed in the
// table of "test resource" results.

LOGGER.trace("Start testing resource {} ", resource);

OperationResult testResult = new OperationResult(ConnectorTestOperation.TEST_CONNECTION.getOperation());
testResult.addParam("resource", resource);
testResult.addContext(OperationResult.CONTEXT_IMPLEMENTATION_CLASS, ProvisioningServiceImpl.class);

resourceManager.testConnection(resource, task, testResult);

testResult.computeStatus("Test resource has failed");

LOGGER.debug("Finished testing {}, result: {} ", resource,
testResult.getStatus());
return testResult;
}

@Override
public void refreshShadow(PrismObject<ShadowType> shadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationCapabilityType;
import com.evolveum.prism.xml.ns._public.types_3.SchemaDefinitionType;

import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Document;
Expand Down Expand Up @@ -190,11 +191,15 @@ private void applyConnectorSchema() throws StopException {
throw new StopException();
}

// Now we need to re-read the resource from the repository and re-apply the schemas. This ensures that we will
// cache the correct version and that we avoid race conditions, etc.
PrismObject<ResourceType> reloaded = beans.resourceManager.readResourceFromRepository(resource.getOid(), result);
beans.resourceManager.applyConnectorSchemasToResource(reloaded, task, result);
return reloaded;
if (isRepoResource()) {
// Now we need to re-read the resource from the repository and re-apply the schemas. This ensures that we will
// cache the correct version and that we avoid race conditions, etc.
PrismObject<ResourceType> reloaded = beans.resourceManager.readResourceFromRepository(resource.getOid(), result);
beans.resourceManager.applyConnectorSchemasToResource(reloaded, task, result);
return reloaded;
} else {
return resource;
}
}

private void parseSchema(PrismObject<ResourceType> reloaded) {
Expand All @@ -213,6 +218,16 @@ private void parseSchema(PrismObject<ResourceType> reloaded) {
private void completeSchemaAndCapabilities()
throws SchemaException, CommunicationException, ObjectNotFoundException, GenericFrameworkException,
ConfigurationException {
if (isRepoResource()) {
completeSchemaAndCapabilitiesRepoResource();
} else {
completeSchemaAndCapabilitiesResourceObject();
}
}

private void completeSchemaAndCapabilitiesRepoResource()
throws SchemaException, CommunicationException, ObjectNotFoundException, GenericFrameworkException,
ConfigurationException {

Collection<ItemDelta<?,?>> modifications = new ArrayList<>();

Expand Down Expand Up @@ -273,6 +288,52 @@ private void completeSchemaAndCapabilities()
}
}

private void completeSchemaAndCapabilitiesResourceObject()
throws SchemaException, CommunicationException, ObjectNotFoundException, GenericFrameworkException,
ConfigurationException {

// Capabilities
// we need to process capabilities first. Schema is one of the connector capabilities.
// We need to determine this capability to select the right connector for schema retrieval.
completeCapabilities(capabilityMap != null, capabilityMap, null, result);

if (rawResourceSchema == null) {
// Try to get existing schema from resource. We do not want to override this if it exists
// (but we still want to refresh the capabilities, that happens below)
rawResourceSchema = ResourceSchemaFactory.getRawSchema(resource);
}

if (rawResourceSchema == null || rawResourceSchema.isEmpty()) {
fetchResourceSchema();
}

if (rawResourceSchema != null) {
if (isSchemaFreshlyLoaded) {
adjustSchemaForSimulatedCapabilities();
resource.asObjectable().schema(createSchemaUpdateValue());

// Update the operational state (we know we are up, as the schema was freshly loaded).
AvailabilityStatusType previousStatus = ResourceTypeUtil.getLastAvailabilityStatus(resource.asObjectable());
if (previousStatus != UP) {
resource.asObjectable().operationalState(
beans.operationalStateManager.createAndLogOperationalState(
previousStatus,
UP,
resource.toString(),
"resource schema was successfully fetched"));
} else {
// just for sure (if the status changed in the meanwhile)
resource.asObjectable().getOperationalState().lastAvailabilityStatus(UP);
}
} else {
CachingMetadataType schemaCachingMetadata = getCurrentCachingMetadata();
if (schemaCachingMetadata == null) {
resource.asObjectable().getSchema().cachingMetadata(MiscSchemaUtil.generateCachingMetadata());
}
}
}
}

private CachingMetadataType getCurrentCachingMetadata() {
XmlSchemaType schema = resource.asObjectable().getSchema();
return schema != null ? schema.getCachingMetadata() : null;
Expand Down Expand Up @@ -329,12 +390,16 @@ private void completeConnectorCapabilities(ConnectorSpec connectorSpec, Capabili
CachingMetadataType cachingMetadata = capType.getCachingMetadata();
if (cachingMetadata == null) {
cachingMetadata = MiscSchemaUtil.generateCachingMetadata();
modifications.add(
PrismContext.get().deltaFactory().property().createModificationReplaceProperty(
ItemPath.create(ResourceType.F_CAPABILITIES, CapabilitiesType.F_CACHING_METADATA),
connectorSpec.getResource().getDefinition(),
cachingMetadata)
);
if (isRepoResource()) {
modifications.add(
PrismContext.get().deltaFactory().property().createModificationReplaceProperty(
ItemPath.create(ResourceType.F_CAPABILITIES, CapabilitiesType.F_CACHING_METADATA),
connectorSpec.getResource().getDefinition(),
cachingMetadata)
);
} else {
resource.asObjectable().getCapabilities().cachingMetadata(cachingMetadata);
}
}
return;
}
Expand All @@ -361,15 +426,28 @@ private void completeConnectorCapabilities(ConnectorSpec connectorSpec, Capabili
CachingMetadataType cachingMetadata = MiscSchemaUtil.generateCachingMetadata();
capType.setCachingMetadata(cachingMetadata);

//noinspection unchecked
ObjectDelta<ResourceType> capabilitiesReplaceDelta = PrismContext.get().deltaFactory().object()
.createModificationReplaceContainer(ResourceType.class, connectorSpec.getResource().getOid(),
itemPath, capType.asPrismContainerValue().clone());
if (isRepoResource()) {
//noinspection unchecked
ObjectDelta<ResourceType> capabilitiesReplaceDelta = PrismContext.get().deltaFactory().object()
.createModificationReplaceContainer(ResourceType.class, connectorSpec.getResource().getOid(),
itemPath, capType.asPrismContainerValue().clone());

modifications.addAll(capabilitiesReplaceDelta.getModifications());
modifications.addAll(capabilitiesReplaceDelta.getModifications());
}
}

private ContainerDelta<XmlSchemaType> createSchemaUpdateDelta() throws SchemaException {
PrismContainerValue<XmlSchemaType> cval = createSchemaUpdateValue().asPrismContainerValue();

PrismContext prismContext = PrismContext.get();
ContainerDelta<XmlSchemaType> schemaContainerDelta =
prismContext.deltaFactory().container().createDelta(ResourceType.F_SCHEMA, ResourceType.class);
schemaContainerDelta.setValueToReplace(cval);

return schemaContainerDelta;
}

private XmlSchemaType createSchemaUpdateValue() throws SchemaException {
Document xsdDoc;
try {
xsdDoc = rawResourceSchema.serializeToXsd();
Expand All @@ -385,26 +463,17 @@ private ContainerDelta<XmlSchemaType> createSchemaUpdateDelta() throws SchemaExc
throw new SchemaException("No schema was generated for " + resource);
}

PrismContext prismContext = PrismContext.get();
ContainerDelta<XmlSchemaType> schemaContainerDelta =
prismContext.deltaFactory().container().createDelta(ResourceType.F_SCHEMA, ResourceType.class);
PrismContainerValue<XmlSchemaType> cval = prismContext.itemFactory().createContainerValue();
schemaContainerDelta.setValueToReplace(cval);
PrismProperty<CachingMetadataType> cachingMetadataProperty = cval.createProperty(XmlSchemaType.F_CACHING_METADATA);
cachingMetadataProperty.setRealValue(
MiscSchemaUtil.generateCachingMetadata());
XmlSchemaType schemaType = new XmlSchemaType()
.cachingMetadata(MiscSchemaUtil.generateCachingMetadata());
List<QName> objectClasses = ResourceTypeUtil.getSchemaGenerationConstraints(resource);
if (objectClasses != null) {
PrismProperty<SchemaGenerationConstraintsType> generationConstraints =
cval.createProperty(XmlSchemaType.F_GENERATION_CONSTRAINTS);
SchemaGenerationConstraintsType constraints = new SchemaGenerationConstraintsType();
constraints.getGenerateObjectClass().addAll(objectClasses);
generationConstraints.setRealValue(constraints);
schemaType.beginGenerationConstraints().getGenerateObjectClass().addAll(objectClasses);
}
PrismProperty<SchemaDefinitionType> definitionProperty = cval.createProperty(XmlSchemaType.F_DEFINITION);
ObjectTypeUtil.setXsdSchemaDefinition(definitionProperty, xsdElement);
SchemaDefinitionType schemaDef = new SchemaDefinitionType();
schemaDef.setSchema(xsdElement);
schemaType.definition(schemaDef);

return schemaContainerDelta;
return schemaType;
}

private PropertyDelta<CachingMetadataType> createMetadataUpdateDelta() {
Expand Down Expand Up @@ -497,4 +566,9 @@ public OperationResultStatus getOperationResultStatus() {
/** Stopping the evaluation, and returning the {@link #resource}. */
private static class StopException extends Exception {
}

private boolean isRepoResource() {
String resourceOid = resource.getOid();
return StringUtils.isNotEmpty(resourceOid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,18 @@ public void modifyResourceAvailabilityStatus(String resourceOid, AvailabilitySta
}
}

public void modifyResourceAvailabilityStatus(PrismObject<ResourceType> resource, AvailabilityStatusType newStatus, String statusChangeReason) {

AvailabilityStatusType currentStatus = ResourceTypeUtil.getLastAvailabilityStatus(resource.asObjectable());
String resourceDesc = resource.toString();

if (newStatus != currentStatus) {
OperationalStateType newState = operationalStateManager.createAndLogOperationalState(
currentStatus,newStatus, resourceDesc, statusChangeReason);
resource.asObjectable().operationalState(newState);
}
}

public void applyDefinition(
ObjectDelta<ResourceType> delta,
ResourceType resourceWhenNoOid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,9 @@ public class ResourceOperationalStateManager {
AvailabilityStatusType newStatus, String resourceDesc, String statusChangeReason,
PrismObject<ResourceType> resource) throws SchemaException {

String stateChangeClause;
if (previousStatus != null) {
stateChangeClause = "changed from " + previousStatus + " to " + newStatus;
} else {
stateChangeClause = "set to " + newStatus;
}
String stateChangeClause = getChangeClauseAndLogState(previousStatus, newStatus, resourceDesc, statusChangeReason);

// The level is INFO because it's needed for diagnosing the issues with resource availability.
LOGGER.info("Availability status {} for {} because {}", stateChangeClause, resourceDesc, statusChangeReason);

OperationalStateType changeStateRecord = new OperationalStateType(prismContext);
changeStateRecord.setLastAvailabilityStatus(newStatus);
changeStateRecord.setMessage("Status " + stateChangeClause + " because " + statusChangeReason);
changeStateRecord.setNodeId(taskManager.getNodeId());
changeStateRecord.setTimestamp(clock.currentTimeXMLGregorianCalendar());
OperationalStateType changeStateRecord = createNewOperationalState(newStatus, stateChangeClause, statusChangeReason);

List<ItemDelta<?, ?>> deltas = new ArrayList<>();
deltas.add(createOperationalStateDelta(changeStateRecord.clone()));
Expand All @@ -78,6 +66,34 @@ public class ResourceOperationalStateManager {
return deltas;
}

OperationalStateType createAndLogOperationalState(AvailabilityStatusType previousStatus,
AvailabilityStatusType newStatus, String resourceDesc, String statusChangeReason) {

String stateChangeClause = getChangeClauseAndLogState(previousStatus, newStatus, resourceDesc, statusChangeReason);
return createNewOperationalState(newStatus, stateChangeClause, statusChangeReason);
}

private OperationalStateType createNewOperationalState(AvailabilityStatusType newStatus, String stateChangeClause, String statusChangeReason) {
return new OperationalStateType()
.lastAvailabilityStatus(newStatus)
.message("Status " + stateChangeClause + " because " + statusChangeReason)
.nodeId(taskManager.getNodeId())
.timestamp(clock.currentTimeXMLGregorianCalendar());
}

private String getChangeClauseAndLogState(AvailabilityStatusType previousStatus, AvailabilityStatusType newStatus, String resourceDesc, String statusChangeReason) {
String stateChangeClause;
if (previousStatus != null) {
stateChangeClause = "changed from " + previousStatus + " to " + newStatus;
} else {
stateChangeClause = "set to " + newStatus;
}

// The level is INFO because it's needed for diagnosing the issues with resource availability.
LOGGER.info("Availability status {} for {} because {}", stateChangeClause, resourceDesc, statusChangeReason);
return stateChangeClause;
}

private ItemDelta<?, ?> createOperationalStateDelta(OperationalStateType newState) throws SchemaException {
return prismContext.deltaFor(ResourceType.class)
.item(ResourceType.F_OPERATIONAL_STATE).replace(newState)
Expand Down

0 comments on commit 8eb1c2f

Please sign in to comment.