io.undertow.server.handlers.proxy.mod_cluster.MCMPWebManager Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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 io.undertow.server.handlers.proxy.mod_cluster;
import io.undertow.io.Sender;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
import io.undertow.util.StatusCodes;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* The mod cluster manager web frontend.
*
* @author Emanuel Muckenhuber
*/
class MCMPWebManager extends MCMPHandler {
private final boolean checkNonce;
private final boolean reduceDisplay;
private final boolean allowCmd;
private final Random r = new SecureRandom();
private String nonce = null;
MCMPWebManager(MCMPConfig.MCMPWebManagerConfig config, ModCluster modCluster, HttpHandler next) {
super(config, modCluster, next);
this.checkNonce = config.isCheckNonce();
this.reduceDisplay = config.isReduceDisplay();
this.allowCmd = config.isAllowCmd();
}
String getNonce() {
return "nonce=" + getRawNonce();
}
synchronized String getRawNonce() {
if (this.nonce == null) {
byte[] nonce = new byte[16];
r.nextBytes(nonce);
this.nonce = "";
for (int i = 0; i < 16; i = i + 2) {
this.nonce = this.nonce.concat(Integer.toHexString(0xFF & nonce[i] * 16 + 0xFF & nonce[i + 1]));
}
}
return nonce;
}
@Override
protected void handleRequest(HttpString method, HttpServerExchange exchange) throws Exception {
if (!Methods.GET.equals(method)) {
super.handleRequest(method, exchange);
return;
}
// Process the request
processRequest(exchange);
}
protected boolean handlesMethod(HttpString method) {
if(Methods.GET.equals(method)) {
return true;
}
return super.handlesMethod(method);
}
private void processRequest(HttpServerExchange exchange) throws IOException {
Map> params = exchange.getQueryParameters();
boolean hasNonce = params.containsKey("nonce");
int refreshTime = 0;
if (checkNonce) {
/* Check the nonce */
if (hasNonce) {
String receivedNonce = params.get("nonce").getFirst();
if (receivedNonce.equals(getRawNonce())) {
boolean refresh = params.containsKey("refresh");
if (refresh) {
String sval = params.get("refresh").getFirst();
refreshTime = Integer.parseInt(sval);
if (refreshTime < 10)
refreshTime = 10;
exchange.getResponseHeaders().add(new HttpString("Refresh"), Integer.toString(refreshTime));
}
boolean cmd = params.containsKey("Cmd");
boolean range = params.containsKey("Range");
if (cmd) {
String scmd = params.get("Cmd").getFirst();
if (scmd.equals("INFO")) {
processInfo(exchange);
return;
} else if (scmd.equals("DUMP")) {
processDump(exchange);
return;
} else if (scmd.equals("ENABLE-APP") && range) {
String srange = params.get("Range").getFirst();
final RequestData data = buildRequestData(exchange, params);
if (srange.equals("NODE")) {
processNodeCommand(exchange, data, MCMPAction.ENABLE);
}
if (srange.equals("DOMAIN")) {
boolean domain = params.containsKey("Domain");
if (domain) {
String sdomain = params.get("Domain").getFirst();
processDomainCmd(exchange, sdomain, MCMPAction.ENABLE);
}
}
if (srange.equals("CONTEXT")) {
processAppCommand(exchange, data, MCMPAction.ENABLE);
}
} else if (scmd.equals("DISABLE-APP") && range) {
final String srange = params.get("Range").getFirst();
final RequestData data = buildRequestData(exchange, params);
if (srange.equals("NODE")) {
processNodeCommand(exchange, data, MCMPAction.DISABLE);
}
if (srange.equals("DOMAIN")) {
boolean domain = params.containsKey("Domain");
if (domain) {
String sdomain = params.get("Domain").getFirst();
processDomainCmd(exchange, sdomain, MCMPAction.DISABLE);
}
}
if (srange.equals("CONTEXT")) {
processAppCommand(exchange, data, MCMPAction.DISABLE);
}
}
return;
}
}
}
}
exchange.setStatusCode(StatusCodes.OK);
exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "text/html; charset=ISO-8859-1");
final Sender resp = exchange.getResponseSender();
final StringBuilder buf = new StringBuilder();
buf.append("\nMod_cluster Status \n\n");
buf.append("" + MOD_CLUSTER_EXPOSED_VERSION + "
");
final String uri = exchange.getRequestPath();
final String nonce = getNonce();
if (refreshTime <= 0) {
buf.append("Auto Refresh");
}
buf.append(" show DUMP output");
buf.append(" show INFO output");
buf.append("\n");
// Show load balancing groups
final Map> nodes = new LinkedHashMap<>();
for (final Node node : container.getNodes()) {
final String domain = node.getNodeConfig().getDomain() != null ? node.getNodeConfig().getDomain() : "";
List list = nodes.get(domain);
if (list == null) {
list = new ArrayList<>();
nodes.put(domain, list);
}
list.add(node);
}
for (Map.Entry> entry : nodes.entrySet()) {
final String groupName = entry.getKey();
if (reduceDisplay) {
buf.append("
LBGroup " + groupName + ": ");
} else {
buf.append(" LBGroup " + groupName + ": ");
}
if (allowCmd) {
domainCommandString(buf, uri, MCMPAction.ENABLE, groupName);
domainCommandString(buf, uri, MCMPAction.DISABLE, groupName);
}
for (final Node node : entry.getValue()) {
final NodeConfig nodeConfig = node.getNodeConfig();
if (reduceDisplay) {
buf.append("
Node " + nodeConfig.getJvmRoute());
printProxyStat(buf, node, reduceDisplay);
} else {
buf.append(" Node " + nodeConfig.getJvmRoute() + " (" + nodeConfig.getConnectionURI() + "):
\n");
}
if (allowCmd) {
nodeCommandString(buf, uri, MCMPAction.ENABLE, nodeConfig.getJvmRoute());
nodeCommandString(buf, uri, MCMPAction.DISABLE, nodeConfig.getJvmRoute());
}
if (!reduceDisplay) {
buf.append("
\n");
buf.append("Balancer: " + nodeConfig.getBalancer() + ",LBGroup: " + nodeConfig.getDomain());
String flushpackets = "off";
if (nodeConfig.isFlushPackets()) {
flushpackets = "Auto";
}
buf.append(",Flushpackets: " + flushpackets + ",Flushwait: " + nodeConfig.getFlushwait() + ",Ping: " + nodeConfig.getPing() + " ,Smax: " + nodeConfig.getPing() + ",Ttl: " + TimeUnit.MILLISECONDS.toSeconds(nodeConfig.getTtl()));
printProxyStat(buf, node, reduceDisplay);
} else {
buf.append("
\n");
}
buf.append("\n");
// Process the virtual-host of the node
printInfoHost(buf, uri, reduceDisplay, allowCmd, node);
}
}
buf.append("\n");
resp.send(buf.toString());
}
void nodeCommandString(StringBuilder buf, String uri, MCMPAction status, String jvmRoute) {
switch (status) {
case ENABLE:
buf.append("Enable Contexts ");
break;
case DISABLE:
buf.append("Disable Contexts ");
break;
}
}
static void printProxyStat(StringBuilder buf, Node node, boolean reduceDisplay) {
String status = "NOTOK";
if (node.getStatus() == NodeStatus.NODE_UP)
status = "OK";
if (reduceDisplay) {
buf.append(" " + status + " ");
} else {
buf.append(",Status: " + status + ",Elected: " + node.getElected() + ",Read: " + node.getConnectionPool().getClientStatistics().getRead() + ",Transferred: " + node.getConnectionPool().getClientStatistics().getWritten() + ",Connected: "
+ node.getConnectionPool().getOpenConnections() + ",Load: " + node.getLoad());
}
}
/* based on domain_command_string */
void domainCommandString(StringBuilder buf, String uri, MCMPAction status, String lbgroup) {
switch (status) {
case ENABLE:
buf.append("Enable Nodes ");
break;
case DISABLE:
buf.append("Disable Nodes");
break;
}
}
void processDomainCmd(HttpServerExchange exchange, String domain, MCMPAction action) throws IOException {
if (domain != null) {
for (final Node node : container.getNodes()) {
if (domain.equals(node.getNodeConfig().getDomain())) {
processNodeCommand(node.getJvmRoute(), action);
}
}
}
processOK(exchange);
}
/* based on manager_info_hosts */
private void printInfoHost(StringBuilder buf, String uri, boolean reduceDisplay, boolean allowCmd, final Node node) {
for (Node.VHostMapping host : node.getVHosts()) {
if (!reduceDisplay) {
buf.append(" Virtual Host " + host.getId() + ":
");
}
printInfoContexts(buf, uri, reduceDisplay, allowCmd, host.getId(), host, node);
if (reduceDisplay) {
buf.append("Aliases: ");
for (String alias : host.getAliases()) {
buf.append(alias + " ");
}
} else {
buf.append("Aliases:
");
buf.append("");
for (String alias : host.getAliases()) {
buf.append(alias + "\n");
}
buf.append("
");
}
}
}
/* based on manager_info_contexts */
private void printInfoContexts(StringBuilder buf, String uri, boolean reduceDisplay, boolean allowCmd, long host, Node.VHostMapping vhost, Node node) {
if (!reduceDisplay)
buf.append("Contexts:
");
buf.append("");
for (Context context : node.getContexts()) {
if (context.getVhost() == vhost) {
String status = "REMOVED";
switch (context.getStatus()) {
case ENABLED:
status = "ENABLED";
break;
case DISABLED:
status = "DISABLED";
break;
case STOPPED:
status = "STOPPED";
break;
}
buf.append(context.getPath() + " , Status: " + status + " Request: " + context.getActiveRequests() + " ");
if (allowCmd) {
contextCommandString(buf, uri, context.getStatus(), context.getPath(), vhost.getAliases(), node.getJvmRoute());
}
buf.append("\n");
}
}
buf.append("
");
}
/* generate a command URL for the context */
void contextCommandString(StringBuilder buf, String uri, Context.Status status, String path, List alias, String jvmRoute) {
switch (status) {
case DISABLED:
buf.append("Enable ");
break;
case ENABLED:
buf.append("Disable ");
break;
}
}
static void contextString(StringBuilder buf, String path, List alias, String jvmRoute) {
buf.append("JVMRoute=" + jvmRoute + "&Alias=");
boolean first = true;
for (String a : alias) {
if (first) {
first = false;
} else {
buf.append(",");
}
buf.append(a);
}
buf.append("&Context=" + path);
}
static RequestData buildRequestData(final HttpServerExchange exchange, Map> params) {
final RequestData data = new RequestData();
for (final Map.Entry> entry : params.entrySet()) {
final HttpString name = new HttpString(entry.getKey());
data.addValues(name, entry.getValue());
}
return data;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy