Skip to content

Commit

Permalink
Merge pull request #3131 from ehsavoie/WFCORE-3633
Browse files Browse the repository at this point in the history
[WFCORE-3633]: Read only mode is not properly supported for domain.
  • Loading branch information
bstansberry committed Feb 23, 2018
2 parents 9e6ce51 + 74ffc6a commit 67a37af
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ public static HostControllerEnvironmentWrapper determineEnvironment(String[] arg
domainConfigInteractionPolicy = ConfigurationFile.InteractionPolicy.DISCARD;
} else if (arg.startsWith(CommandLineConstants.READ_ONLY_DOMAIN_CONFIG)) {
initialDomainConfig = parseValue(arg, CommandLineConstants.READ_ONLY_DOMAIN_CONFIG);
domainConfigInteractionPolicy = ConfigurationFile.InteractionPolicy.READ_ONLY;
if (initialDomainConfig == null) {
return new HostControllerEnvironmentWrapper(HostControllerEnvironmentWrapper.HostControllerEnvironmentStatus.ERROR);
}
Expand All @@ -362,6 +363,7 @@ public static HostControllerEnvironmentWrapper determineEnvironment(String[] arg
hostConfig = val;
} else if (arg.startsWith(CommandLineConstants.READ_ONLY_HOST_CONFIG)) {
initialHostConfig = parseValue(arg, CommandLineConstants.READ_ONLY_HOST_CONFIG);
hostConfigInteractionPolicy = ConfigurationFile.InteractionPolicy.READ_ONLY;
if (initialHostConfig == null) {
return new HostControllerEnvironmentWrapper(HostControllerEnvironmentWrapper.HostControllerEnvironmentStatus.ERROR);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright 2018 JBoss by Red Hat.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.as.test.integration.domain;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.client.helpers.Operations;
import org.jboss.as.controller.client.helpers.domain.DomainClient;
import org.jboss.as.controller.client.helpers.domain.impl.DomainClientImpl;
import org.jboss.as.test.integration.domain.management.util.DomainLifecycleUtil;
import org.jboss.as.test.integration.domain.management.util.DomainTestSupport;
import org.jboss.as.test.integration.domain.management.util.WildFlyManagedConfiguration;
import org.jboss.as.test.shared.TimeoutUtil;
import org.jboss.dmr.ModelNode;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

/**
*
* @author Emmanuel Hugonnet (c) 2017 Red Hat, inc.
*/
public class ReadOnlyModeTestCase {

private static DomainTestSupport.Configuration domainConfig;
private static DomainTestSupport domainManager;
private static DomainLifecycleUtil domainMasterLifecycleUtil;
private static DomainLifecycleUtil domainSlaveLifecycleUtil;
private static final long TIMEOUT_S = TimeoutUtil.adjust(30);
private static final int TIMEOUT_SLEEP_MILLIS = 50;

@BeforeClass
public static void setupDomain() throws Exception {
domainConfig = DomainTestSupport.Configuration.create(ReadOnlyModeTestCase.class.getSimpleName(),
"domain-configs/domain-standard.xml", "host-configs/host-master.xml", "host-configs/host-slave.xml");
domainConfig.getMasterConfiguration().setReadOnlyHost(true);
domainConfig.getMasterConfiguration().setReadOnlyDomain(true);
domainConfig.getSlaveConfiguration().setReadOnlyDomain(true);
domainConfig.getSlaveConfiguration().setReadOnlyHost(false);
domainManager = DomainTestSupport.create(domainConfig);
domainManager.start();
domainMasterLifecycleUtil = domainManager.getDomainMasterLifecycleUtil();
domainSlaveLifecycleUtil = domainManager.getDomainSlaveLifecycleUtil();
}

@AfterClass
public static void tearDownDomain() throws Exception {
domainManager.stop();
domainManager = null;
domainMasterLifecycleUtil = null;
domainSlaveLifecycleUtil = null;
}

@Test
public void testConfigurationNotUpdated() throws Exception {
ModelNode domainAddress = PathAddress.pathAddress("system-property", "domain-read-only").toModelNode();
ModelNode masterAddress = PathAddress.pathAddress("host", "master").append("system-property", "master-read-only").toModelNode();
ModelNode slaveAddress = PathAddress.pathAddress("host", "slave").append("system-property", "slave-read-only").toModelNode();
try (final DomainClient masterClient = domainMasterLifecycleUtil.getDomainClient()) {
ModelNode op = Operations.createAddOperation(domainAddress);
op.get("value").set(true);
Operations.isSuccessfulOutcome(masterClient.execute(op));
op = Operations.createAddOperation(masterAddress);
op.get("value").set(true);
Operations.isSuccessfulOutcome(masterClient.execute(op));
op = Operations.createAddOperation(slaveAddress);
op.get("value").set(true);
Operations.isSuccessfulOutcome(masterClient.execute(op));
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(domainAddress, "value"))).asBoolean());
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(masterAddress, "value"))).asBoolean());
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(slaveAddress, "value"))).asBoolean());

// reload master HC
op = new ModelNode();
op.get(OP_ADDR).add(HOST, "master");
op.get(OP).set("reload");
domainMasterLifecycleUtil.executeAwaitConnectionClosed(op);
// Try to reconnect to the hc
domainMasterLifecycleUtil.connect();
domainMasterLifecycleUtil.awaitHostController(System.currentTimeMillis());

Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(domainAddress, "value"))).asBoolean());
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(masterAddress, "value"))).asBoolean());
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(slaveAddress, "value"))).asBoolean());

// reload slave HC
op = new ModelNode();
op.get(OP_ADDR).add(HOST, "slave");
op.get(OP).set("reload");
domainSlaveLifecycleUtil.executeAwaitConnectionClosed(op);
// Try to reconnect to the hc
domainSlaveLifecycleUtil.connect();
domainSlaveLifecycleUtil.awaitHostController(System.currentTimeMillis());

Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(domainAddress, "value"))).asBoolean());
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(masterAddress, "value"))).asBoolean());
Assert.assertTrue(Operations.readResult(masterClient.execute(Operations.createReadAttributeOperation(slaveAddress, "value"))).asBoolean());
}
domainManager.stop();
domainConfig.getMasterConfiguration().setRewriteConfigFiles(false);
domainConfig.getSlaveConfiguration().setRewriteConfigFiles(false);
domainManager.getDomainMasterLifecycleUtil().startAsync();
domainManager.getDomainSlaveLifecycleUtil().startAsync();
try (final DomainClient clientMaster = getDomainClient(domainConfig.getMasterConfiguration())) {
waitForHostControllerBeingStarted(TIMEOUT_S, clientMaster);
Assert.assertTrue(Operations.getFailureDescription(clientMaster.execute(Operations.createReadAttributeOperation(domainAddress, "value"))).asString().contains("WFLYCTL0216"));
Assert.assertTrue(Operations.getFailureDescription(clientMaster.execute(Operations.createReadAttributeOperation(masterAddress, "value"))).asString().contains("WFLYCTL0216"));
Assert.assertTrue(Operations.readResult(clientMaster.execute(Operations.createReadAttributeOperation(slaveAddress, "value"))).asBoolean());
}
}


private void waitForHostControllerBeingStarted(long timeoutSeconds, DomainClient client) {
runWithTimeout(timeoutSeconds, () -> client.getServerStatuses());
}

private void runWithTimeout(long timeoutSeconds, Runnable voidFunctionInterface) {
runWithTimeout(timeoutSeconds, () -> {
voidFunctionInterface.run();
return null;
});
}

