Skip to content

Commit

Permalink
add Administration.shutdownGracefully
Browse files Browse the repository at this point in the history
  • Loading branch information
Ladicek committed Jul 12, 2016
1 parent 72059ab commit c5b9871
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ private Constants() {} // avoid instantiation
public static final String START = "start";
public static final String STEPS = "steps";
public static final String STOP = "stop";
public static final String TIMEOUT = "timeout";
public static final String WHOAMI = "whoami";

public static final List<String> RESULT_CODES_FOR_UNKNOWN_OR_NOT_FOUND = Collections.unmodifiableList(Arrays.asList(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.wildfly.extras.creaper.core.online.operations.admin;

import org.wildfly.extras.creaper.core.ServerVersion;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;

import java.io.IOException;
Expand All @@ -24,13 +25,15 @@
public class Administration {
static final int DEFAULT_TIMEOUT = 60; // seconds

private final OnlineManagementClient client;
private final AdministrationOperations ops;

public Administration(OnlineManagementClient client) {
this(client, DEFAULT_TIMEOUT);
}

public Administration(OnlineManagementClient client, int timeoutInSeconds) {
this.client = client;
if (client.options().isDomain) {
this.ops = new DomainAdministrationOperations(client, timeoutInSeconds);
} else {
Expand Down Expand Up @@ -97,7 +100,21 @@ public final boolean restartIfRequired() throws IOException, InterruptedExceptio

/** Shuts down the server. In domain, shuts down the entire host. */
public final void shutdown() throws IOException {
ops.shutdown();
ops.shutdown(0);
}

/**
* Shuts down the server gracefully. That is, the server will wait up to {@code timeoutInSeconds} for all active
* requests to finish. In domain, all servers on the host are shut down gracefully and then the host itself
* is shut down (there's no such thing as graceful shutdown of a host controller).
*
* @param timeoutInSeconds if {@code == 0}, then the server will shutdown immediately without waiting
* for the active requests to finish; if {@code <= 0}, then the server will wait indefinitely for the active
* requests to finish
*/
public final void shutdownGracefully(int timeoutInSeconds) throws IOException {
client.version().assertAtLeast(ServerVersion.VERSION_3_0_0, "Graceful shutdown is only supported since WildFly 9");
ops.shutdown(timeoutInSeconds);
}

// ---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface AdministrationOperations {

boolean restartIfRequired() throws IOException, InterruptedException, TimeoutException;

void shutdown() throws IOException;
void shutdown(int timeoutInSeconds) throws IOException;

void waitUntilRunning() throws InterruptedException, TimeoutException, IOException;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.wildfly.extras.creaper.core.online.operations.admin;

import org.wildfly.extras.creaper.core.ServerVersion;
import org.wildfly.extras.creaper.core.online.Constants;
import org.wildfly.extras.creaper.core.online.ModelNodeResult;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
Expand Down Expand Up @@ -197,7 +198,7 @@ void restartServers(String host, List<String> servers) throws IOException, Inter

/** Shuts down given {@code host}. This is a variant of {@link Administration#shutdown()}. */
public void shutdown(String host) throws IOException, InterruptedException, TimeoutException {
domainOps.shutdown(host);
domainOps.shutdown(host, 0);
}

/** @see #shutdownAllServers(String) */
Expand Down Expand Up @@ -231,6 +232,69 @@ void shutdownServers(String host, List<String> servers) throws IOException, Inte
ops.batch(batch);
}

/**
* Shuts down given {@code host} gracefully. This is a variant of {@link Administration#shutdownGracefully(int)}.
*
* @param timeoutInSeconds if {@code == 0}, then the server will shutdown immediately without waiting
* for the active requests to finish; if {@code <= 0}, then the server will wait indefinitely for the active
* requests to finish
*/
public void shutdownGracefully(String host, int timeoutInSeconds) throws IOException, InterruptedException,
TimeoutException {
client.version().assertAtLeast(ServerVersion.VERSION_3_0_0, "Graceful shutdown is only supported since WildFly 9");
domainOps.shutdown(host, timeoutInSeconds);
}

/** @see #shutdownAllServers(String) */
public void shutdownAllServersGracefully(int timeoutInSeconds) throws InterruptedException, IOException,
TimeoutException {
shutdownAllServersGracefully(client.options().defaultHost, timeoutInSeconds);
}

/**
* Shuts down all the servers on given {@code host} gracefully. As opposed to
* {@link Administration#shutdownGracefully(int)}, this doesn't shut down the entire host, just the servers.
*
* @param timeoutInSeconds if {@code == 0}, then the server will shutdown immediately without waiting
* for the active requests to finish; if {@code <= 0}, then the server will wait indefinitely for the active
* requests to finish
*/
public void shutdownAllServersGracefully(String host, int timeoutInSeconds) throws InterruptedException,
TimeoutException, IOException {
shutdownServersGracefully(host, allRunningServers(host), timeoutInSeconds);
}

/** @see #shutdownServer(String, String) */
public void shutdownServerGracefully(String server, int timeoutInSeconds) throws InterruptedException,
TimeoutException, IOException {
shutdownServerGracefully(client.options().defaultHost, server, timeoutInSeconds);
}

/**
* Shuts down given {@code server} on given {@code host} gracefully.
*
* @param timeoutInSeconds if {@code == 0}, then the server will shutdown immediately without waiting
* for the active requests to finish; if {@code <= 0}, then the server will wait indefinitely for the active
* requests to finish
*/
public void shutdownServerGracefully(String host, String server, int timeoutInSeconds)
throws InterruptedException, TimeoutException, IOException {

shutdownServersGracefully(host, Collections.singletonList(server), timeoutInSeconds);
}

void shutdownServersGracefully(String host, List<String> servers, int timeoutInSeconds) throws IOException,
InterruptedException, TimeoutException {
client.version().assertAtLeast(ServerVersion.VERSION_3_0_0, "Graceful shutdown is only supported since WildFly 9");

Batch batch = new Batch();
for (String server : servers) {
batch.invoke(Constants.STOP, Address.host(host).and(Constants.SERVER_CONFIG, server),
Values.of(Constants.TIMEOUT, timeoutInSeconds));
}
ops.batch(batch);
}

// ---

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.wildfly.extras.creaper.core.online.operations.Address;
import org.wildfly.extras.creaper.core.online.operations.Batch;
import org.wildfly.extras.creaper.core.online.operations.Operations;
import org.wildfly.extras.creaper.core.online.operations.Values;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -63,12 +64,23 @@ public boolean restartIfRequired() throws IOException, InterruptedException, Tim
}

@Override
public void shutdown() throws IOException {
shutdown(client.options().defaultHost);
public void shutdown(int timeoutInSeconds) throws IOException {
shutdown(client.options().defaultHost, timeoutInSeconds);
}

void shutdown(String host) throws IOException {
ops.invoke(Constants.SHUTDOWN, Address.host(host));
void shutdown(String host, int timeoutInSeconds) throws IOException {
if (timeoutInSeconds == 0) {
// older versions don't understand the "timeout" parameter
ops.invoke(Constants.SHUTDOWN, Address.host(host));
} else {
Batch batch = new Batch();
for (String server : allRunningServers(host)) {
batch.invoke(Constants.STOP, Address.host(host).and(Constants.SERVER_CONFIG, server),
Values.of(Constants.TIMEOUT, timeoutInSeconds));
}
batch.invoke(Constants.SHUTDOWN, Address.host(host));
ops.batch(batch);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
import org.wildfly.extras.creaper.core.online.operations.Address;
import org.wildfly.extras.creaper.core.online.operations.Operations;
import org.wildfly.extras.creaper.core.online.operations.Values;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -55,8 +56,13 @@ public boolean restartIfRequired() throws IOException, InterruptedException, Tim
}

@Override
public void shutdown() throws IOException {
ops.invoke(Constants.SHUTDOWN, Address.root());
public void shutdown(int timeoutInSeconds) throws IOException {
if (timeoutInSeconds == 0) {
// older versions don't understand the "timeout" parameter
ops.invoke(Constants.SHUTDOWN, Address.root());
} else {
ops.invoke(Constants.SHUTDOWN, Address.root(), Values.of(Constants.TIMEOUT, timeoutInSeconds));
}
}

@Override
Expand Down
5 changes: 5 additions & 0 deletions testsuite/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
<artifactId>bcprov-jdk15on</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap</groupId>
<artifactId>shrinkwrap-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.wildfly.extras.creaper.arquillian;

import org.jboss.arquillian.container.spi.ServerKillProcessor;
import org.jboss.arquillian.core.spi.LoadableExtension;

public final class Extension implements LoadableExtension {
@Override
public void register(ExtensionBuilder builder) {
builder.service(ServerKillProcessor.class, FakeServerKillProcessor.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.wildfly.extras.creaper.arquillian;

import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ServerKillProcessor;

final class FakeServerKillProcessor implements ServerKillProcessor {
@Override
public void kill(Container container) throws Exception {
// does nothing, this is only to let Arquillian know that the server is gone
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.wildfly.extras.creaper.arquillian.Extension
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import static org.junit.Assert.assertTrue;

@RunWith(Arquillian.class)
public class AdminTest {
public class ReloadIfRequiredTest {
private OnlineManagementClient client;
private Operations ops;
private Administration admin;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.wildfly.extras.creaper.core.online.operations.admin;

import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.junit.After;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.wildfly.extras.creaper.core.ManagementClient;
import org.wildfly.extras.creaper.core.ServerVersion;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
import org.wildfly.extras.creaper.core.online.OnlineOptions;
import org.wildfly.extras.creaper.test.ManualTests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@Category(ManualTests.class)
@RunWith(Arquillian.class)
public class ShutdownTest {
private OnlineManagementClient client = ManagementClient.onlineLazy(
OnlineOptions.standalone().localDefault().build());
private Administration admin = new Administration(client);

@ArquillianResource
private ContainerController controller;

@Test
@InSequence(1)
public void startServer() {
controller.start(ManualTests.ARQUILLIAN_CONTAINER);
}

@Test
@InSequence(2)
public void shutdown() throws Exception {
assertTrue(controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER));

admin.shutdown();
serverShutdown();

assertFalse(controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER));
}

@Test
@InSequence(3)
public void startServerAgain() throws Exception {
controller.start(ManualTests.ARQUILLIAN_CONTAINER);
client.reconnect(10);
}

@Test
@InSequence(4)
public void shutdownGracefully() throws Exception {
if (client.version().lessThan(ServerVersion.VERSION_3_0_0)) {
// graceful shutdown not supported
return;
}

assertTrue(controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER));

admin.shutdownGracefully(5);
serverShutdown();

assertFalse(controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER));

}

@Test
@InSequence(5)
public void startServerYetAgain() throws Exception {
startServerAgain();
}

@Test
@InSequence(6)
public void shutdownGracefullyWithZeroTimeout() throws Exception {
if (client.version().lessThan(ServerVersion.VERSION_3_0_0)) {
// graceful shutdown not supported
return;
}

assertTrue(controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER));

admin.shutdownGracefully(0);
serverShutdown();

assertFalse(controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER));
}

@Test
@InSequence(7)
public void stopServer() throws Exception {
if (controller.isStarted(ManualTests.ARQUILLIAN_CONTAINER)) {
controller.stop(ManualTests.ARQUILLIAN_CONTAINER);
}
}

@After
public void tearDown() throws Exception {
client.close();
}

private void serverShutdown() throws Exception {
// server shutdown takes a couple of millis, we have to wait for it
// TODO how could Creaper wait for the server to shut down? polling the mgmt port?
Thread.sleep(100);

// this only lets Arquillian know that the server is gone (see FakeServerKillProcessor)
controller.kill(ManualTests.ARQUILLIAN_CONTAINER);
}
}

0 comments on commit c5b9871

Please sign in to comment.