use of io.quarkus.builder.BuildException in project quarkus-operator-sdk by quarkiverse.
the class OperatorSDKProcessor method createControllerConfiguration.
@SuppressWarnings("unchecked")
private Optional<QuarkusControllerConfiguration> createControllerConfiguration(ClassInfo info, BuildProducer<AdditionalBeanBuildItem> additionalBeans, BuildProducer<ReflectiveClassBuildItem> reflectionClasses, BuildProducer<ForceNonWeakReflectiveClassBuildItem> forcedReflectionClasses, IndexView index, CRDGeneration crdGeneration, LiveReloadBuildItem liveReload) {
// first retrieve the target resource class name
final var primaryType = JandexUtil.resolveTypeParameters(info.name(), RECONCILER, index).get(0);
final var primaryTypeDN = primaryType.name();
final var primaryTypeName = primaryTypeDN.toString();
// retrieve the reconciler's name
final var reconcilerClassName = info.name().toString();
final var controllerAnnotation = info.classAnnotation(CONTROLLER_CONFIGURATION);
final String name = ConfigurationUtils.getReconcilerName(reconcilerClassName, controllerAnnotation);
// if we get CustomResource instead of a subclass, ignore the controller since we cannot do anything with it
if (primaryTypeName == null || CUSTOM_RESOURCE.equals(primaryTypeDN)) {
log.infov("Skipped processing of ''{0}'' controller as it's not parameterized with a CustomResource sub-class", reconcilerClassName);
return Optional.empty();
}
// create Reconciler bean
additionalBeans.produce(AdditionalBeanBuildItem.builder().addBeanClass(reconcilerClassName).setUnremovable().setDefaultScope(APPLICATION_SCOPED).build());
// register target resource class for introspection
registerForReflection(reflectionClasses, primaryTypeName);
forcedReflectionClasses.produce(new ForceNonWeakReflectiveClassBuildItem(primaryTypeName));
// register spec and status for introspection if we're targeting a CustomResource
final var primaryCI = index.getClassByName(primaryTypeDN);
boolean isCR = false;
if (primaryCI == null) {
log.warnv("''{0}'' has not been found in the Jandex index so it cannot be introspected. Assumed not to be a CustomResource implementation. If you believe this is wrong, please index your classes with Jandex.", primaryTypeDN);
} else {
try {
isCR = JandexUtil.isSubclassOf(index, primaryCI, CUSTOM_RESOURCE);
} catch (BuildException e) {
log.errorv("Couldn't ascertain if ''{0}'' is a CustomResource subclass. Assumed not to be.", e);
}
}
String specClassName = null;
String statusClassName = null;
if (isCR) {
final var crParamTypes = JandexUtil.resolveTypeParameters(primaryTypeDN, CUSTOM_RESOURCE, index);
specClassName = crParamTypes.get(0).name().toString();
statusClassName = crParamTypes.get(1).name().toString();
registerForReflection(reflectionClasses, specClassName);
registerForReflection(reflectionClasses, statusClassName);
}
// now check if there's more work to do, depending on reloaded state
Class<? extends HasMetadata> resourceClass = null;
String resourceFullName = null;
// check if we need to regenerate the CRD
final var changeInformation = liveReload.getChangeInformation();
if (isCR && crdGeneration.wantCRDGenerated()) {
// check whether we already have generated CRDs
var storedCRDInfos = liveReload.getContextObject(ContextStoredCRDInfos.class);
// request CRD generation by default
final boolean[] generateCurrent = { true };
final var crClass = (Class<? extends CustomResource>) loadClass(primaryTypeName);
resourceClass = crClass;
resourceFullName = getFullResourceName(crClass);
// When we have a live reload, check if we need to regenerate the associated CRD
if (liveReload.isLiveReload() && storedCRDInfos != null) {
final var finalCrdName = resourceFullName;
final var crdInfos = storedCRDInfos.getCRDInfosFor(resourceFullName);
// check for all CRD spec version requested
buildTimeConfiguration.crd.versions.forEach(v -> {
final var crd = crdInfos.get(v);
// if we don't have any information about this CRD version, we need to generate the CRD
if (crd == null) {
return;
}
// if dependent classes have been changed
if (changeInformation != null) {
for (String changedClass : changeInformation.getChangedClasses()) {
if (crd.getDependentClassNames().contains(changedClass)) {
// a dependent class has been changed, so we'll need to generate the CRD
return;
}
}
}
// we've looked at all the changed classes and none have been changed for this CR/version: do not regenerate CRD
generateCurrent[0] = false;
log.infov("''{0}'' CRD generation was skipped for ''{1}'' because no changes impacting the CRD were detected", v, finalCrdName);
});
}
// if we still need to generate the CRD, add the CR to the set to be generated
if (generateCurrent[0]) {
crdGeneration.withCustomResource(crClass, resourceFullName, name);
}
}
// check if we need to regenerate the configuration for this controller
QuarkusControllerConfiguration configuration = null;
boolean regenerateConfig = true;
var storedConfigurations = liveReload.getContextObject(ContextStoredControllerConfigurations.class);
if (liveReload.isLiveReload() && storedConfigurations != null) {
// check if we've already generated a configuration for this controller
configuration = storedConfigurations.getConfigurations().get(reconcilerClassName);
if (configuration != null) {
/*
* A configuration needs to be regenerated if:
* - the ResourceController annotation has changed
* - the associated CustomResource metadata has changed
* - the configuration properties have changed as follows:
* + extension-wide properties affecting all controllers have changed
* + controller-specific properties have changed
*
* Here, we only perform a simplified check: either the class holding the ResourceController annotation has
* changed, or the associated CustomResource class or application.properties as a whole has changed. This
* could be optimized further if needed.
*
*/
final var changedClasses = changeInformation == null ? Collections.emptySet() : changeInformation.getChangedClasses();
regenerateConfig = changedClasses.contains(reconcilerClassName) || changedClasses.contains(primaryTypeName) || liveReload.getChangedResources().contains("application.properties");
}
}
if (regenerateConfig) {
// extract the configuration from annotation and/or external configuration
final var delayedRegistrationAnnotation = info.classAnnotation(DELAY_REGISTRATION);
final var configExtractor = new BuildTimeHybridControllerConfiguration(buildTimeConfiguration, buildTimeConfiguration.controllers.get(name), controllerAnnotation, delayedRegistrationAnnotation);
if (resourceFullName == null) {
resourceClass = (Class<? extends HasMetadata>) loadClass(primaryTypeName);
resourceFullName = getFullResourceName(resourceClass);
}
final var crVersion = HasMetadata.getVersion(resourceClass);
// create the configuration
configuration = new QuarkusControllerConfiguration(reconcilerClassName, name, resourceFullName, crVersion, configExtractor.generationAware(), primaryTypeName, configExtractor.delayedRegistration(), configExtractor.namespaces(name), getFinalizer(controllerAnnotation, resourceFullName), getLabelSelector(controllerAnnotation), Optional.ofNullable(specClassName), Optional.ofNullable(statusClassName));
log.infov("Processed ''{0}'' reconciler named ''{1}'' for ''{2}'' resource (version ''{3}'')", reconcilerClassName, name, resourceFullName, HasMetadata.getApiVersion(resourceClass));
} else {
log.infov("Skipped configuration reload for ''{0}'' reconciler as no changes were detected", reconcilerClassName);
}
// store the configuration in the live reload context
if (storedConfigurations == null) {
storedConfigurations = new ContextStoredControllerConfigurations();
}
storedConfigurations.getConfigurations().put(reconcilerClassName, configuration);
liveReload.setContextObject(ContextStoredControllerConfigurations.class, storedConfigurations);
return Optional.of(configuration);
}
Aggregations