private <T> T runWithTimeout(long timeoutSeconds, Supplier<T> function) {
final long timeoutTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(timeoutSeconds);
while(true) {
try {
return function.get();
} catch (Throwable t) {
if(timeoutTime < System.currentTimeMillis()) {
throw new IllegalStateException("Function '" + function
+ "' failed to process in " + timeoutSeconds + " s, caused: " + t.getMessage() , t);
}
try {
Thread.sleep(TIMEOUT_SLEEP_MILLIS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}

private DomainClient getDomainClient(WildFlyManagedConfiguration config) throws UnknownHostException {
final InetAddress address = InetAddress.getByName(config.getHostControllerManagementAddress());
final int port = config.getHostControllerManagementPort();
final String protocol = config.getHostControllerManagementProtocol();
return new DomainClientImpl(protocol, address, port);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2018 JBoss by Red Hat.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.as.test.manualmode.management;


import javax.inject.Inject;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.helpers.Operations;
import org.jboss.as.test.integration.security.common.CoreUtils;
import org.jboss.dmr.ModelNode;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.core.testrunner.ServerControl;
import org.wildfly.core.testrunner.ServerController;
import org.wildfly.core.testrunner.WildflyTestRunner;

/**
*
* @author Emmanuel Hugonnet (c) 2017 Red Hat, inc.
*/
@RunWith(WildflyTestRunner.class)
@ServerControl(manual = true)
public class ReadOnlyModeTestCase {

@Inject
private ServerController container;

@Before
public void startContainer() throws Exception {
// Start the server
container.startReadOnly();
}

@Test
public void testConfigurationNotUpdated() throws Exception {
ModelNode address = PathAddress.pathAddress("system-property", "read-only").toModelNode();
try (ModelControllerClient client = container.getClient().getControllerClient()) {
ModelNode op = Operations.createAddOperation(address);
op.get("value").set(true);
CoreUtils.applyUpdate(op, client);
Assert.assertTrue(Operations.readResult(client.execute(Operations.createReadAttributeOperation(address, "value"))).asBoolean());
container.reload();
Assert.assertTrue(Operations.readResult(client.execute(Operations.createReadAttributeOperation(address, "value"))).asBoolean());
}
container.stop();
container.startReadOnly();
try (ModelControllerClient client = container.getClient().getControllerClient()) {
Assert.assertTrue(Operations.getFailureDescription(client.execute(Operations.createReadAttributeOperation(address, "value"))).asString().contains("WFLYCTL0216"));
}
}

@After
public void stopContainer() throws Exception {
// Stop the container
container.stop();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ public class Server {
private volatile Process process;
private final ManagementClient client = new ManagementClient(new DelegatingModelControllerClient(ServerClientProvider.INSTANCE), managementAddress, managementPort, managementProtocol);
private final URI authConfigUri;
private final boolean readOnly;

public Server() {
this(null);
this(null, false);
}

/**
Expand All @@ -86,9 +87,23 @@ public Server() {
* @param authConfigUri the path to the {@code wildfly-config.xml} to use or {@code null}
*/
public Server(final URI authConfigUri) {
this.authConfigUri = authConfigUri;
this(authConfigUri, false);
}

/**
* Creates a new server.
* <p>
* If the {@code authConfigUri} is defined the path will be used to authenticate the
* {@link ModelControllerClient}.
* </p>
*
* @param authConfigUri the path to the {@code wildfly-config.xml} to use or {@code null}
* @param readOnly {@code true} to start the server in read-only mode
*/
public Server(final URI authConfigUri, boolean readOnly) {
this.authConfigUri = authConfigUri;
this.readOnly = readOnly;
}

private static boolean processHasDied(final Process process) {
try {
Expand Down Expand Up @@ -143,9 +158,14 @@ protected void start(PrintStream out) {
commandBuilder.setStartSuspended();
}

if(readOnly) {
commandBuilder.setServerReadOnlyConfiguration(serverConfig);
} else {
commandBuilder.setServerConfiguration(serverConfig);
}

//we are testing, of course we want assertions and set-up some other defaults
commandBuilder.addJavaOption("-ea")
.setServerConfiguration(serverConfig)
.setBindAddressHint("management", managementAddress);

if (jbossArgs != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ public void start(final URI authConfigUri) {
* @param authConfigUri the path to the {@code wildfly-config.xml} or {@code null}
*/
public void start(final String serverConfig, final URI authConfigUri) {
start(serverConfig, authConfigUri, Server.StartMode.NORMAL, System.out);
start(serverConfig, authConfigUri, Server.StartMode.NORMAL, System.out, false);
}

public void start(final String serverConfig, Server.StartMode startMode) {
start(serverConfig, startMode, System.out);
}

public void start(final String serverConfig, Server.StartMode startMode, PrintStream out) {
start(serverConfig, null, startMode, out);
start(serverConfig, null, startMode, out, false);
}

/**
Expand All @@ -68,10 +68,11 @@ public void start(final String serverConfig, Server.StartMode startMode, PrintSt
* @param authConfigUri the path to the {@code wildfly-config.xml} or {@code null}
* @param startMode the mode to start the server in
* @param out the print stream used to consume the {@code stdout} and {@code stderr} streams
* @param readOnly
*/
public void start(final String serverConfig, final URI authConfigUri, Server.StartMode startMode, PrintStream out) {
public void start(final String serverConfig, final URI authConfigUri, Server.StartMode startMode, PrintStream out, boolean readOnly) {
if (started.compareAndSet(false, true)) {
server = new Server(authConfigUri);
server = new Server(authConfigUri, readOnly);
if (serverConfig != null) {
server.setServerConfig(serverConfig);
}
Expand Down Expand Up @@ -99,6 +100,10 @@ public void startInAdminMode(){
start(null, Server.StartMode.ADMIN_ONLY);
}

public void startReadOnly(){
start(null, null, Server.StartMode.NORMAL, System.out, true);
}

public void startSuspended() {
start(null, Server.StartMode.SUSPEND);
}
Expand Down

0 comments on commit 67a37af

Please sign in to comment.