modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java | 91 ++--- modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageProperty.java | 181 ++++++++++ modules/core/util/src/main/java/org/rhq/core/util/PropertiesFileUpdate.java | 9 modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java | 55 --- modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java | 151 +++++++- modules/enterprise/server/installer/src/main/resources/logging.properties | 6 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementAggregate.java | 2 modules/enterprise/server/server-control/pom.xml | 22 + modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java | 133 ++++++- modules/enterprise/server/server-control/src/main/resources/logging.properties | 6 modules/enterprise/server/server-control/src/main/resources/module/main/module.xml | 32 - 11 files changed, 542 insertions(+), 146 deletions(-)
New commits: commit 4f2756240bc1e32fad8c5ca94c813af696ef0ce7 Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Oct 1 10:45:02 2013 -0400
limit dependencies by using core util only
diff --git a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java index 2233cea..b3209f9 100644 --- a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java +++ b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java @@ -26,6 +26,7 @@ import java.util.Properties; import java.util.Set;
import org.rhq.core.util.PropertiesFileUpdate; +import org.rhq.core.util.StringUtil; import org.rhq.core.util.obfuscation.PicketBoxObfuscator;
/** @@ -268,7 +269,7 @@ public class ServerProperties {
for (String name : ServerProperties.BOOLEAN_PROPERTIES) { String val = serverProperties.get(name); - if (ServerInstallUtil.isEmpty(val) && OPTIONAL_PROPERTIES.contains(name)) { + if (StringUtil.isBlank(val) && OPTIONAL_PROPERTIES.contains(name)) { continue; } if (!("true".equals(val) || "false".equals(val))) { @@ -278,7 +279,7 @@ public class ServerProperties {
for (String name : ServerProperties.INTEGER_PROPERTIES) { String val = serverProperties.get(name); - if (ServerInstallUtil.isEmpty(val) && OPTIONAL_PROPERTIES.contains(name)) { + if (StringUtil.isBlank(val) && OPTIONAL_PROPERTIES.contains(name)) { continue; } try { @@ -295,7 +296,7 @@ public class ServerProperties { } for (String name : requiredStringProperties) { String val = serverProperties.get(name); - if (ServerInstallUtil.isEmpty(val)) { + if (StringUtil.isBlank(val)) { dataErrors.append("[" + name + "] must exist and be set to a valid string value\n");
} else if (ServerProperties.OBFUSCATED_PROPERTIES.contains(name)) {
commit 331cc77b2ffb65320c5731d22d00147fb522cfb4 Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Oct 1 10:44:35 2013 -0400
fix typo
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementAggregate.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementAggregate.java index 7acc5f6..6f2bb6f 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementAggregate.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementAggregate.java @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -package org.rhq.enterprise.server.measurement;; +package org.rhq.enterprise.server.measurement;
import java.io.Serializable;
commit aafabc790c03be5b038171fa3e27c5664aab0637 Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Oct 1 09:47:19 2013 -0400
Bug 1002778 - Installer to prompt user for rhqadmin password, rather than using hard-coded default Perform more up front validation of rhq-server.properties and rhq-storage.properties when executing 'rhqctl install' in order to prevent doomed installation attempts.
Moreover, add the ability to prompt for certain required settings. If not set in the rhq-server.properties file rhqctl will now prompt for the jboss.bind.address setting and the rhq.server.database.password setting. The latter accepts plain text and will encode the value automatically prior to updating rhq-server.properties.
- moved validation logic into ServerProperties and improved - similar to ServerProperties, created StorageProperty (enum) with built-in validation logic. - decrease logging sensitivity to INFO for rhqctl and the server installer - try to clean up what rhqctl spits out to the console
diff --git a/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java b/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java index 30a51a4..29aa8d4 100644 --- a/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java +++ b/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java @@ -106,19 +106,6 @@ public class StorageInstaller {
private final String STORAGE_BASEDIR = "rhq-storage";
- private static final String OPTION_HOSTNAME = "rhq.storage.hostname"; - private static final String OPTION_SEEDS = "rhq.storage.seeds"; - private static final String OPTION_CQL_PORT = "rhq.storage.cql-port"; - private static final String OPTION_JMX_PORT = "rhq.storage.jmx-port"; - private static final String OPTION_GOSSIP_PORT = "rhq.storage.gossip-port"; - private static final String OPTION_COMMITLOG = "rhq.storage.commitlog"; - private static final String OPTION_DATA = "rhq.storage.data"; - private static final String OPTION_SAVED_CACHES = "rhq.storage.saved-caches"; - private static final String OPTION_HEAP_SIZE = "rhq.storage.heap-size"; - private static final String OPTION_HEAP_NEW_SIZE = "rhq.storage.heap-new-size"; - private static final String OPTION_STACK_SIZE = "rhq.storage.stack-size"; - private static final String OPTION_VERIFY_DATA_DIRS_EMPTY = "rhq.storage.verify-data-dirs-empty"; - private final Log log = LogFactory.getLog(StorageInstaller.class);
private Options options; @@ -147,26 +134,27 @@ public class StorageInstaller { storageBasedir = new File(basedir, STORAGE_BASEDIR); logDir = new File(serverBasedir, "logs");
- Option hostname = new Option("n", OPTION_HOSTNAME, true, + Option hostname = new Option("n", StorageProperty.HOSTNAME.property(), true, "The hostname or IP address on which the node will listen for " + "requests. Note that if a hostname is specified, the IP address is used. Defaults to the IP " + "address of the local host (which depending on hostname configuration may not be localhost)."); hostname.setArgName("HOSTNAME");
- Option seeds = new Option("s", OPTION_SEEDS, true, "A comma-delimited list of hostnames or IP addresses that " - + "serve as contact points. Nodes use this list to find each other and to learn the cluster topology. " - + "It does not need to specify all nodes in the cluster. Defaults to this node's hostname."); + Option seeds = new Option("s", StorageProperty.SEEDS.property(), true, + "A comma-delimited list of hostnames or IP addresses that " + + "serve as contact points. Nodes use this list to find each other and to learn the cluster topology. " + + "It does not need to specify all nodes in the cluster. Defaults to this node's hostname."); seeds.setArgName("SEEDS");
- Option jmxPortOption = new Option("j", OPTION_JMX_PORT, true, + Option jmxPortOption = new Option("j", StorageProperty.JMX_PORT.property(), true, "The port on which to listen for JMX connections. " + "Defaults to " + defaultJmxPort + "."); jmxPortOption.setArgName("PORT");
- Option cqlPortOption = new Option("c", OPTION_CQL_PORT, true, "The port on which to " + Option cqlPortOption = new Option("c", StorageProperty.CQL_PORT.property(), true, "The port on which to " + "listen for client requests. Defaults to " + defaultCqlPort); cqlPortOption.setArgName("PORT");
- Option gossipPortOption = new Option(null, OPTION_GOSSIP_PORT, true, + Option gossipPortOption = new Option(null, StorageProperty.GOSSIP_PORT.property(), true, "The port on which to listen for requests " + " from other nodes. Defaults to " + defaultGossipPort); gossipPortOption.setArgName("PORT");
@@ -178,15 +166,16 @@ public class StorageInstaller { + "after starting it. This option is ignored if the start option is not set. Defaults to true."); checkStatus.setArgName("true|false");
- Option commitLogOption = new Option(null, OPTION_COMMITLOG, true, "The directory where the storage node keeps " - + "commit log files. Defaults to " + getDefaultCommitLogDir() + "."); + Option commitLogOption = new Option(null, StorageProperty.COMMITLOG.property(), true, + "The directory where the storage node keeps " + "commit log files. Defaults to " + getDefaultCommitLogDir() + + "."); commitLogOption.setArgName("DIR");
- Option dataDirOption = new Option(null, OPTION_DATA, true, + Option dataDirOption = new Option(null, StorageProperty.DATA.property(), true, "The directory where the storage node keeps data files. " + "Defaults to " + getDefaultDataDir() + "."); dataDirOption.setArgName("DIR");
- Option savedCachesDirOption = new Option(null, OPTION_SAVED_CACHES, true, + Option savedCachesDirOption = new Option(null, StorageProperty.SAVED_CACHES.property(), true, "The directory where the storage node " + "keeps saved cache files. Defaults to " + getDefaultSavedCachesDir() + "."); savedCachesDirOption.setArgName("DIR"); @@ -194,17 +183,17 @@ public class StorageInstaller { Option basedirOption = new Option(null, "dir", true, "The directory where the storage node will be installed " + "The default directory will be " + storageBasedir);
- Option heapSizeOption = new Option(null, OPTION_HEAP_SIZE, true, + Option heapSizeOption = new Option(null, StorageProperty.HEAP_SIZE.property(), true, "The value to use for both the min and max heap. " + "This value is passed directly to the -Xms and -Xmx options of the Java executable. Defaults to " + defaultHeapSize);
- Option heapNewSizeOption = new Option(null, OPTION_HEAP_NEW_SIZE, true, + Option heapNewSizeOption = new Option(null, StorageProperty.HEAP_NEW_SIZE.property(), true, "The value to use for the new generation " + "of the heap. This value is passed directly to the -Xmn option of the Java executable. Defaults to " + defaultHeapNewSize);
- Option stackSizeOption = new Option(null, OPTION_STACK_SIZE, true, + Option stackSizeOption = new Option(null, StorageProperty.STACK_SIZE.property(), true, "The value to use for the thread stack size. " + "This value is passed directly to the -Xss option of the Java executable.");
@@ -212,7 +201,7 @@ public class StorageInstaller { + "where the existing RHQ server is installed."); upgradeOption.setArgName("RHQ_SERVER_DIR");
- Option verifyDataDirsEmptyOption = new Option(null, OPTION_VERIFY_DATA_DIRS_EMPTY, true, + Option verifyDataDirsEmptyOption = new Option(null, StorageProperty.VERIFY_DATA_DIRS_EMPTY.property(), true, "Will cause the installer " + "to abort if any of the data directories is not empty. Defaults to true.");
options = new Options().addOption(new Option("h", "help", false, "Show this message.")).addOption(hostname) @@ -250,8 +239,8 @@ public class StorageInstaller { log.info("Updating rhq-server.properties..."); Properties properties = new Properties(); properties.setProperty("rhq.storage.nodes", installerInfo.hostname); - properties.setProperty(OPTION_CQL_PORT, Integer.toString(installerInfo.cqlPort)); - properties.setProperty(OPTION_GOSSIP_PORT, Integer.toString(installerInfo.gossipPort)); + properties.setProperty(StorageProperty.CQL_PORT.property(), Integer.toString(installerInfo.cqlPort)); + properties.setProperty(StorageProperty.GOSSIP_PORT.property(), Integer.toString(installerInfo.gossipPort));
serverPropertiesUpdater.update(properties);
@@ -335,21 +324,23 @@ public class StorageInstaller { deploymentOptions.setListenAddress(installerInfo.hostname); deploymentOptions.setRpcAddress(installerInfo.hostname);
- String seeds = cmdLine.getOptionValue(OPTION_SEEDS, installerInfo.hostname); + String seeds = cmdLine.getOptionValue(StorageProperty.SEEDS.property(), installerInfo.hostname); deploymentOptions.setSeeds(seeds);
- String commitlogDir = cmdLine.getOptionValue(OPTION_COMMITLOG, getDefaultCommitLogDir().getAbsolutePath()); - String dataDir = cmdLine.getOptionValue(OPTION_DATA, getDefaultDataDir().getAbsolutePath()); - String savedCachesDir = cmdLine.getOptionValue(OPTION_SAVED_CACHES, getDefaultSavedCachesDir() + String commitlogDir = cmdLine.getOptionValue(StorageProperty.COMMITLOG.property(), getDefaultCommitLogDir() + .getAbsolutePath()); + String dataDir = cmdLine.getOptionValue(StorageProperty.DATA.property(), getDefaultDataDir() .getAbsolutePath()); + String savedCachesDir = cmdLine.getOptionValue(StorageProperty.SAVED_CACHES.property(), + getDefaultSavedCachesDir().getAbsolutePath());
File commitLogDirFile = new File(commitlogDir); File dataDirFile = new File(dataDir); File savedCachesDirFile = new File(savedCachesDir); installerInfo.logFile = new File(logDir, "rhq-storage.log");
- boolean verifyDataDirsEmpty = Boolean - .valueOf(cmdLine.getOptionValue(OPTION_VERIFY_DATA_DIRS_EMPTY, "true")); + boolean verifyDataDirsEmpty = Boolean.valueOf(cmdLine.getOptionValue( + StorageProperty.VERIFY_DATA_DIRS_EMPTY.property(), "true")); if (verifyDataDirsEmpty) { // validate the three data directories are empty - if they are not, we are probably stepping on // another storage node @@ -373,20 +364,20 @@ public class StorageInstaller { } }
- installerInfo.jmxPort = getPort(cmdLine, OPTION_JMX_PORT, defaultJmxPort); + installerInfo.jmxPort = getPort(cmdLine, StorageProperty.JMX_PORT.property(), defaultJmxPort); if (isPortBound(installerInfo.hostname, installerInfo.jmxPort, "jmx-port")) { throw new StorageInstallerException("The jmx-port (" + installerInfo.jmxPort + ") is already in use. " + "Installation cannot proceed.", STATUS_JMX_PORT_CONFLICT); }
- installerInfo.cqlPort = getPort(cmdLine, OPTION_CQL_PORT, defaultCqlPort); - if (isPortBound(installerInfo.hostname, installerInfo.cqlPort, OPTION_CQL_PORT)) { + installerInfo.cqlPort = getPort(cmdLine, StorageProperty.CQL_PORT.property(), defaultCqlPort); + if (isPortBound(installerInfo.hostname, installerInfo.cqlPort, StorageProperty.CQL_PORT.property())) { throw new StorageInstallerException("The cql-port (" + installerInfo.cqlPort + ") is already in use. " + "Installation cannot proceed.", STATUS_CQL_PORT_CONFLICT); }
- installerInfo.gossipPort = getPort(cmdLine, OPTION_GOSSIP_PORT, defaultGossipPort); - if (isPortBound(installerInfo.hostname, installerInfo.gossipPort, OPTION_GOSSIP_PORT)) { + installerInfo.gossipPort = getPort(cmdLine, StorageProperty.GOSSIP_PORT.property(), defaultGossipPort); + if (isPortBound(installerInfo.hostname, installerInfo.gossipPort, StorageProperty.GOSSIP_PORT.property())) { throw new StorageInstallerException("The gossip-port (" + installerInfo.gossipPort + ") is already in use. " + "Installation cannot proceed.", STATUS_GOSSIP_PORT_CONFLICT); } @@ -404,10 +395,12 @@ public class StorageInstaller { deploymentOptions.setGossipPort(installerInfo.gossipPort); deploymentOptions.setJmxPort(installerInfo.jmxPort);
- deploymentOptions.setHeapSize(cmdLine.getOptionValue(OPTION_HEAP_SIZE, defaultHeapSize)); - deploymentOptions.setHeapNewSize(cmdLine.getOptionValue(OPTION_HEAP_NEW_SIZE, defaultHeapNewSize)); - if (cmdLine.hasOption(OPTION_STACK_SIZE)) { - deploymentOptions.setStackSize(cmdLine.getOptionValue(OPTION_STACK_SIZE)); + deploymentOptions + .setHeapSize(cmdLine.getOptionValue(StorageProperty.HEAP_SIZE.property(), defaultHeapSize)); + deploymentOptions.setHeapNewSize(cmdLine.getOptionValue(StorageProperty.HEAP_NEW_SIZE.property(), + defaultHeapNewSize)); + if (cmdLine.hasOption(StorageProperty.STACK_SIZE.property())) { + deploymentOptions.setStackSize(cmdLine.getOptionValue(StorageProperty.STACK_SIZE.property())); }
// The out of box default for native_transport_max_threads is 128. We default @@ -417,9 +410,9 @@ public class StorageInstaller { deploymentOptions.load();
List<String> errors = new ArrayList<String>(); - checkPerms(options.getOption(OPTION_SAVED_CACHES), savedCachesDir, errors); - checkPerms(options.getOption(OPTION_COMMITLOG), commitlogDir, errors); - checkPerms(options.getOption(OPTION_DATA), dataDir, errors); + checkPerms(options.getOption(StorageProperty.SAVED_CACHES.property()), savedCachesDir, errors); + checkPerms(options.getOption(StorageProperty.COMMITLOG.property()), commitlogDir, errors); + checkPerms(options.getOption(StorageProperty.DATA.property()), dataDir, errors);
if (!errors.isEmpty()) { log.error("Problems have been detected with one or more of the directories in which the storage " @@ -913,7 +906,7 @@ public class StorageInstaller { public Options getHelpOptions() { Options helpOptions = new Options(); for (Option option : (Collection<Option>) options.getOptions()) { - if (option.getLongOpt().equals(OPTION_VERIFY_DATA_DIRS_EMPTY)) { + if (option.getLongOpt().equals(StorageProperty.VERIFY_DATA_DIRS_EMPTY)) { continue; } helpOptions.addOption(option); diff --git a/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageProperty.java b/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageProperty.java new file mode 100644 index 0000000..3b9a5f1 --- /dev/null +++ b/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageProperty.java @@ -0,0 +1,181 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.storage.installer; + +import java.io.File; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.rhq.core.util.PropertiesFileUpdate; + +public enum StorageProperty { + HOSTNAME("rhq.storage.hostname"), // + SEEDS("rhq.storage.seeds"), // + CQL_PORT("rhq.storage.cql-port"), // + JMX_PORT("rhq.storage.jmx-port"), // + GOSSIP_PORT("rhq.storage.gossip-port"), // + COMMITLOG("rhq.storage.commitlog"), // + DATA("rhq.storage.data"), // + SAVED_CACHES("rhq.storage.saved-caches"), // + HEAP_SIZE("rhq.storage.heap-size"), // + HEAP_NEW_SIZE("rhq.storage.heap-new-size"), // + STACK_SIZE("rhq.storage.stack-size"), // + VERIFY_DATA_DIRS_EMPTY("rhq.storage.verify-data-dirs-empty"); + + private static final HashSet<StorageProperty> STRINGS = new HashSet<StorageProperty>(); + static { + // currently no required string properties + } + + private static final HashSet<StorageProperty> INTEGERS = new HashSet<StorageProperty>(); + static { + INTEGERS.add(CQL_PORT); + INTEGERS.add(JMX_PORT); + INTEGERS.add(GOSSIP_PORT); + } + + private static final HashSet<StorageProperty> BOOLEANS = new HashSet<StorageProperty>(); + static { + BOOLEANS.add(VERIFY_DATA_DIRS_EMPTY); + } + + // validate optional non-string properties, if set + private static final HashSet<StorageProperty> OPTIONAL = new HashSet<StorageProperty>(); + static { + OPTIONAL.add(CQL_PORT); + OPTIONAL.add(JMX_PORT); + OPTIONAL.add(GOSSIP_PORT); + OPTIONAL.add(VERIFY_DATA_DIRS_EMPTY); + } + + private String property; + + StorageProperty(String property) { + this.property = property; + } + + public String property() { + return this.property; + } + + @Override + public String toString() { + return this.property; + } + + public static void validate(File storagePropertiesFile) throws Exception { + validate(storagePropertiesFile, null); + } + + /** + * @param storagePropertiesFile + * @param additionalProperties additional properties that should be set (present and not empty). can be null. + * @throws Exception + */ + public static void validate(File storagePropertiesFile, Set<StorageProperty> additionalProperties) throws Exception { + if (!storagePropertiesFile.isFile()) { + throw new Exception("Properties file not found: [" + storagePropertiesFile.getAbsolutePath() + "]"); + } + + PropertiesFileUpdate pfu = new PropertiesFileUpdate(storagePropertiesFile); + Properties props = pfu.loadExistingProperties(); + final HashMap<String, String> map = new HashMap<String, String>(props.size()); + for (Object property : props.keySet()) { + map.put(property.toString(), props.getProperty(property.toString())); + } + + validate(map, additionalProperties); + } + + public static void validate(Map<String, String> storageProperties) throws Exception { + validate(storageProperties, null); + } + + /** + * @param storageProperties + * @param additionalProperties additional properties that should be set (present and not empty). can be null. + * @throws Exception + */ + public static void validate(Map<String, String> storageProperties, Set<StorageProperty> additionalProperties) + throws Exception { + final StringBuilder dataErrors = new StringBuilder(); + + for (StorageProperty storageProperty : BOOLEANS) { + String val = storageProperties.get(storageProperty.property()); + if (isEmpty(val) && OPTIONAL.contains(storageProperty)) { + continue; + } + if (!("true".equals(val) || "false".equals(val))) { + dataErrors + .append("[" + storageProperty + "] must exist and be set 'true' or 'false' : [" + val + "]\n"); + } + } + + for (StorageProperty storageProperty : StorageProperty.INTEGERS) { + String val = storageProperties.get(storageProperty.property); + if (isEmpty(val) && OPTIONAL.contains(storageProperty)) { + continue; + } + try { + Integer.parseInt(val); + } catch (NumberFormatException e) { + dataErrors.append("[" + storageProperty + "] must exist and be set to a number : [" + val + "]\n"); + } + } + + Set<StorageProperty> requiredStringProperties = new HashSet<StorageProperty>(); + requiredStringProperties.addAll(STRINGS); + if (null != additionalProperties) { + requiredStringProperties.addAll(additionalProperties); + } + for (StorageProperty storageProperty : requiredStringProperties) { + String val = storageProperties.get(storageProperty.property); + if (isEmpty(val)) { + dataErrors.append("[" + storageProperty + "] must exist and be set to a valid string value\n"); + } + } + + for (String property : storageProperties.keySet()) { + boolean unknown = true; + for (StorageProperty storageProperty : EnumSet.allOf(StorageProperty.class)) { + if (storageProperty.property.equals(property)) { + unknown = false; + break; + } + } + if (unknown) { + dataErrors.append("[" + property + + "] property found in file but not recognized. Please fix or remove.\n"); + } + } + + if (dataErrors.length() > 0) { + throw new Exception("Validation errors:\n" + dataErrors.toString()); + } + } + + private static boolean isEmpty(String s) { + return s == null || s.trim().length() == 0; + } + +} diff --git a/modules/core/util/src/main/java/org/rhq/core/util/PropertiesFileUpdate.java b/modules/core/util/src/main/java/org/rhq/core/util/PropertiesFileUpdate.java index d419770..306d5d9 100644 --- a/modules/core/util/src/main/java/org/rhq/core/util/PropertiesFileUpdate.java +++ b/modules/core/util/src/main/java/org/rhq/core/util/PropertiesFileUpdate.java @@ -63,6 +63,15 @@ public class PropertiesFileUpdate { }
/** + * Constructor given the .properties file. + * + * @param the properties file + */ + public PropertiesFileUpdate(File file) { + this.file = file; + } + + /** * Updates the properties file so it will contain the key with the value. If value is <code>null</code>, an empty * string will be used in the properties file. If the property does not yet exist in the properties file, it will be * appended to the end of the file. diff --git a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java index 445f41e..6f9ccfe 100644 --- a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java +++ b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/InstallerServiceImpl.java @@ -23,10 +23,12 @@ import java.io.IOException; import java.net.InetAddress; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Random; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern;
@@ -130,7 +132,7 @@ public class InstallerServiceImpl implements InstallerService { HashMap<String, String> serverProperties = preInstall();
// make sure the data is valid - verifyDataFormats(serverProperties); + ServerProperties.validate(serverProperties);
// checks to make sure we can connect to the DB final String dbUrl = serverProperties.get(ServerProperties.PROP_DATABASE_CONNECTION_URL); @@ -294,6 +296,13 @@ public class InstallerServiceImpl implements InstallerService { serverProperties.put(ServerProperties.PROP_STORAGE_PASSWORD, encodedStoragePassword); }
+ // After manipulating the server props, sanity check them + Set<String> additionalProperties = new HashSet<String>(); + additionalProperties.add(ServerProperties.PROP_MGMT_USER_PASSWORD); + additionalProperties.add(ServerProperties.PROP_STORAGE_USERNAME); + additionalProperties.add(ServerProperties.PROP_STORAGE_PASSWORD); + ServerProperties.validate(serverProperties, additionalProperties); + prepareDatabase(serverProperties, serverDetails, existingSchemaOption);
// perform stuff that has to get done via the JBossAS management client @@ -354,9 +363,6 @@ public class InstallerServiceImpl implements InstallerService { public void prepareDatabase(HashMap<String, String> serverProperties, ServerDetails serverDetails, String existingSchemaOption) throws Exception {
- // since we are going to write out the properties file, we need to make sure the properties are valid - verifyDataFormats(serverProperties); - // if we are in auto-install mode, ignore the server details passed in and build our own using the given server properties // if not in auto-install mode, make sure user gave us the server details that we will need final boolean autoInstallMode = ServerInstallUtil.isAutoinstallEnabled(serverProperties); @@ -653,45 +659,6 @@ public class InstallerServiceImpl implements InstallerService { }
/** - * Makes sure the data is at least in the correct format (booleans are true/false, integers are valid numbers). - * - * @param serverProperties the server properties to check for correctness - * - * @throws Exception if the data was invalid - */ - private void verifyDataFormats(HashMap<String, String> serverProperties) throws Exception { - final StringBuilder dataErrors = new StringBuilder(); - for (Map.Entry<String, String> entry : serverProperties.entrySet()) { - final String name = entry.getKey(); - if (ServerProperties.BOOLEAN_PROPERTIES.contains(name)) { - final String newValue = entry.getValue(); - if (!(newValue.equals("true") || newValue.equals("false"))) { - dataErrors.append("[" + name + "] must be 'true' or 'false' : [" + newValue + "]\n"); - } - } else if (ServerProperties.INTEGER_PROPERTIES.contains(name)) { - final String newValue = entry.getValue(); - try { - Integer.parseInt(newValue); - } catch (NumberFormatException e) { - if (ServerInstallUtil.isEmpty(newValue) && name.equals(ServerProperties.PROP_CONNECTOR_BIND_PORT)) { - // this is a special setting and is allowed to be empty - } else { - dataErrors.append("[" + name + "] must be a number : [" + newValue + "]\n"); - } - } - } else if (ServerProperties.STRING_PROPERTIES.contains(name)) { - final String newValue = entry.getValue(); - if (ServerInstallUtil.isEmpty(newValue)) { - dataErrors.append("[" + name + "] must be set to a valid string value\n"); - } - } - } - if (dataErrors.length() > 0) { - throw new Exception("Cannot install due to data errors:\n" + dataErrors.toString()); - } - } - - /** * Save the given properties to the server's .properties file. * * Note that this is private - it is not exposed to the installer UI. It should have no need to save @@ -701,6 +668,8 @@ public class InstallerServiceImpl implements InstallerService { * @throws Exception if failed to save the properties to the .properties file */ private void saveServerProperties(HashMap<String, String> serverProperties) throws Exception { + ServerProperties.validate(serverProperties); + final File serverPropertiesFile = getServerPropertiesFile(); final PropertiesFileUpdate propsFile = new PropertiesFileUpdate(serverPropertiesFile.getAbsolutePath());
diff --git a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java index 6ac264d..2233cea 100644 --- a/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java +++ b/modules/enterprise/server/installer/src/main/java/org/rhq/enterprise/server/installer/ServerProperties.java @@ -18,9 +18,16 @@ */ package org.rhq.enterprise.server.installer;
+import java.io.File; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Properties; import java.util.Set;
+import org.rhq.core.util.PropertiesFileUpdate; +import org.rhq.core.util.obfuscation.PicketBoxObfuscator; + /** * Settings found in the rhq-server.properties file that controls the startup configuration of the server. * @@ -125,24 +132,20 @@ public class ServerProperties { public static final String PROP_STORAGE_GOSSIP_PORT = "rhq.storage.gossip-port";
// this list contains all the properties that are to have boolean values (true | false) - public static final Set<String> BOOLEAN_PROPERTIES; + private static final Set<String> BOOLEAN_PROPERTIES; static { BOOLEAN_PROPERTIES = new HashSet<String>(); - BOOLEAN_PROPERTIES.add(PROP_SECURITY_CLIENT_SERVER_AUTH_MODE_ENABLED); - BOOLEAN_PROPERTIES.add(PROP_MM_AT_START); - BOOLEAN_PROPERTIES.add(PROP_AUTOINSTALL_ENABLE); BOOLEAN_PROPERTIES.add(PROP_AGENT_MULTICAST_DETECTOR_ENABLED); + BOOLEAN_PROPERTIES.add(PROP_AUTOINSTALL_ENABLE); + BOOLEAN_PROPERTIES.add(PROP_MM_AT_START); + BOOLEAN_PROPERTIES.add(PROP_SECURITY_CLIENT_SERVER_AUTH_MODE_ENABLED); }
// this list contains all the properties that are to have integer values - public static final Set<String> INTEGER_PROPERTIES; + private static final Set<String> INTEGER_PROPERTIES; static { INTEGER_PROPERTIES = new HashSet<String>(); - INTEGER_PROPERTIES.add(PROP_WEB_HTTP_PORT); - INTEGER_PROPERTIES.add(PROP_WEB_HTTPS_PORT); - INTEGER_PROPERTIES.add(PROP_CONNECTOR_BIND_PORT); - INTEGER_PROPERTIES.add(PROP_EMAIL_SMTP_PORT); - INTEGER_PROPERTIES.add(PROP_OPERATION_TIMEOUT); + INTEGER_PROPERTIES.add(PROP_AGENT_MULTICAST_DETECTOR_PORT); INTEGER_PROPERTIES.add(PROP_CONCURRENCY_LIMIT_AVAIL_REPORT); INTEGER_PROPERTIES.add(PROP_CONCURRENCY_LIMIT_CONTENT_DOWNLOAD); INTEGER_PROPERTIES.add(PROP_CONCURRENCY_LIMIT_CONTENT_REPORT); @@ -152,16 +155,50 @@ public class ServerProperties { INTEGER_PROPERTIES.add(PROP_CONCURRENCY_LIMIT_MEAS_REPORT); INTEGER_PROPERTIES.add(PROP_CONCURRENCY_LIMIT_MEASSCHED_REQ); INTEGER_PROPERTIES.add(PROP_CONCURRENCY_LIMIT_WEBCONNS); - INTEGER_PROPERTIES.add(PROP_AGENT_MULTICAST_DETECTOR_PORT); + INTEGER_PROPERTIES.add(PROP_CONNECTOR_BIND_PORT); + INTEGER_PROPERTIES.add(PROP_DATABASE_PORT); + INTEGER_PROPERTIES.add(PROP_EMAIL_SMTP_PORT); + INTEGER_PROPERTIES.add(PROP_OPERATION_TIMEOUT); INTEGER_PROPERTIES.add(PROP_STORAGE_CQL_PORT); INTEGER_PROPERTIES.add(PROP_STORAGE_GOSSIP_PORT); + INTEGER_PROPERTIES.add(PROP_WEB_HTTP_PORT); + INTEGER_PROPERTIES.add(PROP_WEB_HTTPS_PORT); }
// this list contains all the properties that are to have non-empty string values - public static final Set<String> STRING_PROPERTIES; + private static final Set<String> STRING_PROPERTIES; static { STRING_PROPERTIES = new HashSet<String>(); + STRING_PROPERTIES.add(PROP_AUTOINSTALL_DATABASE); + STRING_PROPERTIES.add(PROP_DATABASE_TYPE); + STRING_PROPERTIES.add(PROP_DATABASE_CONNECTION_URL); + STRING_PROPERTIES.add(PROP_DATABASE_PASSWORD); + STRING_PROPERTIES.add(PROP_DATABASE_USERNAME); + STRING_PROPERTIES.add(PROP_DATABASE_SERVER_NAME); + STRING_PROPERTIES.add(PROP_DATABASE_DB_NAME); + STRING_PROPERTIES.add(PROP_DATABASE_HIBERNATE_DIALECT); + STRING_PROPERTIES.add(PROP_EMAIL_FROM_ADDRESS); + STRING_PROPERTIES.add(PROP_EMAIL_SMTP_HOST); STRING_PROPERTIES.add(PROP_JBOSS_BIND_ADDRESS); + STRING_PROPERTIES.add(PROP_QUARTZ_DRIVER_DELEGATE_CLASS); + STRING_PROPERTIES.add(PROP_QUARTZ_LOCK_HANDLER_CLASS); + STRING_PROPERTIES.add(PROP_QUARTZ_SELECT_WITH_LOCK_SQL); + } + + // this list contains all the STRING properties that are to have obfuscated values + private static final Set<String> OBFUSCATED_PROPERTIES; + static { + OBFUSCATED_PROPERTIES = new HashSet<String>(); + OBFUSCATED_PROPERTIES.add(PROP_DATABASE_PASSWORD); + OBFUSCATED_PROPERTIES.add(PROP_MGMT_USER_PASSWORD); + OBFUSCATED_PROPERTIES.add(PROP_STORAGE_PASSWORD); + } + + // this list contains all the non-STRING properties that can be unset when verified + private static final Set<String> OPTIONAL_PROPERTIES; + static { + OPTIONAL_PROPERTIES = new HashSet<String>(); + OPTIONAL_PROPERTIES.add(PROP_CONNECTOR_BIND_PORT); }
public static final Set<String> CLIENT_AUTH_MODES; @@ -191,4 +228,91 @@ public class ServerProperties { IBM_ALGOROTHM_SETTINGS.add(PROP_SECURITY_CLIENT_KEYSTORE_ALGORITHM); IBM_ALGOROTHM_SETTINGS.add(PROP_SECURITY_CLIENT_TRUSTSTORE_ALGORITHM); } -} \ No newline at end of file + + public static void validate(File serverPropertiesFile) throws Exception { + validate(serverPropertiesFile, null); + } + + /** + * @param serverPropertiesFile + * @param additionalProperties additional properties that should be set (present and not empty). can be null. + * @throws Exception + */ + public static void validate(File serverPropertiesFile, Set<String> additionalProperties) throws Exception { + if (!serverPropertiesFile.isFile()) { + throw new Exception("Properties file not found: [" + serverPropertiesFile.getAbsolutePath() + "]"); + } + + PropertiesFileUpdate pfu = new PropertiesFileUpdate(serverPropertiesFile); + Properties props = pfu.loadExistingProperties(); + final HashMap<String, String> map = new HashMap<String, String>(props.size()); + for (Object property : props.keySet()) { + map.put(property.toString(), props.getProperty(property.toString())); + } + + validate(map, additionalProperties); + } + + public static void validate(Map<String, String> serverProperties) throws Exception { + validate(serverProperties, null); + } + + /** + * @param serverProperties + * @param additionalProperties additional properties that should be set (present and not empty). can be null. + * @throws Exception + */ + public static void validate(Map<String, String> serverProperties, Set<String> additionalProperties) + throws Exception { + final StringBuilder dataErrors = new StringBuilder(); + + for (String name : ServerProperties.BOOLEAN_PROPERTIES) { + String val = serverProperties.get(name); + if (ServerInstallUtil.isEmpty(val) && OPTIONAL_PROPERTIES.contains(name)) { + continue; + } + if (!("true".equals(val) || "false".equals(val))) { + dataErrors.append("[" + name + "] must exist and be set 'true' or 'false' : [" + val + "]\n"); + } + } + + for (String name : ServerProperties.INTEGER_PROPERTIES) { + String val = serverProperties.get(name); + if (ServerInstallUtil.isEmpty(val) && OPTIONAL_PROPERTIES.contains(name)) { + continue; + } + try { + Integer.parseInt(val); + } catch (NumberFormatException e) { + dataErrors.append("[" + name + "] must exist and be set to a number : [" + val + "]\n"); + } + } + + Set<String> requiredStringProperties = new HashSet<String>(); + requiredStringProperties.addAll(STRING_PROPERTIES); + if (null != additionalProperties) { + requiredStringProperties.addAll(additionalProperties); + } + for (String name : requiredStringProperties) { + String val = serverProperties.get(name); + if (ServerInstallUtil.isEmpty(val)) { + dataErrors.append("[" + name + "] must exist and be set to a valid string value\n"); + + } else if (ServerProperties.OBFUSCATED_PROPERTIES.contains(name)) { + try { + PicketBoxObfuscator.decode(val); + } catch (Throwable e) { + dataErrors + .append("[" + + name + + "] must be encoded for security reasons. The value is not valid, perhaps it is set to a plain text value? : [" + + val + "]\n"); + } + } + } + + if (dataErrors.length() > 0) { + throw new Exception("Validation errors:\n" + dataErrors.toString()); + } + } +} diff --git a/modules/enterprise/server/installer/src/main/resources/logging.properties b/modules/enterprise/server/installer/src/main/resources/logging.properties index 0affd97..6cd57d1 100644 --- a/modules/enterprise/server/installer/src/main/resources/logging.properties +++ b/modules/enterprise/server/installer/src/main/resources/logging.properties @@ -2,20 +2,20 @@ loggers=org.rhq
# Root logger level -logger.level=${rhq.server.installer.loglevel:DEBUG} +logger.level=${rhq.server.installer.loglevel:INFO} # Root logger handlers logger.handlers=FILE,CONSOLE
# Console handler configuration handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler handler.CONSOLE.properties=autoFlush -handler.CONSOLE.level=${rhq.server.installer.loglevel:DEBUG} +handler.CONSOLE.level=${rhq.server.installer.loglevel:INFO} handler.CONSOLE.autoFlush=true handler.CONSOLE.formatter=PATTERN
# File handler configuration handler.FILE=org.jboss.logmanager.handlers.FileHandler -handler.FILE.level=${rhq.server.installer.loglevel:DEBUG} +handler.FILE.level=${rhq.server.installer.loglevel:INFO} handler.FILE.properties=autoFlush,append,fileName handler.FILE.autoFlush=true handler.FILE.append=true diff --git a/modules/enterprise/server/server-control/pom.xml b/modules/enterprise/server/server-control/pom.xml index 9f53404..b4302f0 100644 --- a/modules/enterprise/server/server-control/pom.xml +++ b/modules/enterprise/server/server-control/pom.xml @@ -28,6 +28,18 @@
<dependency> <groupId>${project.groupId}</groupId> + <artifactId>rhq-installer-util</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>rhq-cassandra-installer</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>rhq-jboss-as-dmr-client</artifactId> <version>${project.version}</version> </dependency> @@ -105,6 +117,16 @@ <version>${project.version}</version> </artifactItem> <artifactItem> + <groupId>${project.groupId}</groupId> + <artifactId>rhq-installer-util</artifactId> + <version>${project.version}</version> + </artifactItem> + <artifactItem> + <groupId>${project.groupId}</groupId> + <artifactId>rhq-cassandra-installer</artifactId> + <version>${project.version}</version> + </artifactItem> + <artifactItem> <groupId>org.rhq</groupId> <artifactId>rhq-jboss-as-dmr-client</artifactId> </artifactItem> diff --git a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java index 2d8d54c..7ad3b62 100644 --- a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java +++ b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java @@ -22,18 +22,24 @@ * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ - package org.rhq.server.control;
+import java.io.Console; import java.io.File; import java.util.LinkedList; import java.util.List; +import java.util.Properties;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
+import org.rhq.core.util.PropertiesFileUpdate; +import org.rhq.core.util.StringUtil; import org.rhq.core.util.exception.ThrowableUtil; +import org.rhq.core.util.obfuscation.Obfuscator; +import org.rhq.enterprise.server.installer.ServerProperties; +import org.rhq.storage.installer.StorageProperty;
/** * @author John Sanda @@ -67,21 +73,7 @@ public class RHQControl { String commandName = findCommand(commands, args); command = commands.get(commandName);
- // perform any up front validation we can at this point. Not that after this point we - // lose stdin due to the use of ProcessExecutions. - if ("install".equalsIgnoreCase(command.getName())) { - File serverProperties = new File("bin/rhq-server.properties"); - File storageProperties = new File("bin/rhq-storage.properties"); - - if (!serverProperties.isFile()) { - throw new RHQControlException("Missing required configuration file, can not continue: [" - + serverProperties.getAbsolutePath() + "]"); - } - if (!storageProperties.isFile()) { - throw new RHQControlException("Missing required configuration file, can not continue: [" - + storageProperties.getAbsolutePath() + "]"); - } - } + validateInstallCommand(command);
// in case the installer gets killed, prepare the shutdown hook to try the undo abortHook.setCommand(command); @@ -93,11 +85,18 @@ public class RHQControl { } catch (UsageException e) { printUsage(); } catch (RHQControlException e) { - log.error(e.getMessage() + " [Cause: " + e.getCause() + "]", e); undo = true; + + Throwable rootCause = ThrowableUtil.getRootCause(e); + // Only show the messy stack trace if we're in debug mode. Otherwise keep it cleaner for the user... + if (log.isDebugEnabled()) { + log.error(rootCause.getMessage(), rootCause); + } else { + log.error(rootCause.getMessage()); + } } catch (Throwable t) { - log.error(t); undo = true; + log.error(t); } finally { abortHook.setCommand(null); Runtime.getRuntime().removeShutdownHook(abortHook); @@ -119,6 +118,97 @@ public class RHQControl { return; }
+ private void validateInstallCommand(ControlCommand command) { + if (!"install".equalsIgnoreCase(command.getName())) { + return; + } + + // perform any up front validation we can at this point. Not that after this point we + // lose stdin due to the use of ProcessExecutions. + File serverPropertiesFile = new File("bin/rhq-server.properties"); + File storagePropertiesFile = new File("bin/rhq-storage.properties"); + + if (!serverPropertiesFile.isFile()) { + throw new RHQControlException( + "The required rhq-server.properties file can not be found in the expected location [" + + serverPropertiesFile.getAbsolutePath() + "]. Installation is canceled."); + } + + if (!storagePropertiesFile.isFile()) { + throw new RHQControlException( + "The required rhq-storage.properties file can not be found in the expected location [" + + storagePropertiesFile.getAbsolutePath() + "]. Installation is canceled."); + } + + // Prompt for critical required values, if not yet set. + try { + PropertiesFileUpdate pfu = new PropertiesFileUpdate(serverPropertiesFile); + Properties props = pfu.loadExistingProperties(); + + promptForProperty(pfu, props, serverPropertiesFile.getName(), ServerProperties.PROP_JBOSS_BIND_ADDRESS, + false); + promptForProperty(pfu, props, serverPropertiesFile.getName(), ServerProperties.PROP_DATABASE_PASSWORD, true); + + } catch (Throwable t) { + throw new RHQControlException("The rhq-server.properties file is not valid. Installation is canceled: " + + t.getMessage()); + } + + // Now, validate the property settings + try { + ServerProperties.validate(serverPropertiesFile); + + } catch (Throwable t) { + throw new RHQControlException("The rhq-server.properties file is not valid. Installation is canceled: " + + t.getMessage()); + } + + try { + StorageProperty.validate(storagePropertiesFile); + + } catch (Throwable t) { + throw new RHQControlException("The rhq-storage.properties file is not valid. Installation is canceled: " + + t.getMessage()); + } + } + + private void promptForProperty(PropertiesFileUpdate pfu, Properties props, String propertiesFileName, + String propertyName, boolean encode) throws Exception { + + String propertyValue = props.getProperty(propertyName); + if (StringUtil.isBlank(propertyValue)) { + + // prompt for the property value + Console console = System.console(); + console.format("\nThe [%s] property is required but not set in [%s].\n", propertyName, propertiesFileName); + console.format("Do you want to set [%s] value now?\n", propertyName); + String response = ""; + while (!(response.startsWith("n") || response.startsWith("y"))) { + response = String.valueOf(console.readLine("%s", "yes|no: ")).toLowerCase(); + } + if (response.startsWith("n")) { + throw new RHQControlException("Please update the [" + propertiesFileName + "] file as required."); + } + + do { + propertyValue = ""; + while (StringUtil.isBlank(propertyValue)) { + propertyValue = String.valueOf(console.readLine("%s", propertyName + + ((encode ? " (enter as plain text): " : ": ")))); + } + + console.format("Is [" + propertyValue + "] correct?\n"); + response = ""; + while (!(response.startsWith("n") || response.startsWith("y"))) { + response = String.valueOf(console.readLine("%s", "yes|no: ")).toLowerCase(); + } + } while (response.startsWith("n")); + + props.setProperty(propertyName, encode ? Obfuscator.encode(propertyValue) : propertyValue); + pfu.update(props); + } + } + private String findCommand(Commands commands, String[] args) throws RHQControlException { List<String> commandNames = new LinkedList<String>(); for (String arg : args) { @@ -153,7 +243,12 @@ public class RHQControl { System.exit(0); } catch (RHQControlException e) { Throwable rootCause = ThrowableUtil.getRootCause(e); - control.log.error("There was an unxpected error: " + rootCause.getMessage(), rootCause); + // Only show the messy stack trace if we're in debug mode. Otherwise keep it cleaner for the user... + if (control.log.isDebugEnabled()) { + control.log.error("There was an unexpected error: " + rootCause.getMessage(), rootCause); + } else { + control.log.error("There was an unexpected error: " + rootCause.getMessage()); + } System.exit(1); } } diff --git a/modules/enterprise/server/server-control/src/main/resources/logging.properties b/modules/enterprise/server/server-control/src/main/resources/logging.properties index 9f69ca9..fefc9f6 100644 --- a/modules/enterprise/server/server-control/src/main/resources/logging.properties +++ b/modules/enterprise/server/server-control/src/main/resources/logging.properties @@ -2,20 +2,20 @@ loggers=org.rhq
# Root logger level -logger.level=${rhq.control.loglevel:DEBUG} +logger.level=${rhq.control.loglevel:INFO} # Root logger handlers logger.handlers=FILE,CONSOLE
# Console handler configuration handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler handler.CONSOLE.properties=autoFlush -handler.CONSOLE.level=${rhq.control.loglevel:DEBUG} +handler.CONSOLE.level=${rhq.control.loglevel:INFO} handler.CONSOLE.autoFlush=true handler.CONSOLE.formatter=PATTERN
# File handler configuration handler.FILE=org.jboss.logmanager.handlers.FileHandler -handler.FILE.level=${rhq.control.loglevel:DEBUG} +handler.FILE.level=${rhq.control.loglevel:INFO} handler.FILE.properties=autoFlush,append,fileName handler.FILE.autoFlush=true handler.FILE.append=false diff --git a/modules/enterprise/server/server-control/src/main/resources/module/main/module.xml b/modules/enterprise/server/server-control/src/main/resources/module/main/module.xml index 0cba6f7..1489d4c 100644 --- a/modules/enterprise/server/server-control/src/main/resources/module/main/module.xml +++ b/modules/enterprise/server/server-control/src/main/resources/module/main/module.xml @@ -1,26 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="${moduleName}"> - <main-class name="org.rhq.server.control.RHQControl" /> + <main-class name="org.rhq.server.control.RHQControl"/>
<resources> - <resource-root path="${project.build.finalName}.jar" /> - <resource-root path="rhq-core-util-${project.version}.jar" /> - <resource-root path="rhq-jboss-as-dmr-client-${project.version}.jar" /> + <resource-root path="${project.build.finalName}.jar"/> + <resource-root path="rhq-core-util-${project.version}.jar"/> + <resource-root path="rhq-jboss-as-dmr-client-${project.version}.jar"/> + <resource-root path="rhq-installer-util-${project.version}.jar"/> + <resource-root path="rhq-cassandra-installer-${project.version}.jar"/> </resources>
<dependencies> - <module name="javax.api" /> - <module name="org.apache.commons.logging" /> - <module name="org.apache.commons.cli" /> - <module name="org.apache.commons.exec" /> - <module name="org.apache.commons.configuration" /> - <module name="org.apache.log4j" /> - <module name="sun.jdk" /> - <module name="org.jboss.as.controller-client" /> - <module name="org.jboss.dmr" /> - <module name="org.jboss.logmanager" services="import" /> - <module name="org.jboss.logging" /> + <module name="javax.api"/> + <module name="org.apache.commons.logging"/> + <module name="org.apache.commons.cli"/> + <module name="org.apache.commons.exec"/> + <module name="org.apache.commons.configuration"/> + <module name="org.apache.log4j"/> + <module name="sun.jdk"/> + <module name="org.jboss.as.controller-client"/> + <module name="org.jboss.dmr"/> + <module name="org.jboss.logmanager" services="import"/> + <module name="org.jboss.logging"/> <module name="org.picketbox"/> </dependencies> </module>