Skip to content

Commit

Permalink
Add diagnostics and workaround for "no schema" msg
Browse files Browse the repository at this point in the history
This is to diagnose or avoid rare but bothersome "No resource schema;
have you executed the Test Resource operation?" (MID-5931).
  • Loading branch information
mederly committed Nov 20, 2019
1 parent efe4165 commit ecef663
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 94 deletions.
Expand Up @@ -670,10 +670,7 @@ public static ShadowCheckType getShadowConstraintsCheck(ResourceType resource) {

public static boolean isValidateSchema(ResourceType resource) {
ResourceConsistencyType consistency = resource.getConsistency();
if (consistency == null) {
return false;
}
return Boolean.TRUE.equals(consistency.isValidateSchema());
return consistency != null && Boolean.TRUE.equals(consistency.isValidateSchema());
}

// TODO: maybe later move to ResourceSchema?
Expand Down
Expand Up @@ -22,6 +22,7 @@

import com.evolveum.midpoint.CacheInvalidationContext;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl;
import com.evolveum.midpoint.provisioning.ucf.api.connectors.AbstractManagedConnectorInstance;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SingleCacheStateInformationType;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -259,6 +260,11 @@ private ConnectorInstance createConnectorInstance(ConnectorSpec connectorSpec, O
connectorSpec.getResource().getName().toString(),
connectorSpec.toString());

// FIXME temporary -- remove when no longer needed (MID-5931)
if (connector instanceof AbstractManagedConnectorInstance) {
((AbstractManagedConnectorInstance) connector).setResourceOid(connectorSpec.getResource().getOid());
}

} catch (ObjectNotFoundException e) {
result.recordFatalError(e.getMessage(), e);
throw new ObjectNotFoundException(e.getMessage(), e);
Expand Down
Expand Up @@ -227,11 +227,11 @@ public void deleteResource(String oid, ProvisioningOperationOptions options, Tas
* @return completed resource
*/
private PrismObject<ResourceType> completeResource(PrismObject<ResourceType> repoResource, ResourceSchema resourceSchema,
boolean fetchedSchema, Map<String,Collection<Object>> capabilityMap, GetOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
CommunicationException, ConfigurationException, ExpressionEvaluationException {
boolean fetchedSchema, Map<String,Collection<Object>> capabilityMap, GetOperationOptions options, Task task, OperationResult parentResult)
throws ObjectNotFoundException, SchemaException, ExpressionEvaluationException {

// do not add as a subresult..it will be added later, if the completing
// of resource will be successfull.if not, it will be only set as a
// of resource will be successful.if not, it will be only set as a
// fetch result in the resource..
OperationResult result = parentResult.createMinorSubresult(OPERATION_COMPLETE_RESOURCE);

Expand Down Expand Up @@ -286,23 +286,16 @@ private PrismObject<ResourceType> completeResource(PrismObject<ResourceType> rep


try {
// Now we need to re-read the resource from the repository and re-aply the schemas. This ensures that we will
// 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.

newResource = readResourceFromRepository(repoResource.getOid(), null, result);
applyConnectorSchemaToResource(newResource, task, result);

} catch (SchemaException e) {
result.recordFatalError(e);
throw e;
} catch (ObjectNotFoundException e) {
result.recordFatalError(e);
throw e;
} catch (RuntimeException e) {
} catch (SchemaException | ObjectNotFoundException | RuntimeException e) {
result.recordFatalError(e);
throw e;
}

}

try {
Expand Down Expand Up @@ -381,12 +374,10 @@ private void completeSchemaAndCapabilities(PrismObject<ResourceType> resource, R

if (fetchedSchema) {
adjustSchemaForSimulatedCapabilities(resource, resourceSchema);
ContainerDelta<XmlSchemaType> schemaContainerDelta = createSchemaUpdateDelta(resource, resourceSchema);
modifications.add(schemaContainerDelta);
modifications.add(createSchemaUpdateDelta(resource, resourceSchema));

// We have successfully fetched the resource schema. Therefore the resource must be up.
modifications.add(createResourceAvailabilityStatusDelta(resource, AvailabilityStatusType.UP));

} else {
if (resourceSchema != null) {
CachingMetadataType schemaCachingMetadata = resource.asObjectable().getSchema().getCachingMetadata();
Expand All @@ -404,17 +395,14 @@ private void completeSchemaAndCapabilities(PrismObject<ResourceType> resource, R

if (!modifications.isEmpty()) {
try {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Completing {}:\n{}", resource, DebugUtil.debugDump(modifications, 1));
}
LOGGER.trace("Completing {}:\n{}", resource, DebugUtil.debugDumpLazily(modifications, 1));
repositoryService.modifyObject(ResourceType.class, resource.getOid(), modifications, result);
InternalMonitor.recordCount(InternalCounters.RESOURCE_REPOSITORY_MODIFY_COUNT);
} catch (ObjectAlreadyExistsException ex) {
// This should not happen
throw new SystemException(ex);
}
}

}

private void completeCapabilities(PrismObject<ResourceType> resource, boolean forceRefresh, Map<String,Collection<Object>> capabilityMap, Collection<ItemDelta<?, ?>> modifications,
Expand Down Expand Up @@ -493,18 +481,14 @@ private void completeConnectorCapabilities(ConnectorSpec connectorSpec, Capabili
}

private ContainerDelta<XmlSchemaType> createSchemaUpdateDelta(PrismObject<ResourceType> resource, ResourceSchema resourceSchema) throws SchemaException {
Document xsdDoc = null;
Document xsdDoc;
try {
xsdDoc = resourceSchema.serializeToXsd();

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Serialized XSD resource schema for {}:\n{}",
resource, DOMUtil.serializeDOMToString(xsdDoc));
LOGGER.trace("Serialized XSD resource schema for {}:\n{}", resource, DOMUtil.serializeDOMToString(xsdDoc));
}

} catch (SchemaException e) {
throw new SchemaException("Error processing resource schema for "
+ resource + ": " + e.getMessage(), e);
throw new SchemaException("Error processing resource schema for " + resource + ": " + e.getMessage(), e);
}

Element xsdElement = DOMUtil.getFirstChildElement(xsdDoc);
Expand Down Expand Up @@ -736,7 +720,7 @@ public void testConnection(PrismObject<ResourceType> resource, Task task, Operat
OperationResult schemaResult = parentResult.createSubresult(ConnectorTestOperation.RESOURCE_SCHEMA
.getOperation());

ResourceSchema schema = null;
ResourceSchema schema;
try {

schema = fetchResourceSchema(resource, capabilityMap, task, schemaResult);
Expand All @@ -755,11 +739,15 @@ public void testConnection(PrismObject<ResourceType> resource, Task task, Operat
return;
} catch (ObjectNotFoundException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Configuration error: " + e.getMessage(), e);
schemaResult.recordFatalError("Object not found: " + e.getMessage(), e);
return;
} catch (SchemaException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Configuration error: " + e.getMessage(), e);
schemaResult.recordFatalError("Schema error: " + e.getMessage(), e);
return;
} catch (RuntimeException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Unexpected error: " + e.getMessage(), e);
return;
}

Expand All @@ -781,12 +769,9 @@ public void testConnection(PrismObject<ResourceType> resource, Task task, Operat
}
}

// Invoke completeResource(). This will store the fetched schema to the
// ResourceType
// if there is no <schema> definition already. Therefore the
// testResource() can be used to
// generate the resource schema - until we have full schema caching
// capability.
// Invoke completeResource(). This will store the fetched schema to the ResourceType if there is no <schema>
// definition already. Therefore the testResource() can be used to generate the resource schema - until we
// have full schema caching capability.
try {
resource = completeResource(resource, schema, true, capabilityMap, null, task, schemaResult);
} catch (ObjectNotFoundException e) {
Expand All @@ -799,18 +784,14 @@ public void testConnection(PrismObject<ResourceType> resource, Task task, Operat
schemaResult.recordFatalError(
"Schema processing error (probably connector bug): " + e.getMessage(), e);
return;
} catch (CommunicationException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Communication error: " + e.getMessage(), e);
return;
} catch (ConfigurationException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Configuration error: " + e.getMessage(), e);
return;
} catch (ExpressionEvaluationException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Expression error: " + e.getMessage(), e);
return;
} catch (RuntimeException e) {
modifyResourceAvailabilityStatus(resource, AvailabilityStatusType.BROKEN, parentResult);
schemaResult.recordFatalError("Unspecified exception: " + e.getMessage(), e);
return;
}

schemaResult.recordSuccess();
Expand Down
Expand Up @@ -40,7 +40,7 @@
*/
public interface ConnectorFactory {

String OPERATION_LIST_CONNECTOR = ConnectorFactory.class.getName()+".listConnectors";
String OPERATION_LIST_CONNECTORS = ConnectorFactory.class.getName()+".listConnectors";

PrismSchema generateConnectorConfigurationSchema(ConnectorType connectorType) throws ObjectNotFoundException;

Expand All @@ -56,12 +56,12 @@ public interface ConnectorFactory {
* a different factory.
* TODO: Better error handling
*
* @param resource resource definition
* @return configured and initialized connector instance
* @throws ObjectNotFoundException is the specified connector was not found
* @throws SchemaException
* @throws ObjectNotFoundException if the specified connector was not found
* @throws SchemaException if there's any schema issue
*/
public ConnectorInstance createConnectorInstance(ConnectorType connectorType, String namespace, String instanceName, String desc) throws ObjectNotFoundException, SchemaException;
ConnectorInstance createConnectorInstance(ConnectorType connectorType, String namespace, String instanceName, String desc)
throws ObjectNotFoundException, SchemaException;

/**
* Returns a list of all known connectors.
Expand All @@ -77,12 +77,12 @@ public interface ConnectorFactory {
* @param host definition of a connector host or null for local connector list
* @return list of all known connectors.
*/
public Set<ConnectorType> listConnectors(ConnectorHostType host, OperationResult parentRestul) throws CommunicationException;
Set<ConnectorType> listConnectors(ConnectorHostType host, OperationResult parentResult) throws CommunicationException;

/**
* Execute self-test for each connector framework that is capable of executing tests.
*/
public void selfTest(OperationResult parentTestResult);
void selfTest(OperationResult parentTestResult);

boolean supportsFramework(String frameworkIdentifier);

Expand Down
Expand Up @@ -45,6 +45,7 @@ public abstract class AbstractManagedConnectorInstance implements ConnectorInsta
private boolean configured = false;

private String instanceName; // resource name
private String resourceOid; // FIXME temporary -- remove when no longer needed (MID-5931)

public ConnectorType getConnectorObject() {
return connectorObject;
Expand Down Expand Up @@ -103,9 +104,8 @@ protected void setCapabilities(Collection<Object> capabilities) {
}

@Override
public void initialize(ResourceSchema resourceSchema, Collection<Object> capabilities,
boolean caseIgnoreAttributeNames, OperationResult parentResult)
throws CommunicationException, GenericFrameworkException, ConfigurationException {
public void initialize(ResourceSchema resourceSchema, Collection<Object> capabilities, boolean caseIgnoreAttributeNames,
OperationResult parentResult) {

OperationResult result = parentResult.createSubresult(ConnectorInstance.OPERATION_INITIALIZE);
result.addContext("connector", getConnectorObject().toString());
Expand All @@ -124,8 +124,7 @@ public void updateSchema(ResourceSchema resourceSchema) {

@Override
public void configure(PrismContainerValue<?> configuration, List<QName> generateObjectClasses, OperationResult parentResult)
throws CommunicationException, GenericFrameworkException, SchemaException,
ConfigurationException {
throws SchemaException, ConfigurationException {

OperationResult result = parentResult.createSubresult(ConnectorInstance.OPERATION_CONFIGURE);

Expand Down Expand Up @@ -217,4 +216,12 @@ public String getInstanceName() {
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
}

public String getResourceOid() {
return resourceOid;
}

public void setResourceOid(String resourceOid) {
this.resourceOid = resourceOid;
}
}
Expand Up @@ -225,8 +225,8 @@ private ItemDefinition<?> createPropertyDefinition(MutablePrismContainerDefiniti
}

@Override
public ConnectorInstance createConnectorInstance(ConnectorType connectorType, String namespace,
String instanceName, String desc) throws ObjectNotFoundException, SchemaException {
public ConnectorInstance createConnectorInstance(ConnectorType connectorType, String namespace, String instanceName,
String desc) throws ObjectNotFoundException {
ConnectorStruct struct = getConnectorStruct(connectorType);
Class<? extends ConnectorInstance> connectorClass = struct.connectorClass;
ConnectorInstance connectorInstance;
Expand Down Expand Up @@ -257,8 +257,8 @@ public ConnectorInstance createConnectorInstance(ConnectorType connectorType, St
if (connectorInstance instanceof TracerAware) {
((TracerAware) connectorInstance).setTracer(tracer);
}
if (connectorInstance instanceof TaskManagerAware) {
((TaskManagerAware) connectorInstance).setTaskManager(taskManager);
if (connectorInstance instanceof RepositoryAware) {
((RepositoryAware) connectorInstance).setRepositoryService(repositoryService);
}
return connectorInstance;
}
Expand Down
Expand Up @@ -150,7 +150,7 @@ protected String createTicketAdd(PrismObject<? extends ShadowType> object,
protected String createTicketModify(ObjectClassComplexTypeDefinition objectClass,
PrismObject<ShadowType> shadow, Collection<? extends ResourceAttribute<?>> identifiers, String resourceOid, Collection<Operation> changes,
OperationResult result) throws SchemaException, ObjectAlreadyExistsException {
LOGGER.debug("Creating case to modify account {}:\n{}", identifiers, DebugUtil.debugDump(changes, 1));
LOGGER.debug("Creating case to modify account {}:\n{}", identifiers, DebugUtil.debugDumpLazily(changes, 1));
if (InternalsConfig.isSanityChecks()) {
if (MiscUtil.hasDuplicates(changes)) {
throw new SchemaException("Duplicated changes: "+changes);
Expand Down
Expand Up @@ -13,6 +13,8 @@
import com.evolveum.midpoint.provisioning.ucf.api.async.AsyncUpdateSource;
import com.evolveum.midpoint.provisioning.ucf.api.async.ChangeListener;
import com.evolveum.midpoint.provisioning.ucf.api.connectors.AbstractManagedConnectorInstance;
import com.evolveum.midpoint.repo.api.RepositoryAware;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.SearchResultMetadata;
import com.evolveum.midpoint.schema.constants.ConnectorTestOperation;
import com.evolveum.midpoint.schema.internals.InternalMonitor;
Expand Down Expand Up @@ -51,7 +53,7 @@
@SuppressWarnings("DefaultAnnotationParam")
@ManagedConnector(type="AsyncUpdateConnector", version="1.0.0")
public class AsyncUpdateConnectorInstance extends AbstractManagedConnectorInstance implements UcfExpressionEvaluatorAware,
SecurityContextManagerAware, TracerAware, TaskManagerAware {
SecurityContextManagerAware, TracerAware, TaskManagerAware, RepositoryAware {

@SuppressWarnings("unused")
private static final Trace LOGGER = TraceManager.getTrace(AsyncUpdateConnectorInstance.class);
Expand All @@ -74,6 +76,8 @@ public class AsyncUpdateConnectorInstance extends AbstractManagedConnectorInstan

private TaskManager taskManager;

private RepositoryService repositoryService;

/**
* Listening helper. Null if there's no listening in progress.
*/
Expand Down Expand Up @@ -212,6 +216,16 @@ public void setTaskManager(TaskManager taskManager) {
this.taskManager = taskManager;
}

@Override
public RepositoryService getRepositoryService() {
return repositoryService;
}

@Override
public void setRepositoryService(RepositoryService repositoryService) {
this.repositoryService = repositoryService;
}

ExpressionType getTransformExpression() {
return configuration.getTransformExpression();
}
Expand All @@ -222,7 +236,7 @@ public AsyncUpdateErrorHandlingActionType getErrorHandlingAction() {
AsyncUpdateErrorHandlingActionType.STOP_PROCESSING);
}

public SourceManager getSourceManager() {
SourceManager getSourceManager() {
return sourceManager;
}

Expand Down Expand Up @@ -310,4 +324,15 @@ public void fetchChanges(ObjectClassComplexTypeDefinition objectClass, PrismProp
public String toString() {
return "AsyncUpdateConnectorInstance (" + getInstanceName() + ")";
}

@Override
protected void setResourceSchema(ResourceSchema resourceSchema) {
super.setResourceSchema(resourceSchema);
// TODO eliminate these diagnostic messages when no longer needed (MID-5931)
if (resourceSchema == null) {
LOGGER.warn("Setting null resource schema for {}. This might or might not be OK, depending on circumstances", this);
} else {
LOGGER.info("Setting resource schema for {}", this);
}
}
}

0 comments on commit ecef663

Please sign in to comment.