org.wildfly.plugin.tools.DefaultDeploymentManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wildfly-plugin-tools Show documentation
Show all versions of wildfly-plugin-tools Show documentation
A group of tools for interacting/managing with a WildFly container
The newest version!
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.plugin.tools;
import static org.jboss.as.controller.client.helpers.ClientConstants.CHILD_TYPE;
import static org.jboss.as.controller.client.helpers.ClientConstants.DEPLOYMENT;
import static org.jboss.as.controller.client.helpers.ClientConstants.READ_CHILDREN_NAMES_OPERATION;
import static org.jboss.as.controller.client.helpers.ClientConstants.SERVER_GROUP;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.Operation;
import org.jboss.as.controller.client.helpers.Operations;
import org.jboss.as.controller.client.helpers.Operations.CompositeOperationBuilder;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.wildfly.common.Assert;
import org.wildfly.plugin.tools.util.Assertions;
/**
* The default deployment manager.
*
* @author James R. Perkins
*/
@SuppressWarnings("Duplicates")
class DefaultDeploymentManager implements DeploymentManager {
private final ModelControllerClient client;
private final ContainerDescription containerDescription = new LazyContainerDescription();
DefaultDeploymentManager(final ModelControllerClient client) {
this.client = client;
}
@Override
public DeploymentResult deploy(final Deployment deployment) throws IOException {
final DeploymentResult failedResult = validateDeployment(deployment);
if (failedResult != null) {
return failedResult;
}
return execute(DeploymentOperations.createAddDeploymentOperation(deployment));
}
@Override
public DeploymentResult deploy(final Set deployments) throws IOException {
final DeploymentResult failedResult = validateDeployment(deployments);
if (failedResult != null) {
return failedResult;
}
return execute(DeploymentOperations.createAddDeploymentOperation(deployments));
}
@Override
public DeploymentResult forceDeploy(final Deployment deployment) throws IOException {
final DeploymentResult failedResult = validateDeployment(deployment);
if (failedResult != null) {
return failedResult;
}
if (hasDeployment(deployment.getName())) {
// Special handling for domains if the deployment is already in the content repository
if (containerDescription.isDomain()) {
// Retrieve the currently deployment content description
final DeploymentDescription current = getServerGroupDeployment(deployment.getName());
final CompositeOperationBuilder builder = CompositeOperationBuilder.create(true);
// Add a full-replace-deployment as well as add the deployment to any missing server groups
DeploymentOperations.addReplaceOperationSteps(builder, deployment, current, true);
return execute(builder.build());
}
return redeploy(deployment);
}
return deploy(deployment);
}
@Override
public DeploymentResult forceDeploy(final Set deployments) throws IOException {
final DeploymentResult failedResult = validateDeployment(deployments);
if (failedResult != null) {
return failedResult;
}
@SuppressWarnings("TypeMayBeWeakened")
final Set toDeploy = new LinkedHashSet<>();
final Map toRedeploy = new LinkedHashMap<>();
final Set currentDeployments = getDeployments();
for (Deployment deployment : deployments) {
// Find if the current deployment with the same name as the deployment to be deployed, if found it will
// be replaced. If not found it will be deployed
final DeploymentDescription currentDeployment = findDeployment(currentDeployments, deployment);
if (currentDeployment != null) {
toRedeploy.put(deployment, currentDeployment);
} else {
toDeploy.add(deployment);
}
}
final CompositeOperationBuilder builder = CompositeOperationBuilder.create(true);
// Add all the deploy steps
for (Deployment deployment : toDeploy) {
DeploymentOperations.addDeploymentOperationStep(builder, deployment);
}
// Add all the redeploy steps
for (Deployment deployment : toRedeploy.keySet()) {
if (containerDescription.isDomain()) {
// Adds the full-replace-deployment operation for domains as well as adds missing deployments on server
// groups
DeploymentOperations.addReplaceOperationSteps(builder, deployment, toRedeploy.get(deployment), true);
} else {
DeploymentOperations.addReplaceOperationSteps(builder, deployment);
}
}
return execute(builder.build());
}
@Override
public DeploymentResult deployToRuntime(final DeploymentDescription deployment) throws IOException {
return execute(DeploymentOperations.createDeployOperation(Assert.checkNotNullParam("deployment", deployment)));
}
@Override
public DeploymentResult deployToRuntime(final Set deployments) throws IOException {
return execute(DeploymentOperations
.createDeployOperation(Assertions.requiresNotNullOrNotEmptyParameter("deployments", deployments)));
}
@Override
public DeploymentResult redeploy(final Deployment deployment) throws IOException {
final DeploymentResult failedResult = validateDeployment(deployment);
if (failedResult != null) {
return failedResult;
}
return execute(DeploymentOperations.createReplaceOperation(deployment));
}
@Override
public DeploymentResult redeploy(final Set deployments) throws IOException {
final DeploymentResult failedResult = validateDeployment(deployments);
if (failedResult != null) {
return failedResult;
}
return execute(DeploymentOperations.createReplaceOperation(deployments));
}
@Override
public DeploymentResult redeployToRuntime(final DeploymentDescription deployment) throws IOException {
return execute(DeploymentOperations.createRedeployOperation(Assert.checkNotNullParam("deployment", deployment)));
}
@Override
public DeploymentResult redeployToRuntime(final Set deployments) throws IOException {
return execute(DeploymentOperations
.createRedeployOperation(Assertions.requiresNotNullOrNotEmptyParameter("deployments", deployments)));
}
@Override
public DeploymentResult undeploy(final UndeployDescription undeployDescription) throws IOException {
final DeploymentResult failedResult = validateDeployment(undeployDescription);
if (failedResult != null) {
return failedResult;
}
if (undeployDescription.isFailOnMissing()) {
return execute(DeploymentOperations.createUndeployOperation(undeployDescription));
}
final Set currentDeployments = getDeployments();
final DeploymentDescription found = findDeployment(currentDeployments, undeployDescription);
if (currentDeployments.isEmpty() || found == null) {
return DeploymentResult.SUCCESSFUL;
}
return execute(DeploymentOperations.createUndeployOperation(copyIfRequired(undeployDescription, found)));
}
@Override
public DeploymentResult undeploy(final Set undeployDescriptions) throws IOException {
final DeploymentResult failedResult = validateDeployment(undeployDescriptions);
if (failedResult != null) {
return failedResult;
}
final Set currentDeployments = getDeployments();
final Set toRemove = new LinkedHashSet<>(undeployDescriptions.size());
final Set skipped = new LinkedHashSet<>(undeployDescriptions.size());
boolean failOnMissing = false;
for (UndeployDescription undeployDescription : undeployDescriptions) {
if (undeployDescription.isFailOnMissing()) {
failOnMissing = true;
}
if (failOnMissing) {
toRemove.add(undeployDescription);
} else {
final DeploymentDescription found = findDeployment(currentDeployments, undeployDescription);
if (found == null) {
skipped.add(undeployDescription);
} else {
toRemove.add(copyIfRequired(undeployDescription, found));
}
}
}
if (toRemove.isEmpty()) {
if (failOnMissing) {
return new DeploymentResult("No deployments were found matching any of the following deployments: %s",
undeployDescriptions);
}
return DeploymentResult.SUCCESSFUL;
}
// If this is expecting to fail we need to add the skipped ones so execution will fail and the failure message
// will be accurate.
if (failOnMissing) {
toRemove.addAll(skipped);
}
return execute(DeploymentOperations.createUndeployOperation(toRemove));
}
@Override
public Set getDeployments() throws IOException {
final ModelNode readDeployments = Operations.createOperation(READ_CHILDREN_NAMES_OPERATION);
readDeployments.get(CHILD_TYPE).set(DEPLOYMENT);
if (containerDescription.isDomain()) {
// Represents the deployment and each server-group the deployment belongs to
final Map> serverGroupDeployments = new LinkedHashMap<>();
final CompositeOperationBuilder builder = CompositeOperationBuilder.create();
// Get all the deployments in the deployment repository
builder.addStep(readDeployments);
final ModelNode address = Operations.createAddress(SERVER_GROUP, "*", DEPLOYMENT, "*");
// Get all the deployments that are deployed to server groups
builder.addStep(Operations.createReadResourceOperation(address));
final ModelNode result = client.execute(builder.build());
if (Operations.isSuccessfulOutcome(result)) {
final ModelNode results = Operations.readResult(result);
// Load all deployments from the content repository
for (ModelNode r : Operations.readResult(results.get("step-1")).asList()) {
serverGroupDeployments.put(r.asString(), new LinkedHashSet());
}
// Add the server groups to the deployments which belong to server groups
for (ModelNode r : Operations.readResult(results.get("step-2")).asList()) {
final List resultAddress = Operations.getOperationAddress(r).asPropertyList();
String serverGroup = null;
String deployment = null;
for (Property property : resultAddress) {
if (SERVER_GROUP.equals(property.getName())) {
serverGroup = property.getValue().asString();
} else if (DEPLOYMENT.equals(property.getName())) {
deployment = property.getValue().asString();
}
}
// Add the server-group to the map of deployments
final Set serverGroups = serverGroupDeployments.get(deployment);
serverGroups.add(serverGroup);
}
// Convert the server-group mapping to deployment descriptions
final Set deployments = new LinkedHashSet<>();
for (Map.Entry> entry : serverGroupDeployments.entrySet()) {
final String name = entry.getKey();
deployments.add(SimpleDeploymentDescription.of(name, entry.getValue()));
}
return deployments;
}
throw new RuntimeException(
"Failed to get listing of deployments. Reason: " + Operations.getFailureDescription(result).asString());
}
// Handle servers other than managed domains
final Set deployments = new LinkedHashSet<>();
final ModelNode result = client.execute(readDeployments);
if (Operations.isSuccessfulOutcome(result)) {
for (ModelNode deployment : Operations.readResult(result).asList()) {
final String deploymentName = deployment.asString();
deployments.add(SimpleDeploymentDescription.of(deploymentName));
}
return deployments;
}
throw new RuntimeException(
"Failed to get listing of deployments. Reason: " + Operations.getFailureDescription(result).asString());
}
@Override
public Set getDeployments(final String serverGroup) throws IOException {
Assertions.requiresNotNullOrNotEmptyParameter("serverGroup", serverGroup);
if (!containerDescription.isDomain()) {
throw new IllegalStateException("Server is not a managed domain. Running container: " + containerDescription);
}
// Get all the current deployments and filter them to only return deployments located on this server group
final Set deployments = new LinkedHashSet<>();
for (DeploymentDescription deployment : getDeployments()) {
final Set serverGroups = Collections.unmodifiableSet(deployment.getServerGroups());
if (serverGroups.contains(serverGroup)) {
deployments.add(deployment);
}
}
return deployments;
}
@Override
public Set getDeploymentNames() throws IOException {
final ModelNode readDeployments = Operations.createOperation(READ_CHILDREN_NAMES_OPERATION);
readDeployments.get(CHILD_TYPE).set(DEPLOYMENT);
final Set deployments = new LinkedHashSet<>();
final ModelNode result = client.execute(readDeployments);
if (Operations.isSuccessfulOutcome(result)) {
for (ModelNode deployment : Operations.readResult(result).asList()) {
final String deploymentName = deployment.asString();
deployments.add(deploymentName);
}
return deployments;
}
throw new RuntimeException(
"Failed to get listing of deployments. Reason: " + Operations.getFailureDescription(result).asString());
}
@Override
public boolean hasDeployment(final String name) {
return hasDeployment(DeploymentOperations.EMPTY_ADDRESS, Assertions.requiresNotNullOrNotEmptyParameter("name", name));
}
@Override
public boolean hasDeployment(final String name, final String serverGroup) {
final ModelNode address = Operations.createAddress(SERVER_GROUP,
Assertions.requiresNotNullOrNotEmptyParameter("serverGroup", serverGroup));
return hasDeployment(address, Assertions.requiresNotNullOrNotEmptyParameter("name", name));
}
@Override
public boolean isEnabled(final String name) {
return isEnabled(
Operations.createAddress(DEPLOYMENT, Assertions.requiresNotNullOrNotEmptyParameter("name", name)));
}
@Override
public boolean isEnabled(final String name, final String serverGroup) {
return isEnabled(Operations.createAddress(
SERVER_GROUP,
Assertions.requiresNotNullOrNotEmptyParameter("serverGroup", serverGroup),
DEPLOYMENT,
Assertions.requiresNotNullOrNotEmptyParameter("name", name)));
}
private boolean hasDeployment(final ModelNode address, final String name) {
final ModelNode op = Operations.createOperation(READ_CHILDREN_NAMES_OPERATION, address);
op.get(CHILD_TYPE).set(DEPLOYMENT);
final ModelNode listDeploymentsResult;
try {
listDeploymentsResult = client.execute(op);
// Check to make sure there is an outcome
if (Operations.isSuccessfulOutcome(listDeploymentsResult)) {
final List deployments = Operations.readResult(listDeploymentsResult).asList();
for (ModelNode deployment : deployments) {
if (name.equals(deployment.asString())) {
return true;
}
}
} else {
throw new IllegalStateException(Operations.getFailureDescription(listDeploymentsResult).asString());
}
} catch (IOException e) {
throw new IllegalStateException(String.format("Could not execute operation '%s'", op), e);
}
return false;
}
private boolean isEnabled(final ModelNode address) {
final ModelNode op = Operations.createReadAttributeOperation(address, DeploymentOperations.ENABLED);
try {
final ModelNode result = client.execute(op);
// Check to make sure there is an outcome
if (Operations.isSuccessfulOutcome(result)) {
return Operations.readResult(result).asBoolean();
} else {
throw new IllegalStateException(Operations.getFailureDescription(result).asString());
}
} catch (IOException e) {
throw new IllegalStateException(String.format("Could not execute operation '%s'", op), e);
}
}
private DeploymentResult execute(final Operation op) throws IOException {
final ModelNode result = client.execute(op);
return new DeploymentResult(result);
}
private DeploymentDescription getServerGroupDeployment(final String name) throws IOException {
final Set serverGroups = new LinkedHashSet<>();
final ModelNode address = Operations.createAddress(SERVER_GROUP, "*", DEPLOYMENT, name);
final ModelNode result = client.execute(Operations.createReadResourceOperation(address));
if (Operations.isSuccessfulOutcome(result)) {
// Load the server groups
for (ModelNode r : Operations.readResult(result).asList()) {
final List resultAddress = Operations.getOperationAddress(r).asPropertyList();
String foundServerGroup = null;
for (Property property : resultAddress) {
if (SERVER_GROUP.equals(property.getName())) {
foundServerGroup = property.getValue().asString();
}
}
// Add the server-group to the map of deployments
serverGroups.add(foundServerGroup);
}
return SimpleDeploymentDescription.of(name, serverGroups);
}
throw new RuntimeException(
"Failed to get listing of deployments. Reason: " + Operations.getFailureDescription(result).asString());
}
private DeploymentResult validateDeployment(final DeploymentDescription deployment) {
Assert.checkNotNullParam("deployment", deployment);
final Set serverGroups = deployment.getServerGroups();
if (containerDescription.isDomain() && serverGroups.isEmpty()) {
return new DeploymentResult("No server groups were defined for the deployment operation. Deployment: %s",
deployment);
} else if (!containerDescription.isDomain() && !serverGroups.isEmpty()) {
return new DeploymentResult("Server is not a managed domain, but server groups were defined. Deployment: %s",
deployment);
}
return null;
}
private DeploymentResult validateDeployment(final Set extends DeploymentDescription> deployments) {
Assertions.requiresNotNullOrNotEmptyParameter("deployments", deployments);
final Collection missingServerGroups = new LinkedHashSet<>();
final Collection standaloneWithServerGroups = new LinkedHashSet<>();
boolean error = false;
for (DeploymentDescription deployment : deployments) {
final Set serverGroups = deployment.getServerGroups();
if (containerDescription.isDomain() && serverGroups.isEmpty()) {
error = true;
missingServerGroups.add(deployment);
} else if (!containerDescription.isDomain() && !serverGroups.isEmpty()) {
error = true;
standaloneWithServerGroups.add(deployment);
}
}
if (error) {
final StringBuilder message = new StringBuilder();
if (!missingServerGroups.isEmpty()) {
message.append("No server groups were defined on the following deployments: ")
.append(missingServerGroups);
}
if (!standaloneWithServerGroups.isEmpty()) {
message.append("Server is not a managed domain but the following deployments had server groups defined: ")
.append(standaloneWithServerGroups);
}
return new DeploymentResult(message);
}
return null;
}
private static DeploymentDescription findDeployment(final Iterable deployments,
final DeploymentDescription deployment) {
for (DeploymentDescription deploymentDescription : deployments) {
if (deploymentDescription.getName().equals(deployment.getName())) {
return deploymentDescription;
}
}
return null;
}
private static UndeployDescription copyIfRequired(final UndeployDescription undeployDescription,
final DeploymentDescription found) {
final Collection unmatched = new LinkedHashSet<>(undeployDescription.getServerGroups());
unmatched.removeAll(found.getServerGroups());
if (unmatched.isEmpty()) {
return undeployDescription;
}
final Collection toRemove = new LinkedHashSet<>(undeployDescription.getServerGroups());
toRemove.removeAll(unmatched);
// The parameter has more server-groups than the deployment found, create a new UndeployDescription description
// using only the server-groups the deployment exists on
return UndeployDescription.of(undeployDescription.getName())
.addServerGroups(toRemove)
.setFailOnMissing(undeployDescription.isFailOnMissing())
.setRemoveContent(undeployDescription.isRemoveContent());
}
private class LazyContainerDescription implements ContainerDescription {
private volatile ContainerDescription containerDescription;
@Override
public String getProductName() {
return get().getProductName();
}
@Override
public String getProductVersion() {
return get().getProductVersion();
}
@Override
public String getReleaseVersion() {
return get().getReleaseVersion();
}
@Override
public String getLaunchType() {
return get().getLaunchType();
}
@Override
public boolean isDomain() {
return get().isDomain();
}
@Override
public String toString() {
return get().toString();
}
private ContainerDescription get() {
if (containerDescription == null) {
synchronized (this) {
if (containerDescription == null) {
try {
containerDescription = ContainerDescription.lookup(client);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
}
return containerDescription;
}
}
}