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(a)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(a)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(a)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>