/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.extension.undertow.filters;
import io.undertow.server.handlers.proxy.mod_cluster.ModClusterStatus;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationDefinition;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PrimitiveListAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleOperationDefinition;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.client.helpers.MeasurementUnit;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.wildfly.extension.undertow.Constants;
import org.wildfly.extension.undertow.UndertowExtension;
import org.wildfly.extension.undertow.logging.UndertowLogger;
/**
* Runtime representation of a mod_cluster node
*
* @author Stuart Douglas
*/
public class ModClusterNodeDefinition extends SimpleResourceDefinition {
public static ModClusterNodeDefinition INSTANCE = new ModClusterNodeDefinition();
public static final AttributeDefinition LOAD = new SimpleAttributeDefinitionBuilder(Constants.LOAD, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition STATUS = new SimpleAttributeDefinitionBuilder(Constants.STATUS, ModelType.STRING)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition LOAD_BALANCING_GROUP = new SimpleAttributeDefinitionBuilder(Constants.LOAD_BALANCING_GROUP, ModelType.STRING)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition CACHE_CONNECTIONS = new SimpleAttributeDefinitionBuilder(Constants.CACHE_CONNECTIONS, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition MAX_CONNECTIONS = new SimpleAttributeDefinitionBuilder(Constants.MAX_CONNECTIONS, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition OPEN_CONNECTIONS = new SimpleAttributeDefinitionBuilder(Constants.OPEN_CONNECTIONS, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition PING = new SimpleAttributeDefinitionBuilder(Constants.PING, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition READ = new SimpleAttributeDefinitionBuilder(Constants.READ, ModelType.LONG)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition REQUEST_QUEUE_SIZE = new SimpleAttributeDefinitionBuilder(Constants.REQUEST_QUEUE_SIZE, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition TIMEOUT = new SimpleAttributeDefinitionBuilder(Constants.TIMEOUT, ModelType.INT)
.setRequired(false)
.setMeasurementUnit(MeasurementUnit.SECONDS)
.setStorageRuntime()
.build();
public static final AttributeDefinition WRITTEN = new SimpleAttributeDefinitionBuilder(Constants.WRITTEN, ModelType.LONG)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition TTL = new SimpleAttributeDefinitionBuilder(Constants.TTL, ModelType.LONG)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition FLUSH_PACKETS = new SimpleAttributeDefinitionBuilder(Constants.FLUSH_PACKETS, ModelType.BOOLEAN)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition QUEUE_NEW_REQUESTS = new SimpleAttributeDefinitionBuilder(Constants.QUEUE_NEW_REQUESTS, ModelType.BOOLEAN)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition URI = new SimpleAttributeDefinitionBuilder(Constants.URI, ModelType.STRING)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition ALIASES = new PrimitiveListAttributeDefinition.Builder(Constants.ALIASES, ModelType.STRING)
.setRequired(false)
.setStorageRuntime()
.build();
public static final AttributeDefinition ELECTED = new SimpleAttributeDefinitionBuilder(Constants.ELECTED, ModelType.INT)
.setRequired(false)
.setStorageRuntime()
.build();
public final OperationDefinition ENABLE = new SimpleOperationDefinition(Constants.ENABLE, getResourceDescriptionResolver());
public final OperationDefinition DISABLE = new SimpleOperationDefinition(Constants.DISABLE, getResourceDescriptionResolver());
public final OperationDefinition STOP = new SimpleOperationDefinition(Constants.STOP, getResourceDescriptionResolver());
ModClusterNodeDefinition() {
super(UndertowExtension.NODE, UndertowExtension.getResolver("handler", "mod-cluster", "balancer", "node"), null, null, true);
}
@Override
public void registerChildren(ManagementResourceRegistration resourceRegistration) {
resourceRegistration.registerSubModel(ModClusterContextDefinition.INSTANCE);
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
resourceRegistration.registerOperationHandler(ENABLE, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
for (ModClusterStatus.Context n : ctx.getContexts()) {
n.enable();
}
}
});
resourceRegistration.registerOperationHandler(DISABLE, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
for (ModClusterStatus.Context n : ctx.getContexts()) {
n.disable();
}
}
});
resourceRegistration.registerOperationHandler(STOP, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
for (ModClusterStatus.Context n : ctx.getContexts()) {
n.stop();
}
}
});
}
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
resourceRegistration.registerReadOnlyAttribute(LOAD, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getLoad()));
}
});
resourceRegistration.registerReadOnlyAttribute(STATUS, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getStatus().name()));
}
});
resourceRegistration.registerReadOnlyAttribute(LOAD_BALANCING_GROUP, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
final String domain = ctx.getDomain();
if (domain == null) {
context.getResult().set(new ModelNode());
} else {
context.getResult().set(new ModelNode(domain));
}
}
});
resourceRegistration.registerReadOnlyAttribute(CACHE_CONNECTIONS, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getCacheConnections()));
}
});
resourceRegistration.registerReadOnlyAttribute(MAX_CONNECTIONS, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getMaxConnections()));
}
});
resourceRegistration.registerReadOnlyAttribute(OPEN_CONNECTIONS, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getOpenConnections()));
}
});
resourceRegistration.registerReadOnlyAttribute(PING, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getPing()));
}
});
resourceRegistration.registerReadOnlyAttribute(READ, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getRead()));
}
});
resourceRegistration.registerReadOnlyAttribute(REQUEST_QUEUE_SIZE, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getRequestQueueSize()));
}
});
resourceRegistration.registerReadOnlyAttribute(TIMEOUT, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getTimeout()));
}
});
resourceRegistration.registerReadOnlyAttribute(WRITTEN, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getTransferred()));
}
});
resourceRegistration.registerReadOnlyAttribute(TTL, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getTtl()));
}
});
resourceRegistration.registerReadOnlyAttribute(FLUSH_PACKETS, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.isFlushPackets()));
}
});
resourceRegistration.registerReadOnlyAttribute(QUEUE_NEW_REQUESTS, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.isQueueNewRequests()));
}
});
resourceRegistration.registerReadOnlyAttribute(URI, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getUri().toString()));
}
});
resourceRegistration.registerReadOnlyAttribute(ALIASES, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
final ModelNode result = new ModelNode();
for (String alias : ctx.getAliases()) {
UndertowLogger.ROOT_LOGGER.tracef("Adding alias %s", alias);
result.add(alias);
}
context.getResult().set(result);
}
});
resourceRegistration.registerReadOnlyAttribute(ELECTED, new AbstractNodeOperation() {
@Override
protected void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException {
context.getResult().set(new ModelNode(ctx.getElected()));
}
});
}
private abstract class AbstractNodeOperation implements OperationStepHandler {
@Override
public final void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
PathAddress address = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS));
int current = address.size() - 1;
String nodeName = address.getElement(current--).getValue();
String balancerName = address.getElement(current--).getValue();
String modClusterName = address.getElement(current--).getValue();
ModClusterService service = ModClusterResource.service(modClusterName);
if (service == null) {
context.getResult().set(new ModelNode());
context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER);
return;
}
ModClusterStatus.LoadBalancer balancer = service.getModCluster().getController().getStatus().getLoadBalancer(balancerName);
if (balancer == null) {
context.getResult().set(new ModelNode());
context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER);
return;
}
ModClusterStatus.Node node = balancer.getNode(nodeName);
if (node == null) {
context.getResult().set(new ModelNode());
context.completeStep(OperationContext.ResultHandler.NOOP_RESULT_HANDLER);
return;
}
handleNode(context, node, operation);
}
protected abstract void handleNode(OperationContext context, ModClusterStatus.Node ctx, ModelNode operation) throws OperationFailedException;
}
}