Skip to content

Commit

Permalink
NIFI-13757 Improve handling when a NAR contains an extension that pro…
Browse files Browse the repository at this point in the history
…duces an Error (#9274)

Signed-off-by: David Handermann <exceptionfactory@apache.org>
  • Loading branch information
bbende committed Sep 18, 2024
1 parent 9b7b246 commit 44abe39
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,15 @@ public static void documentConfigurableComponent(final Set<ExtensionDefinition>
}
}
case JAVA -> {
final Class<?> extensionClass = extensionManager.getClass(extensionDefinition);
final Class<? extends ConfigurableComponent> componentClass = extensionClass.asSubclass(ConfigurableComponent.class);
// Catch Throwable here to protect against an extension that may have been registered, but throws an Error when attempting to access the Class,
// this method is called during start-up, and we don't want to fail starting just because one bad extension class can't be loaded
try {
final Class<?> extensionClass = extensionManager.getClass(extensionDefinition);
final Class<? extends ConfigurableComponent> componentClass = extensionClass.asSubclass(ConfigurableComponent.class);
logger.debug("Documentation generation started: Component Class [{}]", componentClass);
document(extensionManager, componentDirectory, componentClass, coordinate);
} catch (Exception e) {
logger.warn("Documentation generation failed: Component Class [{}]", componentClass, e);
} catch (Throwable t) {
logger.warn("Documentation generation failed: Component Class [{}]", extensionDefinition.getImplementationClassName(), t);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ public void run() {
final BundleCoordinate loadedCoordinate = loadedBundle.getBundleDetails().getCoordinate();
LOGGER.info("NAR [{}] was installed", loadedCoordinate);
if (loadedCoordinate.equals(coordinate)) {
// If the NAR that was just uploaded was successfully loaded, attempt to access the class of each extension to prove that each
// class can load successfully, if not then we want to bounce out to the catch block and set the state as FAILED
final Set<ExtensionDefinition> loadedExtensionDefinitions = extensionManager.getTypes(coordinate);
for (final ExtensionDefinition loadedExtensionDefinition : loadedExtensionDefinitions) {
final Class<?> extensionClass = extensionManager.getClass(loadedExtensionDefinition);
LOGGER.debug("Loaded [{}] from bundle [{}]", extensionClass.getCanonicalName(), coordinate);
}
narNode.setState(NarState.INSTALLED);
} else {
try {
Expand Down Expand Up @@ -133,10 +140,10 @@ public void run() {
// Notify the NAR Manager that the install task complete for the current NAR
narManager.completeInstall(narNode.getIdentifier());

} catch (final Exception e) {
LOGGER.error("Failed to install NAR [{}]", coordinate, e);
} catch (final Throwable t) {
LOGGER.error("Failed to install NAR [{}]", coordinate, t);
narNode.setState(NarState.FAILED);
narNode.setFailureMessage(e.getMessage());
narNode.setFailureMessage(t.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@
import org.apache.nifi.web.revision.RevisionManager;

import jakarta.ws.rs.WebApplicationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.Collator;
Expand Down Expand Up @@ -288,20 +290,17 @@

public final class DtoFactory {

@SuppressWarnings("rawtypes")
private final static Comparator<Class> CLASS_NAME_COMPARATOR = new Comparator<Class>() {
@Override
public int compare(final Class class1, final Class class2) {
return Collator.getInstance(Locale.US).compare(class1.getSimpleName(), class2.getSimpleName());
}
};
public static final String SENSITIVE_VALUE_MASK = "********";
private static final Logger logger = LoggerFactory.getLogger(DtoFactory.class);

@SuppressWarnings("rawtypes")
private final static Comparator<Class> CLASS_NAME_COMPARATOR = (class1, class2) -> Collator.getInstance(Locale.US).compare(class1.getSimpleName(), class2.getSimpleName());
public static final String SENSITIVE_VALUE_MASK = "********";

private BulletinRepository bulletinRepository;
private ControllerServiceProvider controllerServiceProvider;
private EntityFactory entityFactory;
private Authorizer authorizer;
private ExtensionManager extensionManager;
private BulletinRepository bulletinRepository;
private ControllerServiceProvider controllerServiceProvider;
private EntityFactory entityFactory;
private Authorizer authorizer;
private ExtensionManager extensionManager;

public ControllerConfigurationDTO createControllerConfigurationDto(final ControllerFacade controllerFacade) {
final ControllerConfigurationDTO dto = new ControllerConfigurationDTO();
Expand Down Expand Up @@ -3291,9 +3290,15 @@ public Set<DocumentedTypeDTO> fromDocumentedTypes(final Set<ExtensionDefinition>
continue;
}

final Class cls = extensionManager.getClass(extensionDefinition);
if (cls != null) {
classBundles.put(cls, extensionDefinition.getBundle());
// Catch Throwable here to protect against an extension that may have been registered, but throws an Error when attempting to access the Class,
// we don't need to fail the overall request since we can still return all the other components that are still usable
try {
final Class cls = extensionManager.getClass(extensionDefinition);
if (cls != null) {
classBundles.put(cls, extensionDefinition.getBundle());
}
} catch (final Throwable t) {
logger.warn("Unable to get extension class for [{}]", extensionDefinition.getImplementationClassName(), t);
}
}

Expand Down

0 comments on commit 44abe39

Please sign in to comment.