diff --git a/controller/src/main/java/org/jboss/as/controller/RunningModeControl.java b/controller/src/main/java/org/jboss/as/controller/RunningModeControl.java index ffba4eab7b5..4274c9ff3d0 100644 --- a/controller/src/main/java/org/jboss/as/controller/RunningModeControl.java +++ b/controller/src/main/java/org/jboss/as/controller/RunningModeControl.java @@ -81,4 +81,5 @@ public String getAndClearNewBootFileName() { public void setNewBootFileName(String newBootFileName) { this.newBootFileName = newBootFileName; } + } diff --git a/controller/src/main/java/org/jboss/as/controller/access/constraint/SensitivityClassification.java b/controller/src/main/java/org/jboss/as/controller/access/constraint/SensitivityClassification.java index 3906a9e1a01..1cb2d8b1725 100644 --- a/controller/src/main/java/org/jboss/as/controller/access/constraint/SensitivityClassification.java +++ b/controller/src/main/java/org/jboss/as/controller/access/constraint/SensitivityClassification.java @@ -27,6 +27,7 @@ public class SensitivityClassification extends AbstractSensitivity { public static final SensitivityClassification MODULE_LOADING = new SensitivityClassification("module-loading", false, false, true); public static final SensitivityClassification PATCHING = new SensitivityClassification("patching", false, false, true); public static final SensitivityClassification READ_WHOLE_CONFIG = new SensitivityClassification("read-whole-config", false, true, true); + public static final SensitivityClassification RELOAD_ENHANCED = new SensitivityClassification("reload-enhanced", false, false, false); public static final SensitivityClassification SECURITY_REALM = new SensitivityClassification("security-realm", true, true, true); public static final SensitivityClassification SECURITY_REALM_REF = new SensitivityClassification("security-realm-ref", true, true, true); public static final SensitivityClassification SECURITY_DOMAIN = new SensitivityClassification("security-domain", true, true, true); diff --git a/controller/src/main/java/org/jboss/as/controller/access/management/SensitiveTargetAccessConstraintDefinition.java b/controller/src/main/java/org/jboss/as/controller/access/management/SensitiveTargetAccessConstraintDefinition.java index c33de11eca6..e7da1cc81ad 100644 --- a/controller/src/main/java/org/jboss/as/controller/access/management/SensitiveTargetAccessConstraintDefinition.java +++ b/controller/src/main/java/org/jboss/as/controller/access/management/SensitiveTargetAccessConstraintDefinition.java @@ -35,6 +35,7 @@ public class SensitiveTargetAccessConstraintDefinition implements AccessConstrai public static final SensitiveTargetAccessConstraintDefinition MODULE_LOADING = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.MODULE_LOADING); public static final SensitiveTargetAccessConstraintDefinition PATCHING = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.PATCHING); public static final SensitiveTargetAccessConstraintDefinition READ_WHOLE_CONFIG = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.READ_WHOLE_CONFIG); + public static final SensitiveTargetAccessConstraintDefinition RELOAD_ENHANCED = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.RELOAD_ENHANCED); public static final SensitiveTargetAccessConstraintDefinition SECURITY_DOMAIN = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.SECURITY_DOMAIN); public static final SensitiveTargetAccessConstraintDefinition SECURITY_DOMAIN_REF = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.SECURITY_DOMAIN_REF); public static final SensitiveTargetAccessConstraintDefinition SECURITY_REALM = new SensitiveTargetAccessConstraintDefinition(SensitivityClassification.SECURITY_REALM); diff --git a/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java b/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java index e856e8bef10..77791e4c28e 100644 --- a/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java +++ b/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java @@ -4,6 +4,8 @@ */ package org.jboss.as.controller.descriptions; +import java.util.Set; + /** * String constants frequently used in model descriptions. * @@ -419,6 +421,7 @@ public class ModelDescriptionConstants { public static final String RELEASE_CODENAME = "release-codename"; public static final String RELEASE_VERSION = "release-version"; public static final String RELOAD = "reload"; + public static final String RELOAD_ENHANCED = "reload-enhanced"; public static final String RELOAD_REQUIRED = "reload-required"; public static final String REMOVE = "remove"; public static final String REMOTE = "remote"; @@ -614,6 +617,8 @@ public class ModelDescriptionConstants { public static final String PRIMARY = "primary"; public static final String PERFORM_INSTALLATION = "perform-installation"; + public static final Set RELOAD_OPERATIONS = Set.of(RELOAD, RELOAD_ENHANCED); + private ModelDescriptionConstants() { } } diff --git a/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java b/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java index f2853619461..f0e5385965f 100644 --- a/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java +++ b/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java @@ -117,7 +117,7 @@ public static class Builder { private JmxAuthorizer authorizer = NO_OP_AUTHORIZER; private Supplier securityIdentitySupplier = Functions.constantSupplier(null); private RuntimeHostControllerInfoAccessor hostControllerInfoAccessor = RuntimeHostControllerInfoAccessor.SERVER; - private Stability stability = Stability.DEFAULT; + private Supplier stabilitySupplier = Functions.constantSupplier(Stability.DEFAULT); private Builder(ProcessType processType) { this.processType = processType; @@ -183,12 +183,22 @@ public Builder withHostControllerInfoAccessor(RuntimeHostControllerInfoAccessor } /** - * Overrides the default stability level of the extension registry. - * @param stability a stability level + * Overrides the default stability level of the extension registry. This is a convenience method for + * {@link #withStabilitySupplier(Supplier)}. + * @param stability the stability level to use * @return a reference to this builder */ public Builder withStability(Stability stability) { - this.stability = stability; + return withStabilitySupplier(Functions.constantSupplier(stability)); + } + + /** + * Overrides the default stability level of the extension registry. + * @param stabilitySupplier a Supplier returning the stability level + * @return a reference to this builder + */ + public Builder withStabilitySupplier(Supplier stabilitySupplier) { + this.stabilitySupplier = stabilitySupplier; return this; } @@ -209,7 +219,7 @@ public ExtensionRegistry build() { } private final ProcessType processType; - private final Stability stability; + private final Supplier stability; private SubsystemXmlWriterRegistry writerRegistry; private volatile PathManager pathManager; @@ -233,7 +243,7 @@ private ExtensionRegistry(Builder builder) { this.authorizer = builder.authorizer; this.securityIdentitySupplier = builder.securityIdentitySupplier; this.hostControllerInfoAccessor = builder.hostControllerInfoAccessor; - this.stability = builder.stability; + this.stability = builder.stabilitySupplier; } /** @@ -539,7 +549,7 @@ public TransformerRegistry getTransformerRegistry() { @Override public Stability getStability() { - return this.stability; + return this.stability.get(); } private abstract class AbstractExtensionParsingContext implements ExtensionParsingContext, AutoCloseable { diff --git a/controller/src/main/java/org/jboss/as/controller/operations/common/ProcessReloadHandler.java b/controller/src/main/java/org/jboss/as/controller/operations/common/ProcessReloadHandler.java index 49e81b5e5ff..bc58522406a 100644 --- a/controller/src/main/java/org/jboss/as/controller/operations/common/ProcessReloadHandler.java +++ b/controller/src/main/java/org/jboss/as/controller/operations/common/ProcessReloadHandler.java @@ -34,7 +34,7 @@ public abstract class ProcessReloadHandler impleme /** * The operation name. */ - protected static final String OPERATION_NAME = "reload"; + protected static final String OPERATION_NAME = ModelDescriptionConstants.RELOAD; protected static final AttributeDefinition ADMIN_ONLY = new SimpleAttributeDefinitionBuilder(ModelDescriptionConstants.ADMIN_ONLY, ModelType.BOOLEAN, true) .setDefaultValue(ModelNode.FALSE).build(); diff --git a/controller/src/main/java/org/jboss/as/controller/remote/ModelControllerClientOperationHandler.java b/controller/src/main/java/org/jboss/as/controller/remote/ModelControllerClientOperationHandler.java index 9a8a1f6722b..cc9236adbc4 100644 --- a/controller/src/main/java/org/jboss/as/controller/remote/ModelControllerClientOperationHandler.java +++ b/controller/src/main/java/org/jboss/as/controller/remote/ModelControllerClientOperationHandler.java @@ -16,7 +16,7 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OPERATION_HEADERS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; -import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELOAD; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELOAD_OPERATIONS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SHUTDOWN; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; @@ -32,6 +32,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Collections; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -68,7 +69,12 @@ */ public class ModelControllerClientOperationHandler implements ManagementRequestHandlerFactory { - private static final Set PREPARED_RESPONSE_OPERATIONS = Set.of(RELOAD, SHUTDOWN); + private static final Set PREPARED_RESPONSE_OPERATIONS; + static { + Set ops = new HashSet<>(RELOAD_OPERATIONS); + ops.add(SHUTDOWN); + PREPARED_RESPONSE_OPERATIONS = Collections.unmodifiableSet(ops); + } private final ModelController controller; private final ManagementChannelAssociation channelAssociation; @@ -193,7 +199,7 @@ public void operationPrepared(ModelController.OperationTransaction transaction, @Override public void operationPrepared(ModelController.OperationTransaction transaction, final ModelNode preparedResult, OperationContext context) { transaction.commit(); - if (context == null || !RELOAD.equals(operation.get(OP).asString())) { // TODO deal with shutdown as well, + if (context == null || !RELOAD_OPERATIONS.contains(operation.get(OP).asString())) { // TODO deal with shutdown as well, // the handlers for which have some // subtleties that need thought sendResponse(preparedResult); diff --git a/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiGenericOperationHandler.java b/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiGenericOperationHandler.java index 1fe2aead7e1..e1c53ab7441 100644 --- a/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiGenericOperationHandler.java +++ b/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiGenericOperationHandler.java @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.util.Deque; import java.util.Iterator; +import java.util.Set; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; @@ -40,6 +41,7 @@ import org.jboss.as.controller.client.OperationBuilder; import org.jboss.as.controller.client.OperationMessageHandler; import org.jboss.as.controller.client.OperationResponse; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.core.security.AccessMechanism; import org.jboss.dmr.ModelNode; import org.xnio.IoUtils; @@ -61,9 +63,12 @@ class DomainApiGenericOperationHandler implements HttpHandler { private static final String CLIENT_NAME = "X-Management-Client-Name"; + private static final Set PREPARED_RESPONSE_OPERATIONS = ModelDescriptionConstants.RELOAD_OPERATIONS; + private final ModelController modelController; private final FormParserFactory formParserFactory; + public DomainApiGenericOperationHandler(ModelController modelController) { this.modelController = modelController; this.formParserFactory = FormParserFactory.builder().build(); @@ -203,8 +208,6 @@ private static String stripSuffix(String contentType) { return contentType; } - static final String RELOAD = "reload"; - /** * Determine whether the prepared response should be sent, before the operation completed. This is needed in order * that operations like :reload() can be executed without causing communication failures. @@ -217,7 +220,7 @@ private boolean sendPreparedResponse(final ModelNode operation) { final String op = operation.get(OP).asString(); final int size = address.size(); if (size == 0) { - if (op.equals(RELOAD)) { + if (PREPARED_RESPONSE_OPERATIONS.contains(op)) { return true; } else if (op.equals(COMPOSITE)) { // TODO @@ -227,7 +230,7 @@ private boolean sendPreparedResponse(final ModelNode operation) { } } else if (size == 1) { if (address.getLastElement().getKey().equals(HOST)) { - return op.equals(RELOAD); + return PREPARED_RESPONSE_OPERATIONS.contains(op); } } return false; diff --git a/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiHandler.java b/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiHandler.java index 3fffd314edf..01d710534fd 100644 --- a/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiHandler.java +++ b/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/DomainApiHandler.java @@ -39,6 +39,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; @@ -66,7 +67,7 @@ * @author Kabir Khan */ class DomainApiHandler implements HttpHandler { - + private static final Set PREPARED_RESPONSE_OPERATIONS = ModelDescriptionConstants.RELOAD_OPERATIONS; private static final String JSON_PRETTY = "json.pretty"; /** @@ -309,6 +310,7 @@ private String unescape(String string) { } } + /** * Determine whether the prepared response should be sent, before the operation completed. This is needed in order * that operations like :reload() can be executed without causing communication failures. @@ -321,7 +323,7 @@ private boolean sendPreparedResponse(final ModelNode operation) { final String op = operation.get(OP).asString(); final int size = address.size(); if (size == 0) { - if (op.equals("reload")) { + if (PREPARED_RESPONSE_OPERATIONS.contains(op)) { return true; } else if (op.equals(COMPOSITE)) { // TODO @@ -331,7 +333,7 @@ private boolean sendPreparedResponse(final ModelNode operation) { } } else if (size == 1) { if (address.getLastElement().getKey().equals(HOST)) { - return op.equals("reload"); + return PREPARED_RESPONSE_OPERATIONS.contains(op); } } return false; diff --git a/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/EarlyResponseTransactionControl.java b/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/EarlyResponseTransactionControl.java index 8dd89595f23..e0c3418310c 100644 --- a/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/EarlyResponseTransactionControl.java +++ b/domain-http/interface/src/main/java/org/jboss/as/domain/http/server/EarlyResponseTransactionControl.java @@ -7,13 +7,13 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; -import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELOAD; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; import org.jboss.as.controller.ModelController; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.client.OperationResponse; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.remote.EarlyResponseSendListener; import org.jboss.dmr.ModelNode; @@ -29,7 +29,7 @@ final class EarlyResponseTransactionControl implements ModelController.Operation EarlyResponseTransactionControl(ResponseCallback callback, ModelNode operation) { this.callback = callback; - this.reload = RELOAD.equals(operation.get(OP).asString()); + this.reload = ModelDescriptionConstants.RELOAD_OPERATIONS.contains(operation.get(OP).asString()); } @Override diff --git a/server/src/main/java/org/jboss/as/server/Bootstrap.java b/server/src/main/java/org/jboss/as/server/Bootstrap.java index 826d298650d..e43d918bcbe 100644 --- a/server/src/main/java/org/jboss/as/server/Bootstrap.java +++ b/server/src/main/java/org/jboss/as/server/Bootstrap.java @@ -78,10 +78,12 @@ final class Configuration { private final ManagedAuditLogger auditLogger; private final DelegatingConfigurableAuthorizer authorizer; private final ManagementSecurityIdentitySupplier securityIdentitySupplier; + private ModuleLoader moduleLoader = Module.getBootModuleLoader(); private ConfigurationPersisterFactory configurationPersisterFactory; private long startTime; + public Configuration(final ServerEnvironment serverEnvironment) { assert serverEnvironment != null : "serverEnvironment is null"; this.serverEnvironment = serverEnvironment; @@ -91,7 +93,7 @@ public Configuration(final ServerEnvironment serverEnvironment) { this.securityIdentitySupplier = new ManagementSecurityIdentitySupplier(); this.extensionRegistry = ExtensionRegistry.builder(serverEnvironment.getLaunchType().getProcessType()) .withRunningModeControl(this.runningModeControl) - .withStability(serverEnvironment.getStability()) + .withStabilitySupplier(serverEnvironment::getStability) .withAuditLogger(this.auditLogger) .withAuthorizer(this.authorizer) .withSecurityIdentitySupplier(this.securityIdentitySupplier) diff --git a/server/src/main/java/org/jboss/as/server/ServerEnvironment.java b/server/src/main/java/org/jboss/as/server/ServerEnvironment.java index 40019885b5e..6496f0191d1 100644 --- a/server/src/main/java/org/jboss/as/server/ServerEnvironment.java +++ b/server/src/main/java/org/jboss/as/server/ServerEnvironment.java @@ -303,7 +303,7 @@ public ProcessType getProcessType() { private final boolean startSuspended; private final boolean startGracefully; private final GitRepository repository; - private final Stability stability; + private volatile Stability stability; public ServerEnvironment(final String hostControllerName, final Properties props, final Map env, final String serverConfig, final ConfigurationFile.InteractionPolicy configInteractionPolicy, final LaunchType launchType, @@ -523,9 +523,7 @@ public ServerEnvironment(final String hostControllerName, final Properties props } this.stability = getEnumProperty(props, ProcessEnvironment.STABILITY, productConfig.getDefaultStability()); - if (!productConfig.getStabilitySet().contains(this.stability)) { - throw ServerLogger.ROOT_LOGGER.unsupportedStability(this.stability, productConfig.getProductName()); - } + checkStabilityIsValidForInstallation(productConfig, this.stability); } boolean allowExecutor = true; String maxThreads = WildFlySecurityManager.getPropertyPrivileged(BOOTSTRAP_MAX_THREADS, null); @@ -1170,6 +1168,23 @@ protected void systemPropertyUpdated(String propertyName, String propertyValue) } } + + public void checkStabilityIsValidForInstallation(Stability stability) { + checkStabilityIsValidForInstallation(productConfig, stability); + } + + private void checkStabilityIsValidForInstallation(ProductConfig productConfig, Stability stability) { + if (!productConfig.getStabilitySet().contains(stability)) { + throw ServerLogger.ROOT_LOGGER.unsupportedStability(this.stability, productConfig.getProductName()); + } + } + + // TODO Figure out how to make this package protected + public void setStability(Stability stability) { + WildFlySecurityManager.setPropertyPrivileged(ProcessEnvironment.STABILITY, stability.toString()); + this.stability = stability; + } + /** * Get a File from configuration. * diff --git a/server/src/main/java/org/jboss/as/server/ServerService.java b/server/src/main/java/org/jboss/as/server/ServerService.java index 289894124f6..1b81847d740 100644 --- a/server/src/main/java/org/jboss/as/server/ServerService.java +++ b/server/src/main/java/org/jboss/as/server/ServerService.java @@ -201,7 +201,7 @@ static ProcessType getProcessType(ServerEnvironment serverEnvironment) { : ProcessType.EMBEDDED_SERVER; } - static Stability getStability(ServerEnvironment serverEnvironment) { + private static Stability getStability(ServerEnvironment serverEnvironment) { return serverEnvironment != null ? serverEnvironment.getStability() : Stability.DEFAULT; } diff --git a/server/src/main/java/org/jboss/as/server/controller/resources/ServerRootResourceDefinition.java b/server/src/main/java/org/jboss/as/server/controller/resources/ServerRootResourceDefinition.java index 21f593bae9e..8135be4c5f9 100644 --- a/server/src/main/java/org/jboss/as/server/controller/resources/ServerRootResourceDefinition.java +++ b/server/src/main/java/org/jboss/as/server/controller/resources/ServerRootResourceDefinition.java @@ -413,8 +413,9 @@ public void registerOperations(ManagementResourceRegistration resourceRegistrati resourceRegistration.registerOperationHandler(ServerDomainProcessShutdownHandler.DOMAIN_DEFINITION, new ServerDomainProcessShutdownHandler()); } else { - final ServerProcessReloadHandler reloadHandler = new ServerProcessReloadHandler(Services.JBOSS_AS, runningModeControl, processState, serverEnvironment); - resourceRegistration.registerOperationHandler(ServerProcessReloadHandler.DEFINITION, reloadHandler, false); + + ServerProcessReloadHandler.registerStandardReloadOperation(resourceRegistration, runningModeControl, processState, serverEnvironment); + ServerProcessReloadHandler.registerEnhancedReloadOperation(resourceRegistration, runningModeControl, processState, serverEnvironment); resourceRegistration.registerOperationHandler(ServerSuspendHandler.DEFINITION, ServerSuspendHandler.INSTANCE); resourceRegistration.registerOperationHandler(ServerResumeHandler.DEFINITION, ServerResumeHandler.INSTANCE); diff --git a/server/src/main/java/org/jboss/as/server/operations/ServerProcessReloadHandler.java b/server/src/main/java/org/jboss/as/server/operations/ServerProcessReloadHandler.java index 8c9b36ac1ff..a57c2af6d18 100644 --- a/server/src/main/java/org/jboss/as/server/operations/ServerProcessReloadHandler.java +++ b/server/src/main/java/org/jboss/as/server/operations/ServerProcessReloadHandler.java @@ -4,7 +4,10 @@ */ package org.jboss.as.server.operations; +import java.util.Collections; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.ControlledProcessState; @@ -17,12 +20,16 @@ import org.jboss.as.controller.RunningModeControl; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; import org.jboss.as.controller.SimpleOperationDefinitionBuilder; +import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.operations.common.ProcessReloadHandler; import org.jboss.as.controller.operations.validation.EnumValidator; +import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.server.ServerEnvironment; +import org.jboss.as.server.Services; import org.jboss.as.server.controller.descriptions.ServerDescriptions; import org.jboss.as.server.logging.ServerLogger; +import org.jboss.as.version.Stability; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.msc.service.ServiceName; @@ -51,20 +58,61 @@ public class ServerProcessReloadHandler extends ProcessReloadHandler additionalAttributes; private final ServerEnvironment environment; - public ServerProcessReloadHandler(ServiceName rootService, RunningModeControl runningModeControl, - ControlledProcessState processState, ServerEnvironment environment) { + + protected ServerProcessReloadHandler(ServiceName rootService, RunningModeControl runningModeControl, ControlledProcessState processState, ServerEnvironment environment) { + this(rootService, runningModeControl, processState, environment, null); + } + + private ServerProcessReloadHandler(ServiceName rootService, RunningModeControl runningModeControl, ControlledProcessState processState, ServerEnvironment environment, Set additionalAttributes) { super(rootService, runningModeControl, processState); + this.additionalAttributes = additionalAttributes == null ? Collections.emptySet() : additionalAttributes; this.environment = environment; } + public static void registerStandardReloadOperation(ManagementResourceRegistration resourceRegistration, RunningModeControl runningModeControl, ControlledProcessState processState, ServerEnvironment serverEnvironment) { + ServerProcessReloadHandler reloadHandler = new ServerProcessReloadHandler(Services.JBOSS_AS, runningModeControl, processState, serverEnvironment); + resourceRegistration.registerOperationHandler(ServerProcessReloadHandler.STANDARD_DEFINITION, reloadHandler, false); + } + + public static void registerEnhancedReloadOperation(ManagementResourceRegistration resourceRegistration, RunningModeControl runningModeControl, ControlledProcessState processState, ServerEnvironment serverEnvironment) { + ServerProcessReloadHandler reloadHandler = new ServerProcessReloadHandler(Services.JBOSS_AS, runningModeControl, processState, serverEnvironment, getAttributeNames(ENHANCED_ATTRIBUTES)); + resourceRegistration.registerOperationHandler(ServerProcessReloadHandler.ENHANCED_DEFINITION, reloadHandler, false); + } + + private static Set getAttributeNames(AttributeDefinition[] attributes) { + Set names = new HashSet<>(); + for (AttributeDefinition attr : attributes) { + names.add(attr.getName()); + } + return names; + } + @Override protected ProcessReloadHandler.ReloadContext initializeReloadContext(final OperationContext context, final ModelNode operation) throws OperationFailedException { final boolean unmanaged = context.getProcessType() != ProcessType.DOMAIN_SERVER; // make sure that the params are ignored for managed servers @@ -72,6 +120,15 @@ protected ProcessReloadHandler.ReloadContext initializeReloa final boolean useCurrentConfig = unmanaged && USE_CURRENT_SERVER_CONFIG.resolveModelAttribute(context, operation).asBoolean(true); final String startMode = START_MODE.resolveModelAttribute(context, operation).asString(); + final Stability stability; + if (additionalAttributes.contains(ModelDescriptionConstants.STABILITY) && operation.hasDefined(ModelDescriptionConstants.STABILITY)) { + String val = STABILITY.resolveModelAttribute(context, operation).asString(); + stability = Stability.fromString(val); + environment.checkStabilityIsValidForInstallation(stability); + } else { + stability = null; + } + if(operation.get(ModelDescriptionConstants.ADMIN_ONLY).isDefined() && operation.get(ModelDescriptionConstants.START_MODE).isDefined()) { throw ServerLogger.ROOT_LOGGER.cannotSpecifyBothAdminOnlyAndStartMode(); } @@ -113,6 +170,10 @@ public void doReload(RunningModeControl runningModeControl) { runningModeControl.setUseCurrentConfig(useCurrentConfig); runningModeControl.setNewBootFileName(serverConfig); runningModeControl.setSuspend(finalSuspend); + + if (stability != null) { + environment.setStability(stability); + } } }; } diff --git a/server/src/main/resources/org/jboss/as/server/controller/descriptions/LocalDescriptions.properties b/server/src/main/resources/org/jboss/as/server/controller/descriptions/LocalDescriptions.properties index 3efac468bb6..86e6129853a 100644 --- a/server/src/main/resources/org/jboss/as/server/controller/descriptions/LocalDescriptions.properties +++ b/server/src/main/resources/org/jboss/as/server/controller/descriptions/LocalDescriptions.properties @@ -71,6 +71,16 @@ server.reload.admin-only.deprecated=Use start-mode=admin-only instead. server.reload.blocking=Whether the operation should block and wait until the server is reloaded. server.reload.reply=The status of the server following execution of this operation. server.reload.deprecated=This operation may be removed from the server-config resource in a future version; use the /host=*/server= resource for server lifecycle operations. +server.reload-enhanced=Reloads the server by shutting down all its services and starting again. The JVM itself is not restarted. This is similar to the 'reload' operation, but exposes some more advanced options. +server.reload-enhanced.admin-only=Whether the server should start in running mode ADMIN_ONLY when it restarts. An ADMIN_ONLY server will start any configured management interfaces and accept management requests, but will not start services used for handling end user requests. +server.reload-enhanced.use-current-server-config=Only has an effect if --read-only-server-config was specified when starting the server. In that case, if this parameter is set to false the reloaded server loads the original configuration version; if null or true the current runtime version of the model is used. +server.reload-enhanced.server-config=Use to override the name of the server config to use for the reloaded server. When making changes to the model after the reload, the changes will still be persisted to the original server configuration file that was first used to boot up the server. This parameter is resolved the same way as the --server-config command-line option. +server.reload-enhanced.stability=Set to change the stability level of the reloaded server. +server.reload-enhanced.start-mode=Can be either normal, suspend or admin-only. If it is suspend the server will be started in suspended mode, if it is admin only the server will be started in admin-only mode. +server.reload-enhanced.admin-only.deprecated=Use start-mode=admin-only instead. +server.reload-enhanced.blocking=Whether the operation should block and wait until the server is reloaded. +server.reload-enhanced.reply=The status of the server following execution of this operation. +server.reload-enhanced.deprecated=This operation may be removed from the server-config resource in a future version; use the /host=*/server= resource for server lifecycle operations. server.start=Start a server. server.start.blocking=Whether the operation should block and wait until the server is started. server.start.start-mode=The mode the servers should started in, can be either suspend or normal. diff --git a/testsuite/elytron/src/test/java/org/wildfly/test/integration/elytron/sasl/mgmt/KerberosHttpMgmtSaslTestCase.java b/testsuite/elytron/src/test/java/org/wildfly/test/integration/elytron/sasl/mgmt/KerberosHttpMgmtSaslTestCase.java index c7f093bf149..827c885f96e 100644 --- a/testsuite/elytron/src/test/java/org/wildfly/test/integration/elytron/sasl/mgmt/KerberosHttpMgmtSaslTestCase.java +++ b/testsuite/elytron/src/test/java/org/wildfly/test/integration/elytron/sasl/mgmt/KerberosHttpMgmtSaslTestCase.java @@ -18,7 +18,6 @@ import org.jboss.as.controller.operations.common.Util; import org.jboss.as.test.integration.management.util.ServerReload; import org.jboss.as.test.integration.security.common.CoreUtils; -import org.jboss.as.test.shared.TestSuiteEnvironment; import org.jboss.dmr.ModelNode; import org.junit.runner.RunWith; import org.wildfly.core.testrunner.WildFlyRunner; @@ -81,12 +80,15 @@ protected AutoCloseable configureSaslMechanismOnServer(String mechanism, boolean final HttpMgmtConfigurator httpMgmtConfig = httpMgmtConfigBuilder.build(); httpMgmtConfig.create(client, null); - ServerReload.executeReloadAndWaitForCompletion(client, 30 * 1000, false, "remote", - TestSuiteEnvironment.getServerAddress(), PORT_NATIVE); + ServerReload.Parameters serverReloadParams = new ServerReload.Parameters() + .setTimeout(30 * 1000) + .setProtocol("remote") + .setServerPort(PORT_NATIVE); + + ServerReload.executeReloadAndWaitForCompletion(client, serverReloadParams); return () -> { httpMgmtConfig.remove(client, null); - ServerReload.executeReloadAndWaitForCompletion(client, 30 * 1000, false, "remote", - TestSuiteEnvironment.getServerAddress(), PORT_NATIVE); + ServerReload.executeReloadAndWaitForCompletion(client, serverReloadParams); }; } diff --git a/testsuite/manualmode/src/test/java/org/wildfly/core/test/standalone/mgmt/PreparedResponseTestCase.java b/testsuite/manualmode/src/test/java/org/wildfly/core/test/standalone/mgmt/PreparedResponseTestCase.java index ae20da263f0..300937a6000 100644 --- a/testsuite/manualmode/src/test/java/org/wildfly/core/test/standalone/mgmt/PreparedResponseTestCase.java +++ b/testsuite/manualmode/src/test/java/org/wildfly/core/test/standalone/mgmt/PreparedResponseTestCase.java @@ -78,7 +78,7 @@ public void reloadServer() throws Exception { try (ManagementClient managementClient = getManagementClient()) { block(managementClient); long timeout = SHUTDOWN_WAITING_TIME + System.currentTimeMillis(); - ServerReload.executeReload(managementClient.getControllerClient(), false); + ServerReload.executeReloadAndWaitForCompletion(managementClient.getControllerClient(), false); while (System.currentTimeMillis() < timeout) { Thread.sleep(FREQUENCY); try { diff --git a/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/util/ServerReload.java b/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/util/ServerReload.java index 24ca8e2a857..44af2a1413a 100644 --- a/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/util/ServerReload.java +++ b/testsuite/shared/src/main/java/org/jboss/as/test/integration/management/util/ServerReload.java @@ -22,6 +22,7 @@ import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.controller.client.helpers.ClientConstants; import org.jboss.as.test.shared.TestSuiteEnvironment; +import org.jboss.as.version.Stability; import org.jboss.dmr.ModelNode; import org.junit.Assert; import org.wildfly.core.testrunner.ManagementClient; @@ -61,7 +62,9 @@ public static void executeReloadAndWaitForCompletion(ModelControllerClient clien * @throws AssertionError if the reload does not complete within the timeout */ public static void executeReloadAndWaitForCompletion(ModelControllerClient client, boolean adminOnly) { - executeReloadAndWaitForCompletion(client, TIMEOUT, adminOnly, null, -1); + Parameters parameters = new Parameters() + .setAdminOnly(adminOnly); + executeReloadAndWaitForCompletion(client, parameters); } /** @@ -72,57 +75,36 @@ public static void executeReloadAndWaitForCompletion(ModelControllerClient clien * * @throws AssertionError if the reload does not complete within the specified timeout */ - public static void executeReloadAndWaitForCompletion(ModelControllerClient client, int timeout) { - executeReloadAndWaitForCompletion(client, timeout, false, null, -1); + private static void executeReloadAndWaitForCompletion(ModelControllerClient client, int timeout) { + Parameters parameters = new Parameters() + .setTimeout(timeout); + executeReloadAndWaitForCompletion(client, parameters); } - public static void executeReloadAndWaitForCompletion(ModelControllerClient client, ModelNode reloadOp) { - executeReloadAndWaitForCompletion(client, reloadOp, TIMEOUT, null, -1); + public static void executeReloadAndWaitForCompletion(ModelControllerClient client, Parameters parameters) { + executeReload(client, parameters); + waitForLiveServerToReload(parameters); } - public static void executeReloadAndWaitForCompletion(ModelControllerClient client, ModelNode reloadOp, int timeout, String serverAddress, int serverPort) { - executeReload(client, reloadOp); - waitForLiveServerToReload(timeout, "remote+http", - serverAddress != null ? serverAddress : TestSuiteEnvironment.getServerAddress(), - serverPort != -1 ? serverPort : TestSuiteEnvironment.getServerPort()); - } - - /** - * Executes a {@code reload} operation, optionally putting the server into {@code admin-only} - * running mode, and waits a configurable maximum time for the reload to complete. - * - * @param client the client to use for the request. Cannot be {@code null} - * @param timeout maximum time to wait for the reload to complete, in milliseconds - * @param adminOnly if {@code true}, the server will be reloaded in admin-only mode - * @param serverAddress if {@code null}, use {@code TestSuiteEnvironment.getServerAddress()} to create the ModelControllerClient - * @param serverPort if {@code -1}, use {@code TestSuiteEnvironment.getServerPort()} to create the ModelControllerClient - * - * @throws AssertionError if the reload does not complete within the specified timeout - */ - public static void executeReloadAndWaitForCompletion(ModelControllerClient client, int timeout, boolean adminOnly, String serverAddress, int serverPort) { - executeReload(client, adminOnly); - waitForLiveServerToReload(timeout, "remote+http", - serverAddress != null ? serverAddress : TestSuiteEnvironment.getServerAddress(), - serverPort != -1 ? serverPort : TestSuiteEnvironment.getServerPort()); - } - - public static void executeReloadAndWaitForCompletion(ModelControllerClient client, int timeout, boolean adminOnly, String protocol, String serverAddress, int serverPort) { - executeReload(client, adminOnly); - waitForLiveServerToReload(timeout, protocol, - serverAddress != null ? serverAddress : TestSuiteEnvironment.getServerAddress(), - serverPort != -1 ? serverPort : TestSuiteEnvironment.getServerPort()); - } - - public static void executeReload(ModelControllerClient client, boolean adminOnly) { + private static void executeReload(ModelControllerClient client, Parameters parameters) { ModelNode operation = new ModelNode(); operation.get(OP_ADDR).setEmptyList(); - operation.get(OP).set("reload"); - operation.get("admin-only").set(adminOnly); + operation.get("admin-only").set(parameters.adminOnly); + if (parameters.stability != null) { + operation.get(OP).set("reload-enhanced"); + operation.get("stability").set(parameters.stability.toString()); + } else { + operation.get(OP).set("reload"); + } + if (parameters.serverConfig != null) { + operation.get("server-config").set(parameters.serverConfig); + } executeReload(client, operation); } - public static void executeReload(ModelControllerClient client, ModelNode reloadOp) { + + private static void executeReload(ModelControllerClient client, ModelNode reloadOp) { try { ModelNode result = client.execute(reloadOp); Assert.assertEquals(SUCCESS, result.get(ClientConstants.OUTCOME).asString()); @@ -157,13 +139,13 @@ public static void reloadIfRequired(final ModelControllerClient controllerClient } } - private static void waitForLiveServerToReload(int timeout, String protocol, String serverAddress, int serverPort) { + private static void waitForLiveServerToReload(Parameters parameters) { long start = System.currentTimeMillis(); ModelNode operation = new ModelNode(); operation.get(OP_ADDR).setEmptyList(); operation.get(OP).set(READ_ATTRIBUTE_OPERATION); operation.get(NAME).set("server-state"); - while (System.currentTimeMillis() - start < timeout) { + while (System.currentTimeMillis() - start < parameters.timeout) { //do the sleep before we check, as the attribute state may not change instantly //also reload generally takes longer than 100ms anyway try { @@ -171,8 +153,8 @@ private static void waitForLiveServerToReload(int timeout, String protocol, Stri } catch (InterruptedException e) { } try { - ModelControllerClient liveClient = ModelControllerClient.Factory.create(protocol, - serverAddress, serverPort); + ModelControllerClient liveClient = ModelControllerClient.Factory.create( + parameters.protocol, parameters.serverAddress, parameters.serverPort); try { ModelNode result = liveClient.execute(operation); if ("running".equals(result.get(RESULT).asString())) { @@ -217,5 +199,53 @@ public void tearDown(ManagementClient managementClient) throws Exception { executeReloadAndWaitForCompletion(managementClient.getControllerClient()); } } + + public static class Parameters { + private int timeout = TIMEOUT; + boolean adminOnly = false; + String protocol = "remote+http"; + String serverAddress = TestSuiteEnvironment.getServerAddress(); + int serverPort = TestSuiteEnvironment.getServerPort(); + + String serverConfig = null; + + Stability stability = null; + + public Parameters setTimeout(int timeout) { + this.timeout = timeout; + return this; + } + + public Parameters setAdminOnly(boolean adminOnly) { + this.adminOnly = adminOnly; + return this; + } + + public Parameters setProtocol(String protocol) { + this.protocol = protocol; + return this; + } + + public Parameters setServerAddress(String serverAddress) { + this.serverAddress = serverAddress; + return this; + } + + public Parameters setServerPort(int serverPort) { + this.serverPort = serverPort; + return this; + } + + public Parameters setStability(Stability stability) { + this.stability = stability; + return this; + } + + public Parameters setServerConfig(String serverConfig) { + this.serverConfig = serverConfig; + return this; + } + } + } diff --git a/testsuite/shared/src/main/java/org/wildfly/test/snapshot/ServerSnapshot.java b/testsuite/shared/src/main/java/org/wildfly/test/snapshot/ServerSnapshot.java new file mode 100644 index 00000000000..0f43d56531a --- /dev/null +++ b/testsuite/shared/src/main/java/org/wildfly/test/snapshot/ServerSnapshot.java @@ -0,0 +1,64 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.test.snapshot; + +import org.jboss.as.controller.client.helpers.ClientConstants; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.test.integration.management.util.ServerReload; +import org.jboss.as.version.Stability; +import org.jboss.dmr.ModelNode; +import org.wildfly.core.testrunner.ManagementClient; + +import java.io.File; + +import static org.junit.Assert.fail; + +public class ServerSnapshot { + public static AutoCloseable takeSnapshot(ManagementClient client) { + return takeSnapshot(client, null); + } + /** + * Takes a snapshot of the current state of the server. + * + * Returns a AutoCloseable that can be used to restore the server state + * @param client The client + * @param reloadToStability the stability the AutoCloseable should reload to + * @return A closeable that can be used to restore the server + */ + public static AutoCloseable takeSnapshot(ManagementClient client, Stability reloadToStability) { + try { + ModelNode node = new ModelNode(); + node.get(ModelDescriptionConstants.OP).set("take-snapshot"); + ModelNode result = client.getControllerClient().execute(node); + if (!"success".equals(result.get(ClientConstants.OUTCOME).asString())) { + fail("Reload operation didn't finish successfully: " + result.asString()); + } + String snapshot = result.get(ModelDescriptionConstants.RESULT).asString(); + final String fileName = snapshot.contains(File.separator) ? snapshot.substring(snapshot.lastIndexOf(File.separator) + 1) : snapshot; + return new AutoCloseable() { + @Override + public void close() throws Exception { + ServerReload.Parameters parameters = new ServerReload.Parameters(); + parameters.setServerConfig(fileName); + if (reloadToStability != null) { + parameters.setStability(reloadToStability); + } + ServerReload.executeReloadAndWaitForCompletion(client.getControllerClient(), parameters); + + ModelNode node = new ModelNode(); + node.get(ModelDescriptionConstants.OP).set("write-config"); + ModelNode result = client.getControllerClient().execute(node); + if (!"success".equals(result.get(ClientConstants.OUTCOME).asString())) { + fail("Failed to write config after restoring from snapshot " + result.asString()); + } + } + }; + } catch (Exception e) { + throw new RuntimeException("Failed to take snapshot", e); + } + } + +} diff --git a/testsuite/shared/src/main/java/org/wildfly/test/stability/StabilityServerSetupSnapshotRestoreTasks.java b/testsuite/shared/src/main/java/org/wildfly/test/stability/StabilityServerSetupSnapshotRestoreTasks.java new file mode 100644 index 00000000000..da63e8ae3b6 --- /dev/null +++ b/testsuite/shared/src/main/java/org/wildfly/test/stability/StabilityServerSetupSnapshotRestoreTasks.java @@ -0,0 +1,179 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.test.stability; + +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.client.ModelControllerClient; +import org.jboss.as.controller.operations.common.Util; +import org.jboss.as.test.integration.management.ManagementOperations; +import org.jboss.as.test.integration.management.util.ServerReload; +import org.jboss.as.version.Stability; +import org.jboss.dmr.ModelNode; +import org.junit.Assert; +import org.junit.Assume; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerSetupTask; +import org.wildfly.test.snapshot.ServerSnapshot; + +import java.util.EnumSet; +import java.util.Set; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CORE_SERVICE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_OPERATION_DESCRIPTION_OPERATION; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_OPERATION_NAMES_OPERATION; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELOAD_ENHANCED; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STABILITY; +import static org.jboss.as.server.controller.descriptions.ServerDescriptionConstants.SERVER_ENVIRONMENT; + +/** + * For tests that need to run under a specific server stability level, + * the server setup tasks from the inner classes can be used to change the stability level of the server to the desired level. + * Once the test is done, the original stability level is restored. + * + * In order to not pollute the configuration with XML from a different stability level following the run of the test, + * it takes a snapshot of the server configuration in the setup() method, and + */ +public abstract class StabilityServerSetupSnapshotRestoreTasks implements ServerSetupTask { + + private final Stability desiredStability; + private volatile Stability originalStability; + + private AutoCloseable snapshot; + + + public StabilityServerSetupSnapshotRestoreTasks(Stability desiredStability) { + this.desiredStability = desiredStability; + } + + @Override + public final void setup(ManagementClient managementClient) throws Exception { + // Make sure the desired stability level is one of the ones supported by the server + Set supportedStabilityLevels = getSupportedStabilityLevels(); + Assume.assumeTrue( + String.format("%s is not a supported stability level", desiredStability, supportedStabilityLevels), + supportedStabilityLevels.contains(desiredStability)); + + // Check the reload-enhanced operation exists in the current stability level + Assume.assumeTrue( + "The reload-enhanced operation is not registered at this stability level", + checkReloadEnhancedOperationIsAvailable(managementClient)); + + // Check the reload-enhanced operation exists in the stability level we want to load to so that + // we can reload back to the current one + Stability reloadOpStability = getReloadEnhancedOperationStabilityLevel(managementClient); + Assume.assumeTrue(desiredStability.enables(reloadOpStability)); + + + + originalStability = readCurrentStability(managementClient.getControllerClient()); + + // Take a snapshot, indicating that when reloading we want to go back to the original stability + snapshot = ServerSnapshot.takeSnapshot(managementClient, originalStability); + + // All good, let's do it! + reloadToDesiredStability(managementClient.getControllerClient(), desiredStability); + + // Do any additional setup from the sub-classes + doSetup(managementClient); + } + + protected void doSetup(ManagementClient managementClient) throws Exception { + + } + + @Override + public void tearDown(ManagementClient managementClient) throws Exception { + snapshot.close(); + } + + private boolean checkReloadEnhancedOperationIsAvailable(ManagementClient managementClient) throws Exception { + ModelNode op = Util.createOperation(READ_OPERATION_NAMES_OPERATION, PathAddress.EMPTY_ADDRESS); + ModelNode result = ManagementOperations.executeOperation(managementClient.getControllerClient(), op); + for (ModelNode name : result.asList()) { + if (name.asString().equals(RELOAD_ENHANCED)) { + return true; + } + } + return false; + } + + private Stability getReloadEnhancedOperationStabilityLevel(ManagementClient managementClient) throws Exception { + ModelNode op = Util.createOperation(READ_OPERATION_DESCRIPTION_OPERATION, PathAddress.EMPTY_ADDRESS); + op.get(NAME).set(RELOAD_ENHANCED); + + ModelNode result = ManagementOperations.executeOperation(managementClient.getControllerClient(), op); + String stability = result.get(STABILITY).asString(); + return Stability.fromString(stability); + + } + private Set getSupportedStabilityLevels() { + // TODO WFCORE-6731 - see https://github.com/wildfly/wildfly-core/pull/5895#discussion_r1520489808 + // This information will be available in a management operation, For now just return a hardcoded set + return EnumSet.allOf(Stability.class); + } + + private Stability reloadToDesiredStability(ModelControllerClient client, Stability stability) throws Exception { + // Check the stability + Stability currentStability = readCurrentStability(client); + if (currentStability == stability) { + return originalStability; + } + + //Reload the server to the desired stability level + ServerReload.Parameters parameters = new ServerReload.Parameters() + .setStability(stability); + // Execute the reload + ServerReload.executeReloadAndWaitForCompletion(client, parameters); + + Stability reloadedStability = readCurrentStability(client); + Assert.assertEquals(stability, reloadedStability); + return originalStability; + } + + private Stability readCurrentStability(ModelControllerClient client) throws Exception { + ModelNode op = Util.getReadAttributeOperation(PathAddress.pathAddress(CORE_SERVICE, SERVER_ENVIRONMENT), STABILITY); + ModelNode result = ManagementOperations.executeOperation(client, op); + return Stability.fromString(result.asString()); + } + + /** + * A server setup task that sets the server stability to the default level. + */ + public static class Default extends StabilityServerSetupSnapshotRestoreTasks { + public Default() { + super(Stability.DEFAULT); + } + } + + /** + * A server setup task that sets the server stability to the community level. + */ + public static class Community extends StabilityServerSetupSnapshotRestoreTasks { + public Community() { + super(Stability.COMMUNITY); + } + } + + /** + * A server setup task that sets the server stability to the preview level. + */ + public static class Preview extends StabilityServerSetupSnapshotRestoreTasks { + public Preview() { + super(Stability.PREVIEW); + } + } + + /** + * A server setup task that sets the server stability to the experimental level. + */ + public static class Experimental extends StabilityServerSetupSnapshotRestoreTasks { + public Experimental() { + super(Stability.EXPERIMENTAL); + } + } + +} diff --git a/testsuite/standalone/src/test/java/org/jboss/as/test/integration/security/perimeter/DisableLocalAuthServerSetupTask.java b/testsuite/standalone/src/test/java/org/jboss/as/test/integration/security/perimeter/DisableLocalAuthServerSetupTask.java index 9bbcc40547b..89ec6e56e7c 100644 --- a/testsuite/standalone/src/test/java/org/jboss/as/test/integration/security/perimeter/DisableLocalAuthServerSetupTask.java +++ b/testsuite/standalone/src/test/java/org/jboss/as/test/integration/security/perimeter/DisableLocalAuthServerSetupTask.java @@ -62,7 +62,11 @@ public void setup(final ManagementClient managementClient) throws Exception { executeForSuccess(client, compositeOp.build()); // Use the current client to execute the reload, but the native client to ensure the reload is complete - ServerReload.executeReloadAndWaitForCompletion(client, ServerReload.TIMEOUT, false, protocol, host, port); + ServerReload.executeReloadAndWaitForCompletion(client, new ServerReload.Parameters() + .setProtocol(protocol) + .setServerAddress(host) + .setServerPort(port) + ); } @Override diff --git a/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/AbstractStabilityServerSetupTaskTest.java b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/AbstractStabilityServerSetupTaskTest.java new file mode 100644 index 00000000000..d3facfd3cd4 --- /dev/null +++ b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/AbstractStabilityServerSetupTaskTest.java @@ -0,0 +1,55 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.test.standalone.stability; + +import jakarta.inject.Inject; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.operations.common.Util; +import org.jboss.as.test.integration.management.ManagementOperations; +import org.jboss.as.version.Stability; +import org.jboss.dmr.ModelNode; +import org.junit.Assert; +import org.junit.Test; +import org.wildfly.core.testrunner.ManagementClient; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CORE_SERVICE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STABILITY; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SYSTEM_PROPERTY; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE; +import static org.jboss.as.server.controller.descriptions.ServerDescriptionConstants.SERVER_ENVIRONMENT; + +public abstract class AbstractStabilityServerSetupTaskTest { + private final Stability desiredStability; + + @Inject + private ManagementClient managementClient; + + public AbstractStabilityServerSetupTaskTest(Stability desiredStability) { + this.desiredStability = desiredStability; + } + + @Test + public void testStabilityMatchesSetupTask() throws Exception { + ModelNode op = Util.getReadAttributeOperation(PathAddress.pathAddress(CORE_SERVICE, SERVER_ENVIRONMENT), STABILITY); + ModelNode result = ManagementOperations.executeOperation(managementClient.getControllerClient(), op); + Stability stability = Stability.fromString(result.asString()); + Assert.assertEquals(desiredStability, stability); + } + + @Test + public void testSystemPropertyWasSetByDoSetupCalls() throws Exception { + ModelNode read = Util.getReadAttributeOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, AbstractStabilityServerSetupTaskTest.class.getName()), VALUE); + ModelNode result = ManagementOperations.executeOperation(managementClient.getControllerClient(), read); + Assert.assertEquals(this.getClass().getName(), result.asString()); + } + + + protected static void addSystemProperty(ManagementClient client, Class clazz) throws Exception { + ModelNode add = Util.createAddOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, AbstractStabilityServerSetupTaskTest.class.getName())); + add.get(VALUE).set(clazz.getName()); + ManagementOperations.executeOperation(client.getControllerClient(), add); + } +} diff --git a/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityCommunityServerSetupTestCase.java b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityCommunityServerSetupTestCase.java new file mode 100644 index 00000000000..c7339a7c07e --- /dev/null +++ b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityCommunityServerSetupTestCase.java @@ -0,0 +1,33 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.test.standalone.stability; + +import org.jboss.as.version.Stability; +import org.junit.runner.RunWith; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerSetup; +import org.wildfly.core.testrunner.WildFlyRunner; +import org.wildfly.test.stability.StabilityServerSetupSnapshotRestoreTasks; + +@ServerSetup(StabilityCommunityServerSetupTestCase.CommunityStabilitySetupTask.class) +@RunWith(WildFlyRunner.class) +public class StabilityCommunityServerSetupTestCase extends AbstractStabilityServerSetupTaskTest { + public StabilityCommunityServerSetupTestCase() { + super(Stability.COMMUNITY); + } + + + public static class CommunityStabilitySetupTask extends StabilityServerSetupSnapshotRestoreTasks.Community { + @Override + protected void doSetup(ManagementClient managementClient) throws Exception { + // Not really needed since the resulting written xml will be of a higher stability level + // than the server. Still we are doing it for experimental preview, so it doesn't hurt to + // do the same here. + AbstractStabilityServerSetupTaskTest.addSystemProperty(managementClient, StabilityCommunityServerSetupTestCase.class); + } + } + +} diff --git a/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityDefaultServerSetupTestCase.java b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityDefaultServerSetupTestCase.java new file mode 100644 index 00000000000..1fe120b6c79 --- /dev/null +++ b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityDefaultServerSetupTestCase.java @@ -0,0 +1,31 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.test.standalone.stability; + +import org.jboss.as.version.Stability; +import org.junit.runner.RunWith; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerSetup; +import org.wildfly.core.testrunner.WildFlyRunner; +import org.wildfly.test.stability.StabilityServerSetupSnapshotRestoreTasks; + +@ServerSetup(StabilityDefaultServerSetupTestCase.DefaultStabilitySetupTask.class) +@RunWith(WildFlyRunner.class) +public class StabilityDefaultServerSetupTestCase extends AbstractStabilityServerSetupTaskTest { + public StabilityDefaultServerSetupTestCase() { + super(Stability.DEFAULT); + } + + public static class DefaultStabilitySetupTask extends StabilityServerSetupSnapshotRestoreTasks.Default { + @Override + protected void doSetup(ManagementClient managementClient) throws Exception { + // Not really needed since the resulting written xml will be of a higher stability level + // than the server. Still we are doing it for experimental preview, so it doesn't hurt to + // do the same here. + AbstractStabilityServerSetupTaskTest.addSystemProperty(managementClient, StabilityDefaultServerSetupTestCase.class); + } + } +} diff --git a/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityExperimentalServerSetupTestCase.java b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityExperimentalServerSetupTestCase.java new file mode 100644 index 00000000000..f8d6f4fccae --- /dev/null +++ b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityExperimentalServerSetupTestCase.java @@ -0,0 +1,32 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.test.standalone.stability; + +import org.jboss.as.version.Stability; +import org.junit.runner.RunWith; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerSetup; +import org.wildfly.core.testrunner.WildFlyRunner; +import org.wildfly.test.stability.StabilityServerSetupSnapshotRestoreTasks; + +@ServerSetup(StabilityExperimentalServerSetupTestCase.ExperimentalStabilitySetupTask.class) +@RunWith(WildFlyRunner.class) +public class StabilityExperimentalServerSetupTestCase extends AbstractStabilityServerSetupTaskTest { + public StabilityExperimentalServerSetupTestCase() { + super(Stability.EXPERIMENTAL); + } + + + public static class ExperimentalStabilitySetupTask extends StabilityServerSetupSnapshotRestoreTasks.Experimental { + @Override + protected void doSetup(ManagementClient managementClient) throws Exception { + // Write a system property so the model ges stored with a lower stability level. + // This is to make sure we can reload back to the higher level from the snapshot + AbstractStabilityServerSetupTaskTest.addSystemProperty(managementClient, StabilityExperimentalServerSetupTestCase.class); + } + } + +} diff --git a/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityPreviewServerSetupTestCase.java b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityPreviewServerSetupTestCase.java new file mode 100644 index 00000000000..1d56f6a218b --- /dev/null +++ b/testsuite/standalone/src/test/java/org/wildfly/core/test/standalone/stability/StabilityPreviewServerSetupTestCase.java @@ -0,0 +1,32 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.core.test.standalone.stability; + +import org.jboss.as.version.Stability; +import org.junit.runner.RunWith; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerSetup; +import org.wildfly.core.testrunner.WildFlyRunner; +import org.wildfly.test.stability.StabilityServerSetupSnapshotRestoreTasks; + +@ServerSetup(StabilityPreviewServerSetupTestCase.PreviewStabilitySetupTask.class) +@RunWith(WildFlyRunner.class) +public class StabilityPreviewServerSetupTestCase extends AbstractStabilityServerSetupTaskTest { + public StabilityPreviewServerSetupTestCase() { + super(Stability.PREVIEW); + } + + + public static class PreviewStabilitySetupTask extends StabilityServerSetupSnapshotRestoreTasks.Preview { + @Override + protected void doSetup(ManagementClient managementClient) throws Exception { + // Write a system property so the model ges stored with a lower stability level. + // This is to make sure we can reload back to the higher level from the snapshot + AbstractStabilityServerSetupTaskTest.addSystemProperty(managementClient, StabilityPreviewServerSetupTestCase.class); + } + } + +} diff --git a/testsuite/test-runner/src/main/java/org/wildfly/core/testrunner/WildFlyRunner.java b/testsuite/test-runner/src/main/java/org/wildfly/core/testrunner/WildFlyRunner.java index 9c5a5229384..eb358357492 100644 --- a/testsuite/test-runner/src/main/java/org/wildfly/core/testrunner/WildFlyRunner.java +++ b/testsuite/test-runner/src/main/java/org/wildfly/core/testrunner/WildFlyRunner.java @@ -20,6 +20,7 @@ import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.dmr.ModelNode; +import org.junit.AssumptionViolatedException; import org.junit.runner.Result; import org.junit.runner.notification.RunListener; import org.junit.runner.notification.RunNotifier; @@ -64,6 +65,14 @@ public class WildFlyRunner extends BlockJUnit4ClassRunner { private final ParameterDescriptions parameterDescriptions = new ParameterDescriptions(); + // If a ServerSetupTask.setup() method fails, record the error here + private org.junit.internal.AssumptionViolatedException assumptionFailedInServerSetup; + + //Keeps track of the number of setup tasks that have been run, which is needed when tearing them down again + private int runSetupTasks = 0; + + + /** * Creates a BlockJUnit4ClassRunner to run {@code klass} * @@ -154,6 +163,8 @@ protected Statement methodInvoker(final FrameworkMethod method, final Object tes @Override public void run(final RunNotifier notifier) { + assumptionFailedInServerSetup = null; + int setupTasks = 0; notifier.addListener(new RunListener() { @Override public void testRunFinished(Result result) throws Exception { @@ -173,10 +184,15 @@ public void testRunFinished(Result result) throws Exception { Security.insertProviderAt(ELYTRON_PROVIDER, 0); providerInstalled = true; } - if (automaticServerControl) { - runSetupTasks(); + try { + if (automaticServerControl) { + runSetupTasks(); + } + } catch (AssumptionViolatedException e) { + assumptionFailedInServerSetup = e; } super.run(notifier); + if (automaticServerControl) { runTearDownTasks(); } @@ -189,6 +205,9 @@ private void runSetupTasks() { for (ServerSetupTask task : serverSetupTasks) { try { task.setup(controller.getClient()); + runSetupTasks++; + } catch (AssumptionViolatedException e) { + throw e; } catch (Exception e) { throw new RuntimeException(String.format("Could not run setup task '%s'", task), e); } @@ -196,7 +215,7 @@ private void runSetupTasks() { } private void runTearDownTasks() { - List reverseServerSetupTasks = new LinkedList<>(serverSetupTasks); + List reverseServerSetupTasks = new LinkedList<>(serverSetupTasks.subList(0, runSetupTasks)); Collections.reverse(reverseServerSetupTasks); for (ServerSetupTask task : reverseServerSetupTasks) { try { @@ -300,4 +319,25 @@ private static List> getInjectClasses() { return INJECT_CLASSES; } + @Override + protected Statement classBlock(RunNotifier notifier) { + Statement statement = super.classBlock(notifier); + return new WrappedStatement(statement); + } + + private class WrappedStatement extends Statement { + + private final Statement delegate; + public WrappedStatement(Statement delegate) { + this.delegate = delegate; + } + + @Override + public void evaluate() throws Throwable { + if (assumptionFailedInServerSetup != null) { + throw assumptionFailedInServerSetup; + } + delegate.evaluate(); + } + } }