Created
September 7, 2017 13:03
-
-
Save stalep/3689c960ea7ed911a6906f79af095d7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.jboss.performance.monitor; | |
import org.jboss.aesh.cl.CommandDefinition; | |
import org.jboss.aesh.cl.Option; | |
import org.jboss.aesh.cl.OptionList; | |
import org.jboss.aesh.cl.completer.FileOptionCompleter; | |
import org.jboss.aesh.cl.converter.CLConverter; | |
import org.jboss.aesh.cl.validator.CommandValidator; | |
import org.jboss.aesh.cl.validator.CommandValidatorException; | |
import org.jboss.aesh.cl.validator.OptionValidator; | |
import org.jboss.aesh.cl.validator.OptionValidatorException; | |
import org.jboss.aesh.console.command.Command; | |
import org.jboss.aesh.console.command.CommandOperation; | |
import org.jboss.aesh.console.command.CommandResult; | |
import org.jboss.aesh.console.command.ConsoleCommand; | |
import org.jboss.aesh.console.command.invocation.CommandInvocation; | |
import org.jboss.aesh.terminal.Key; | |
import org.jboss.aesh.terminal.Shell; | |
import org.jboss.as.controller.client.ModelControllerClient; | |
import org.xml.sax.SAXException; | |
import javax.xml.parsers.ParserConfigurationException; | |
import javax.xml.parsers.SAXParser; | |
import javax.xml.parsers.SAXParserFactory; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.PrintWriter; | |
import java.net.InetAddress; | |
import java.net.UnknownHostException; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.jar.JarFile; | |
/** | |
* @author <a href="mailto:[email protected]">Ståle W. Pedersen</a> | |
*/ | |
@CommandDefinition(name = "monitor", | |
description = "Monitor JBoss resources", | |
validator = MonitorResourcesCommand.MonitorValidator.class) | |
public class MonitorResourcesCommand implements Command, ConsoleCommand { | |
private static org.jboss.logging.Logger logger = org.jboss.logging.Logger.getLogger(MonitorResourcesCommand.class); | |
private static final String[] deploymentSubsystemValues = | |
new String[]{"ejb3", "jpa", "web", "webservices", "all", "none"}; | |
private static final String[] subsystemValues = | |
new String[]{"ejb3", "datasources", "web", "transactions", "messaging", "jca", "all", "none"}; | |
@Option(shortName = 'h', hasValue = true, | |
converter = InetConverter.class, | |
description = "Host name of the server to be monitored (defaults to localhost). ") | |
private InetAddress host; | |
@Option(shortName = 'p', hasValue = true, defaultValue = "9999", | |
validator = PortValidator.class, | |
description = "Port of the management interface, if not the default port. " | |
+ "Could be the port of the native interface of the domain controller.") | |
private int port; | |
@Option(shortName = 'f', hasValue = true, required = true, | |
completer = FileOptionCompleter.class, | |
converter = PrintWriterConverter.class, | |
defaultValue = "Filename to log usage statistics to.") | |
private PrintWriter file; | |
@Option(shortName = 'i', hasValue = true, defaultValue = "1000", | |
description = "Interval in milliseconds to gather usage statistics (defaults to once per second).") | |
private long interval; | |
@Option(shortName = 't', hasValue = true, description = "Timestamp date format.", defaultValue = "HH:mm:ss:SSS") | |
private String timestamp; | |
@Option(shortName = 'c', hasValue = true, description = "Configuration file for the standalone server you want to monitor.") | |
private File config; | |
@OptionList(name = "domain-config", shortName = 'd', valueSeparator = ',', | |
description = "Give the two configuration files, starting with the host configuration (e.g. host.xml), and then the domain.") | |
private List<File> domainConfig; | |
@OptionList(shortName = 's', valueSeparator = ',', | |
defaultValue = {"ejb3", "datasources", "web", "transactions", "messaging", "jca", "all", "none"}, | |
validator = SubsystemsValidator.class, | |
description = "List of Subsystems you would like to monitor - valid values are threads, ejb3, datasources, web, transactions, " | |
+ "messaging, jca and all or none - defaults to all (none is for when you want to do monitoring of deployments only)") | |
private List<String> subsystems; | |
@OptionList(name = "domain-server-names", shortName = 'n', valueSeparator = ',', | |
description = "List of server names in a domain to monitor - values are the server names listed in host.xml, default to all " | |
+ "(based on what it finds in host.xml).") | |
private List<String> domainServerNames; | |
@OptionList(shortName = 'a', valueSeparator = ',', | |
converter = JarFileConverter.class, | |
description = "List of deployments (or applications) to monitor - values are the names of the deployments such as <name>.ear, " | |
+ "<name>.war, with the path information to read the files.") | |
private List<JarFile> deployments; | |
@OptionList(name = "deployment-subsystems", shortName = 'b', valueSeparator = ',', | |
defaultValue = {"ejb3", "jpa", "web", "webservices", "all", "none"}, | |
validator = DeploymentSubsystemsValidator.class, | |
description = "List of subsystems, specific to your deployments, you would like to monitor - valid values are ejb3, jpa, web, webservices, " | |
+ "all or none - defaults to all (none is not valid if none is specified for subsystems)") | |
private List<String> deploymentSubsystems; | |
@Option(name = "help", hasValue = false) | |
private boolean help; | |
private boolean domainMode = false; | |
private boolean deploymentsToMonitor = false; | |
private String username; | |
private String password; | |
private boolean attached = false; | |
private Status status = Status.DEFAULT; | |
private ModelControllerClient client; | |
private Monitor[] monitors; | |
private ServerConfiguration serverConfiguration = null; | |
private Shell shell; | |
public MonitorResourcesCommand() { | |
} | |
public List<String> getSubsystems() { | |
return subsystems; | |
} | |
public List<String> getDomainServerNames() { | |
return domainServerNames; | |
} | |
public List<JarFile> getDeployments() { | |
return deployments; | |
} | |
public List<String> getDeploymentSubsystems() { | |
return deploymentSubsystems; | |
} | |
public File getConfig() { | |
return config; | |
} | |
public List<File> getDomainConfig() { | |
return domainConfig; | |
} | |
@Override | |
public CommandResult execute(CommandInvocation commandInvocation) { | |
if(help) | |
commandInvocation.getShell().out().println(commandInvocation.getHelpInfo("monitor")); | |
else { | |
this.shell = commandInvocation.getShell(); | |
attached = true; | |
commandInvocation.attachConsoleCommand(this); | |
initClient(commandInvocation); | |
setupMonitoring(); | |
startMonitoring(); | |
} | |
return CommandResult.SUCCESS; | |
} | |
private void connectWithPassword() { | |
client = NativeClient.getInstance(host, port, username, password); | |
} | |
private void setupMonitoring() { | |
// Setup for monitoring the specified subsystems and/or deployments | |
if(serverConfiguration != null) | |
monitors = serverConfiguration.createMonitors(client, subsystems, deployments, deploymentSubsystems); | |
else | |
shell.out().println("ServerConfiguration is null, cannot start monitors"); | |
} | |
private void initClient(CommandInvocation ci) { | |
// Try connecting to the server without authentication first | |
ModelControllerClient unauthenticatedClient = NativeClient.getInstance(host, port); | |
if (NativeClient.needsToAuthenticate(unauthenticatedClient)) { | |
// Failed to connect, must authenticate | |
if (username == null && password == null) { | |
ci.getShell().out().println("Connection failed, so you must authenticate!"); | |
ci.getShell().out().print("Enter username: "); | |
ci.getShell().out().flush(); | |
status = Status.USERNAME; | |
} | |
try { | |
unauthenticatedClient.close(); | |
} catch (IOException e) { | |
logger.info("Tried to close the unauthenticated client, because we needed to authenticate, but it failed!"); | |
} | |
} | |
else { | |
client = unauthenticatedClient; | |
} | |
} | |
private void startMonitoring() { | |
MonitorResourcesRunner runner = new MonitorResourcesRunner(logger, monitors, client, file, interval, timestamp); | |
try { | |
runner.startMonitoring(); | |
} | |
catch (InitialiseMonitorResourcesException e) { | |
shell.out().println("MonitorResources failed to start with the following error message: "+e.getMessage()); | |
} | |
} | |
public void shutdown() { | |
if(client != null) | |
try { | |
client.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private void setServerConfiguration(ServerConfiguration serverConfiguration) { | |
this.serverConfiguration = serverConfiguration; | |
} | |
@Override | |
public void processOperation(CommandOperation commandOperation) throws IOException { | |
if(status == Status.DEFAULT) { | |
} | |
else if(status == Status.USERNAME) { | |
if(commandOperation.getInputKey() == Key.ENTER) { | |
status = Status.PASSWORD; | |
shell.out().print("Enter password: "); | |
shell.out().flush(); | |
} | |
else | |
username = username + commandOperation.getInputKey().getAsChar(); | |
} | |
else if(status == Status.PASSWORD) { | |
if(commandOperation.getInputKey() == Key.ENTER) { | |
connectWithPassword(); | |
status = Status.PASSWORD; | |
} | |
else | |
password = password + commandOperation.getInputKey().getAsChar(); | |
} | |
} | |
@Override | |
public boolean isAttached() { | |
return attached; | |
} | |
public static class PortValidator implements OptionValidator<Integer> { | |
@Override | |
public void validate(Integer port) throws OptionValidatorException { | |
if(port < 0 || port > 65535) | |
throw new OptionValidatorException("Hey, looks like you specified an invalid port number: "+port); | |
} | |
} | |
public static class InetConverter implements CLConverter<InetAddress> { | |
@Override | |
public InetAddress convert(String host) throws OptionValidatorException { | |
try { | |
return InetAddress.getByName(host); | |
} | |
catch (UnknownHostException e) { | |
throw new OptionValidatorException("Hey, looks like the host is invalid: " + e.getMessage()); | |
} | |
} | |
} | |
public static class JarFileConverter implements CLConverter<JarFile> { | |
@Override | |
public JarFile convert(String deployment) throws OptionValidatorException { | |
try { | |
return new JarFile(deployment); | |
} | |
catch (IOException e) { | |
throw new OptionValidatorException( | |
"The deployment file you specified was invalid: "+e.getMessage()); | |
} | |
} | |
} | |
public static class PrintWriterConverter implements CLConverter<PrintWriter> { | |
@Override | |
public PrintWriter convert(String file) throws OptionValidatorException { | |
try { | |
return new PrintWriter(new File(file)); | |
} | |
catch (IOException e) { | |
throw new OptionValidatorException("Could not open file: "+file+", "+e.getMessage()); | |
} | |
} | |
} | |
public static class DeploymentSubsystemsValidator implements OptionValidator<String> { | |
@Override | |
public void validate(String value) throws OptionValidatorException { | |
for(String subsystem : deploymentSubsystemValues) | |
if(subsystem.equals(value)) | |
return; | |
throw new OptionValidatorException("Value "+value+" is not accepted, must one of: "+ Arrays.toString(deploymentSubsystemValues)); | |
} | |
} | |
public static class SubsystemsValidator implements OptionValidator<String> { | |
@Override | |
public void validate(String value) throws OptionValidatorException { | |
for(String subsystem : subsystemValues) | |
if(subsystem.equals(value)) | |
return; | |
throw new OptionValidatorException("Value "+value+" is not accepted, must one of: "+ Arrays.toString(deploymentSubsystemValues)); | |
} | |
} | |
public class MonitorValidator implements CommandValidator<MonitorResourcesCommand> { | |
@Override | |
public void validate(MonitorResourcesCommand command) throws CommandValidatorException { | |
if(command.getConfig() == null || !command.getConfig().isFile()) { | |
if(command.getDomainConfig() == null || command.getDomainConfig().size() == 0) | |
throw new CommandValidatorException("You did not specify a server configuration file (either domain or standalone) to parse for subsystem information!"); | |
if(command.getDomainConfig().size() != 2) | |
throw new CommandValidatorException("You did not specify the correct number of arguments for domain-config option. You should specify two files, the host and domain xml files."); | |
} | |
if(command.getSubsystems() == null || command.getSubsystems().size() == 0) { | |
command.subsystems = ServerConfiguration.subsystemsToMonitor(); | |
} | |
else { | |
if (command.subsystems.size() == 1 && (command.subsystems.get(0).equals("all"))) { | |
command.subsystems = ServerConfiguration.subsystemsToMonitor(); | |
} | |
else if (command.subsystems.size() == 1 && (command.subsystems.get(0).equals("none"))) { | |
command.subsystems = null; | |
} | |
else { | |
boolean subsystemsAreValid = false; | |
List<String> possibleSubsystemsToMonitor = ServerConfiguration.subsystemsToMonitor(); | |
if (possibleSubsystemsToMonitor.containsAll(command.subsystems)) { | |
subsystemsAreValid = true; | |
} | |
if (!subsystemsAreValid) { | |
throw new CommandValidatorException( | |
"The subsystems you specified on the command line are not completely valid." + | |
"Valid subsystems are " + ServerConfiguration.subsystemsToMonitor() + " or all or none."); | |
} | |
} | |
} | |
if(command.getDeployments() != null) { | |
command.deploymentsToMonitor = true; | |
// So we are doing deployment monitoring, so let's see if the deployment-subsystems are valid | |
if (command.deploymentSubsystems == null) { | |
command.deploymentSubsystems = ServerConfiguration.deploymentSubsystemsToMonitor(); | |
} | |
else { | |
if (command.deploymentSubsystems.size() == 1 && | |
(command.deploymentSubsystems.get(0).equals("all"))) { | |
command.deploymentSubsystems = ServerConfiguration.deploymentSubsystemsToMonitor(); | |
} | |
else if (command.deploymentSubsystems.size() == 1 && | |
(command.deploymentSubsystems.get(0).equals("none"))) { | |
if (command.subsystems == null) { | |
// Specified no monitoring at all, with none on subsystems, and none on deployment subsystems | |
throw new CommandValidatorException( | |
"You must specify a subsystem to monitor either for general subsystems, or deployment specific subsystems, but both were specified as none." + | |
"Valid subsystems are " + ServerConfiguration.subsystemsToMonitor() + | |
"Valid deloyment-subsystems are " + ServerConfiguration.deploymentSubsystemsToMonitor()); | |
} | |
command.deploymentSubsystems = null; | |
} | |
else { | |
boolean deploymentSubsystemsAreValid = false; | |
List<String> possibleDeploymentSubsystemsToMonitor = ServerConfiguration.deploymentSubsystemsToMonitor(); | |
if (possibleDeploymentSubsystemsToMonitor.containsAll(command.deploymentSubsystems)) { | |
deploymentSubsystemsAreValid = true; | |
} | |
if (!deploymentSubsystemsAreValid) { | |
throw new CommandValidatorException( | |
"The deployment-subsystems you specified on the command line are not completely valid." + | |
"Valid deployment-subsystems are " + ServerConfiguration.deploymentSubsystemsToMonitor() + "or all or none."); | |
} | |
} | |
} | |
} | |
parseServerConfigFile(command); | |
} | |
private void parseServerConfigFile(MonitorResourcesCommand command) throws CommandValidatorException { | |
// Parse the servers configuration file | |
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |
ServerConfiguration serverConfiguration = null; | |
serverConfiguration = ServerConfigurationFactory.createServerConfiguration( | |
command.domainMode, command.deploymentsToMonitor, command.deployments); | |
try { | |
SAXParser saxParser = saxParserFactory.newSAXParser(); | |
if (command.domainMode) { | |
saxParser.parse(command.domainConfig.get(0), serverConfiguration); | |
saxParser.parse(command.domainConfig.get(1), serverConfiguration); | |
} | |
else { | |
saxParser.parse(command.config, serverConfiguration); | |
} | |
} | |
catch (SAXException e) { | |
throw new CommandValidatorException("Configuration file may not be valid: "+e.getMessage()); | |
} | |
catch (ParserConfigurationException e) { | |
throw new CommandValidatorException("Parser configuration error: "+e.getMessage()); | |
} | |
catch (IOException e) { | |
throw new CommandValidatorException("Looks like the file name may not be correct: "+e.getMessage()); | |
} | |
// Check if the host and port passed on the command line - or the defaults, match the configuration file | |
if (!serverConfiguration.getManagementInterfaceHostName().equalsIgnoreCase(command.host.getHostName()) && | |
!serverConfiguration.getManagementInterfaceHostName().equalsIgnoreCase(command.host.getHostAddress())) { | |
throw new CommandValidatorException( | |
"Specified and/or default host does not match the host specified in the configuration file!" + | |
"Specified and/or default host is : " + command.host + | |
"Host in the configuration file is: " + serverConfiguration.getManagementInterfaceHostName()); | |
} | |
if (serverConfiguration.getManagementInterfacePort() != command.port) { | |
throw new CommandValidatorException( | |
"Specified and/or default port does not match the port specified in the configuration file!" + | |
"Specified and/or default port is : " + command.port + | |
"Port in the configuration file is: " + serverConfiguration.getManagementInterfacePort()); | |
} | |
//todo: this doesnt do much atm, serverNames is not used | |
if (command.domainMode) { | |
List<String> serverNames; | |
if (command.domainServerNames == null) { | |
serverNames = serverConfiguration.getServerNames(); | |
} else { | |
serverNames = command.domainServerNames; | |
if (serverNames.size() == 1 && (serverNames.get(0).equals("all"))) { | |
serverNames = serverConfiguration.getServerNames(); | |
} else { | |
boolean serverNamesAreValid = false; | |
List<String> possibleServerNames = serverConfiguration.getServerNames(); | |
if (possibleServerNames.containsAll(serverNames)) { | |
serverNamesAreValid = true; | |
} | |
if (!serverNamesAreValid) { | |
throw new CommandValidatorException( | |
"The server names you specified on the command line are not valid." + | |
"Valid server names from your configuration are " + serverConfiguration.getServerNames() + " or all"); | |
} | |
} | |
} | |
} | |
// Check to see that the XML configuration contained information for address for all the subsystems specified for monitoring | |
if (command.subsystems != null) { | |
List<String> removedSubsystems = new ArrayList<String>(); | |
for (String subsystem : command.subsystems) { | |
if (!serverConfiguration.subsystemHasAddressInConfiguration(subsystem)) { | |
logger.warn("Missing configuration needed for monitoring of subsystem " + subsystem + "!"); | |
logger.warn("Removing " + subsystem + " from monitoring."); | |
removedSubsystems.add(subsystem); | |
} | |
} | |
command.subsystems.removeAll(removedSubsystems); | |
if (command.subsystems.isEmpty()) { | |
throw new CommandValidatorException( | |
"Due to previous warnings, there are no valid subsystems to monitor!" + | |
"Exiting due to previous errors. You will need to configure your server correctly for monitoring."); | |
} | |
} | |
command.setServerConfiguration(serverConfiguration); | |
} | |
} | |
enum Status { | |
USERNAME, | |
PASSWORD, | |
DEFAULT; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment