# HG changeset patch # User Severin Gehwolf # Date 1356095946 -3600 # Node ID 40be72a1345c5dec7ee4281698d3c99292a9cd1c # Parent 5a2d3c43b55193ff330ef087627e9a76ed751433 Add SSL (option) to storage command. This is the first step towards adding TLS to mongo<-->agent|client|webservice communication. It adds appropriate options to the mongod command if thermostat is so configured. In order to test this better, I've refactored MongoProcessRunner a bit. Also, DBStartupConfiguration does the parsing of the db.properties file now. As such it's also easier to test. Tests have been added for it too. Finally, I've renamed the c.r.t.agent.cli.db package to c.r.t.agent.cli.impl.db to better reflect in the package name that it is an internal package. Note that you'll need to have a mongod available on your system which understands --ssl* options in order to be able to fire mongod up with SSL enabled. These options are only added if appropriate config is in place in db.properties. Since it defaults to false, it should be OK to be pushed now without breaking existing behaviour. What comes next is adding support on agent/client/webservice side so that they can talk SSL over the mongodb channel as well. Reviewed-by: vanaltj, rkennke Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-December/004940.html PR1243 diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/pom.xml --- a/agent/cli/pom.xml Tue Jan 08 19:22:32 2013 +0100 +++ b/agent/cli/pom.xml Fri Dec 21 14:19:06 2012 +0100 @@ -106,7 +106,7 @@ com.redhat.thermostat.agent.cli.impl, com.redhat.thermostat.agent.cli.impl.locale, - com.redhat.thermostat.agent.cli.db, + com.redhat.thermostat.agent.cli.impl.db, <_nouses>true diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBConfig.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBConfig.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import com.redhat.thermostat.agent.cli.impl.StorageCommand; - -/** - * Set of configuration option that the {@link StorageCommand} understands. - */ -public enum DBConfig { - - BIND, - PORT, - -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBOptionParser.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBOptionParser.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.config.ThermostatOptionParser; -import com.redhat.thermostat.common.locale.Translate; -import com.redhat.thermostat.common.tools.ApplicationState; - -public class DBOptionParser implements ThermostatOptionParser { - - private static final Translate translator = LocaleResources.createLocalizer(); - - private boolean quiet; - - private DBStartupConfiguration configuration; - - private Arguments args; - - private DBArgs serviceAction; - - private boolean dryRun; - - public DBOptionParser(DBStartupConfiguration configuration, Arguments args) { - this.args = args; - this.configuration = configuration; - } - - @Override - public void parse() throws InvalidConfigurationException { - - if (args.hasArgument(DBArgs.START.option)) { - serviceAction = DBArgs.START; - } else if (args.hasArgument(DBArgs.STOP.option)) { - serviceAction = DBArgs.STOP; - } else { - throw new InvalidConfigurationException(translator.localize(LocaleResources.COMMAND_STORAGE_ARGUMENT_REQUIRED)); - } - - if (args.hasArgument(DBArgs.DRY.option)) { - dryRun = true; - } - - if (args.hasArgument(DBArgs.QUIET.option)) { - quiet = true; - } - - // leave at the end, since it depends on the previous settings - String address = configuration.getBindIP(); - long port = configuration.getPort(); - configuration.setDBConnectionString("mongodb://" + address + ":" + port); - } - - public boolean isDryRun() { - return dryRun; - } - - public ApplicationState getAction() { - return serviceAction.state; - } - - static enum DBArgs { - - DRY("dryRun", ApplicationState.NONE), - - HELP("help", ApplicationState.HELP), - - START("start", ApplicationState.START), - STOP("stop", ApplicationState.STOP), - - QUIET("quiet", ApplicationState.NONE); - - private String option; - private ApplicationState state; - - DBArgs(String option, ApplicationState state) { - this.option = option; - this.state = state; - } - } - - public boolean isQuiet() { - return quiet; - } -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBStartupConfiguration.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBStartupConfiguration.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.common.config.ConfigUtils; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.storage.config.StartupConfiguration; - -public class DBStartupConfiguration implements StartupConfiguration { - - private File dbPath; - private File logFile; - private File pidFile; - - private long localPort; - - private String dbConnectionString; - - private String ip; - - public DBStartupConfiguration() throws InvalidConfigurationException { - dbPath = ConfigUtils.getStorageDirectory(); - logFile = ConfigUtils.getStorageLogFile(); - pidFile = ConfigUtils.getStoragePidFile(); - } - - public File getDBPath() { - return dbPath; - } - - public File getLogFile() { - return logFile; - } - - public File getPidFile() { - return pidFile; - } - - public void setPort(long localPort) { - this.localPort = localPort; - } - - public long getPort() { - return localPort; - } - - void setDBConnectionString(String dbConnectionString) { - this.dbConnectionString = dbConnectionString; - } - - @Override - public String getDBConnectionString() { - return dbConnectionString; - } - - public void setBindIP(String ip) { - this.ip = ip; - } - - public String getBindIP() { - return ip; - } -} \ No newline at end of file diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/MongoProcessRunner.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/MongoProcessRunner.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.locale.Translate; -import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.utils.LoggedExternalProcess; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.service.process.UnixProcessUtilities; - -public class MongoProcessRunner { - - private static final Translate translator = LocaleResources.createLocalizer(); - private static final Logger logger = LoggingUtils.getLogger(MongoProcessRunner.class); - - private static final String MONGO_PROCESS = "mongod"; - - private static final String [] MONGO_BASIC_ARGS = { - "mongod", "--quiet", "--fork", "--auth", "--nohttpinterface", "--bind_ip" - }; - - private static final String [] MONGO_SHUTDOWN_ARGS = { - "kill", "-s", "TERM" - }; - - private static final String NO_JOURNAL_ARGUMENT = "--nojournal"; - private static final String NO_JOURNAL_FIRST_VERSION = "1.9.2"; - - private DBStartupConfiguration configuration; - private boolean isQuiet; - - public MongoProcessRunner(DBStartupConfiguration configuration, boolean quiet) { - this.configuration = configuration; - this.isQuiet = quiet; - } - - private String getPid() { - - String pid = null; - - File pidfile = configuration.getPidFile(); - Charset charset = Charset.defaultCharset(); - if (pidfile.exists()) { - try (BufferedReader reader = Files.newBufferedReader(pidfile.toPath(), charset)) { - pid = reader.readLine(); - if (pid == null || pid.isEmpty()) { - pid = null; - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Exception while reading pid file", ex); - pid = null; - } - } - - return pid; - } - - public void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { - - List commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS)); - commands.add(getPid()); - - LoggedExternalProcess process = new LoggedExternalProcess(commands); - int status = process.runAndReturnResult(); - if (status == 0) { - display(translator.localize(LocaleResources.SERVER_SHUTDOWN_COMPLETE, configuration.getDBPath().toString())); - display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); - - } else { - - String message = translator.localize(LocaleResources.CANNOT_SHUTDOWN_SERVER, - configuration.getDBPath().toString(), - String.valueOf(status)); - display(message); - throw new StorageStopException(configuration.getDBPath(), status, message); - } - } - - private boolean checkExistingProcess() { - String pid = getPid(); - if (pid == null) - return false; - - String processName = UnixProcessUtilities.getInstance().getProcessName(getPid()); - // TODO: check if we want mongos or mongod from the configs - return processName != null && processName.equalsIgnoreCase(MONGO_PROCESS); - } - - public void startService() throws IOException, InterruptedException, ApplicationException { - - String pid = getPid(); - if (pid != null) { - String message = null; - if (!checkExistingProcess()) { - message = translator.localize(LocaleResources.STALE_PID_FILE_NO_MATCHING_PROCESS, configuration.getPidFile().toString(), MONGO_PROCESS); - // Mongo didn't remove its PID file? Work around the issue. Log - // the event, remove the stale pid file and continue. - logger.log(Level.WARNING, message); - try { - Files.delete(configuration.getPidFile().toPath()); - } catch (IOException benign) { - // ignore this benign error - } - } else { - message = translator.localize(LocaleResources.STORAGE_ALREADY_RUNNING_WITH_PID, String.valueOf(pid)); - display(message); - throw new StorageAlreadyRunningException(Integer.valueOf(pid), message); - } - } - - List commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS)); - String dbVersion = getDBVersion(); - if (dbVersion.compareTo(NO_JOURNAL_FIRST_VERSION) >= 0) { - commands.add(1, NO_JOURNAL_ARGUMENT); - } - - // check that the db directory exist - display(translator.localize(LocaleResources.STARTING_STORAGE_SERVER)); - - commands.add(configuration.getBindIP()); - - commands.add("--dbpath"); - commands.add(configuration.getDBPath().getCanonicalPath()); - - commands.add("--logpath"); - commands.add(configuration.getLogFile().getCanonicalPath()); - - commands.add("--pidfilepath"); - commands.add(configuration.getPidFile().getCanonicalPath()); - - commands.add("--port"); - commands.add(Long.toString(configuration.getPort())); - - LoggedExternalProcess process = new LoggedExternalProcess(commands); - int status = -1; - try { - status = process.runAndReturnResult(); - } catch (ApplicationException ae) { - String message = translator.localize(LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); - display(message); - throw ae; - } - - Thread.sleep(500); - - if (status == 0) { - pid = getPid(); - if (pid == null) status = -1; - } - - if (status == 0) { - display(translator.localize(LocaleResources.SERVER_LISTENING_ON, configuration.getDBConnectionString())); - display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); - display(translator.localize(LocaleResources.PID_IS, String.valueOf(pid))); - - } else { - - String message = translator.localize(LocaleResources.CANNOT_START_SERVER, - configuration.getDBPath().toString(), - String.valueOf(status)); - display(message); - throw new StorageStartException(configuration.getDBPath(), status, message); - } - } - - private String getDBVersion() throws IOException { - Process process; - try { - process = new ProcessBuilder(Arrays.asList("mongod", "--version")) - .start(); - } catch (IOException e) { - String message = translator.localize( - LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); - display(message); - throw e; - } - InputStream out = process.getInputStream(); - InputStreamReader reader = new InputStreamReader(out); - BufferedReader bufReader = new BufferedReader(reader); - String firstLine = bufReader.readLine(); - int commaIdx = firstLine.indexOf(",", 12); - String versionString = firstLine.substring(12, commaIdx); - return versionString; - } - - private void display(String message) { - if (!isQuiet) { - System.out.println(message); - } - } -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageAlreadyRunningException.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageAlreadyRunningException.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StorageAlreadyRunningException extends ApplicationException { - - private final int storagePid; - - public StorageAlreadyRunningException(int pid, String message) { - super(message); - storagePid = pid; - } - - public int getStoragePid() { - return storagePid; - } - -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStartException.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStartException.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StorageStartException extends ApplicationException { - - private final File dbFile; - private final int status; - - public StorageStartException(File dbPath, int status, String message) { - super(message); - this.dbFile = dbPath; - this.status = status; - } - - public File getDbPath() { - return dbFile; - } - - public int getStatus() { - return status; - } - -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStopException.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStopException.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StorageStopException extends ApplicationException { - - private final File dbConfig; - private final int status; - - public StorageStopException(File dbConfig, int status, String message) { - super(message); - this.dbConfig = dbConfig; - this.status = status; - } - - public File getDbConfig() { - return dbConfig; - } - - public int getStatus() { - return status; - } - -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java Tue Jan 08 19:22:32 2013 +0100 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java Fri Dec 21 14:19:06 2012 +0100 @@ -41,6 +41,7 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import com.redhat.thermostat.agent.cli.impl.db.StorageCommand; import com.redhat.thermostat.common.cli.CommandRegistry; import com.redhat.thermostat.common.cli.CommandRegistryImpl; diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java Tue Jan 08 19:22:32 2013 +0100 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java Fri Dec 21 14:19:06 2012 +0100 @@ -140,7 +140,9 @@ connection.connect(); logger.fine("Connecting to storage..."); + @SuppressWarnings("rawtypes") ServiceReference configServiceRef = bundleContext.getServiceReference(ConfigurationServer.class.getName()); + @SuppressWarnings("unchecked") final ConfigurationServer configServer = (ConfigurationServer) bundleContext.getService(configServiceRef); configServer.startListening(configuration.getConfigListenAddress()); diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java Tue Jan 08 19:22:32 2013 +0100 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java Fri Dec 21 14:19:06 2012 +0100 @@ -40,7 +40,8 @@ import java.util.List; import java.util.concurrent.Semaphore; -import com.redhat.thermostat.agent.cli.db.StorageAlreadyRunningException; +import com.redhat.thermostat.agent.cli.impl.db.StorageAlreadyRunningException; +import com.redhat.thermostat.agent.cli.impl.db.StorageCommand; import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/StorageCommand.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/StorageCommand.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.impl; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - -import com.redhat.thermostat.agent.cli.db.DBConfig; -import com.redhat.thermostat.agent.cli.db.DBOptionParser; -import com.redhat.thermostat.agent.cli.db.DBStartupConfiguration; -import com.redhat.thermostat.agent.cli.db.MongoProcessRunner; -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.config.ConfigUtils; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.common.tools.BasicCommand; - -public class StorageCommand extends BasicCommand { - - private static final String NAME = "storage"; - - private DBStartupConfiguration configuration; - private DBOptionParser parser; - - private MongoProcessRunner runner; - - private void parseArguments(Arguments args) throws InvalidConfigurationException { - - this.configuration = new DBStartupConfiguration(); - // configs, read everything that is in the configs - File propertyFile = ConfigUtils.getStorageConfigurationFile(); - if (!propertyFile.exists()) { - throw new InvalidConfigurationException("can't access database configuration file " + - propertyFile); - } - readAndSetProperties(propertyFile); - - parser = new DBOptionParser(configuration, args); - parser.parse(); - } - - @Override - public void run(CommandContext ctx) throws CommandException { - - try { - parseArgsAndRun(ctx); - } catch (InvalidConfigurationException e) { - throw new CommandException(e); - } - } - - private void parseArgsAndRun(CommandContext ctx) - throws InvalidConfigurationException { - parseArguments(ctx.getArguments()); - - // dry run means we don't do anything at all - if (parser.isDryRun()) return; - - runner = createRunner(); - try { - switch (parser.getAction()) { - case START: - startService(); - break; - case STOP: - stopService(); - break; - default: - break; - } - getNotifier().fireAction(ApplicationState.SUCCESS); - } catch (Exception e) { - getNotifier().fireAction(ApplicationState.FAIL, e); - } - } - - private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException { - - Properties properties = new Properties(); - try { - properties.load(new FileInputStream(propertyFile)); - - } catch (IOException e) { - throw new InvalidConfigurationException(e); - } - - if (properties.containsKey(DBConfig.PORT.name())) { - String port = (String) properties.get(DBConfig.PORT.name()); - int localPort = Integer.parseInt(port); - configuration.setPort(localPort); - } else { - throw new InvalidConfigurationException(DBConfig.PORT + " property missing"); - } - - if (properties.containsKey(DBConfig.BIND.name())) { - String ip = (String) properties.get(DBConfig.BIND.name()); - configuration.setBindIP(ip); - } else { - throw new InvalidConfigurationException(DBConfig.BIND + " property missing"); - } - } - - private void startService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { - runner.startService(); - getNotifier().fireAction(ApplicationState.START); - } - - - private void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { - check(); - runner.stopService(); - getNotifier().fireAction(ApplicationState.STOP); - } - - MongoProcessRunner createRunner() { - return new MongoProcessRunner(configuration, parser.isQuiet()); - } - - private void check() throws InvalidConfigurationException { - if (!configuration.getDBPath().exists() || - !configuration.getLogFile().getParentFile().exists() || - !configuration.getPidFile().getParentFile().exists()) - { - throw new InvalidConfigurationException("database directories do not exist..."); - } - } - - @Override - public DBStartupConfiguration getConfiguration() { - return configuration; - } - - @Override - public String getName() { - return NAME; - } - -} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBConfig.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + + +/** + * Set of configuration options that the {@link StorageCommand} understands. + * Keys map to properties in $THERMOSTAT_HOME/storage/db.properties. + */ +public enum DBConfig { + + /** + * The bind IP address. + */ + BIND, + /** + * The port on which mongodb will be listening. + */ + PORT, + /** + * Weather or not to start mongodb with SSL enabled. + */ + SSL_ENABLE, + /** + * The PEM encoded SSL certificate + SSL key. + */ + SSL_PEM_FILE, + /** + * The passphrase for the encrypted SSL key. Only used if the private key was encrypted. + */ + SSL_KEY_PASSWORD, + +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBOptionParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBOptionParser.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,121 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.ThermostatOptionParser; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.common.tools.ApplicationState; + +public class DBOptionParser implements ThermostatOptionParser { + + private static final Translate translator = LocaleResources.createLocalizer(); + + private boolean quiet; + + private DBStartupConfiguration configuration; + + private Arguments args; + + private DBArgs serviceAction; + + private boolean dryRun; + + public DBOptionParser(DBStartupConfiguration configuration, Arguments args) { + this.args = args; + this.configuration = configuration; + } + + @Override + public void parse() throws InvalidConfigurationException { + + if (args.hasArgument(DBArgs.START.option)) { + serviceAction = DBArgs.START; + } else if (args.hasArgument(DBArgs.STOP.option)) { + serviceAction = DBArgs.STOP; + } else { + throw new InvalidConfigurationException(translator.localize(LocaleResources.COMMAND_STORAGE_ARGUMENT_REQUIRED)); + } + + if (args.hasArgument(DBArgs.DRY.option)) { + dryRun = true; + } + + if (args.hasArgument(DBArgs.QUIET.option)) { + quiet = true; + } + + // leave at the end, since it depends on the previous settings + String address = configuration.getBindIP(); + long port = configuration.getPort(); + configuration.setDBConnectionString("mongodb://" + address + ":" + port); + } + + public boolean isDryRun() { + return dryRun; + } + + public ApplicationState getAction() { + return serviceAction.state; + } + + static enum DBArgs { + + DRY("dryRun", ApplicationState.NONE), + + HELP("help", ApplicationState.HELP), + + START("start", ApplicationState.START), + STOP("stop", ApplicationState.STOP), + + QUIET("quiet", ApplicationState.NONE); + + private String option; + private ApplicationState state; + + DBArgs(String option, ApplicationState state) { + this.option = option; + this.state = state; + } + } + + public boolean isQuiet() { + return quiet; + } +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfiguration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfiguration.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,179 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.storage.config.StartupConfiguration; + +public class DBStartupConfiguration implements StartupConfiguration { + + private File dbPath; + private File logFile; + private File pidFile; + private boolean sslEnabled = false; + private File sslPemFile; + private String sslKeyPassphrase; + + private long localPort; + + private String dbConnectionString; + + private String ip; + + public DBStartupConfiguration(File properties, File dbPath, File logFile, + File pidFile) throws InvalidConfigurationException { + this.dbPath = dbPath; + this.logFile = logFile; + this.pidFile = pidFile; + readAndSetProperties(properties); + } + + public File getDBPath() { + return dbPath; + } + + public File getLogFile() { + return logFile; + } + + public File getPidFile() { + return pidFile; + } + + public void setPort(long localPort) { + this.localPort = localPort; + } + + public long getPort() { + return localPort; + } + + void setDBConnectionString(String dbConnectionString) { + this.dbConnectionString = dbConnectionString; + } + + @Override + public String getDBConnectionString() { + return dbConnectionString; + } + + void setBindIP(String ip) { + this.ip = ip; + } + + public String getBindIP() { + return ip; + } + + public boolean isSslEnabled() { + return sslEnabled; + } + + void setSslEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + /** + * + * @return The file containing the server certificate and the private key in PEM format or null + * if nothing was specified in $THERMOSTAT_HOME/storage/db.properties. + */ + public File getSslPemFile() { + return sslPemFile; + } + + void setSslPemFile(File sslPemFile) { + this.sslPemFile = sslPemFile; + } + + /** + * + * @return The passphrase for the encrypted server key or null if config was + * not set. + */ + public String getSslKeyPassphrase() { + return sslKeyPassphrase; + } + + void setSslKeyPassphrase(String sslKeyPassphrase) { + this.sslKeyPassphrase = sslKeyPassphrase; + } + + private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException { + + Properties properties = new Properties(); + try { + properties.load(new FileInputStream(propertyFile)); + + } catch (IOException e) { + throw new InvalidConfigurationException(e); + } + + if (properties.containsKey(DBConfig.PORT.name())) { + String port = (String) properties.get(DBConfig.PORT.name()); + int localPort = Integer.parseInt(port); + setPort(localPort); + } else { + throw new InvalidConfigurationException(DBConfig.PORT + " property missing"); + } + + if (properties.containsKey(DBConfig.BIND.name())) { + String ip = (String) properties.get(DBConfig.BIND.name()); + setBindIP(ip); + } else { + throw new InvalidConfigurationException(DBConfig.BIND + " property missing"); + } + + // optional config + String enableSSLConfig = properties.getProperty(DBConfig.SSL_ENABLE.name()); + setSslEnabled(Boolean.parseBoolean(enableSSLConfig)); + + String pemFile = properties.getProperty(DBConfig.SSL_PEM_FILE.name()); + if (pemFile != null) { + setSslPemFile(new File(pemFile)); + } + + String keyPassPhrase = properties.getProperty(DBConfig.SSL_KEY_PASSWORD.name()); + setSslKeyPassphrase(keyPassPhrase); + + } +} \ No newline at end of file diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/MongoProcessRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/MongoProcessRunner.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,266 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.common.tools.ApplicationException; +import com.redhat.thermostat.common.utils.LoggedExternalProcess; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.service.process.UnixProcessUtilities; + +public class MongoProcessRunner { + + private static final Translate translator = LocaleResources.createLocalizer(); + private static final Logger logger = LoggingUtils.getLogger(MongoProcessRunner.class); + + private static final String MONGO_PROCESS = "mongod"; + + private static final String [] MONGO_BASIC_ARGS = { + "mongod", "--quiet", "--fork", "--auth", "--nohttpinterface", "--bind_ip" + }; + + private static final String [] MONGO_SHUTDOWN_ARGS = { + "kill", "-s", "TERM" + }; + + private static final String NO_JOURNAL_ARGUMENT = "--nojournal"; + private static final String NO_JOURNAL_FIRST_VERSION = "1.9.2"; + + private DBStartupConfiguration configuration; + private boolean isQuiet; + + public MongoProcessRunner(DBStartupConfiguration configuration, boolean quiet) { + this.configuration = configuration; + this.isQuiet = quiet; + } + + private String getPid() { + + String pid = null; + + File pidfile = configuration.getPidFile(); + Charset charset = Charset.defaultCharset(); + if (pidfile.exists()) { + try (BufferedReader reader = Files.newBufferedReader(pidfile.toPath(), charset)) { + pid = reader.readLine(); + if (pid == null || pid.isEmpty()) { + pid = null; + } + } catch (IOException ex) { + logger.log(Level.WARNING, "Exception while reading pid file", ex); + pid = null; + } + } + + return pid; + } + + public void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { + + List commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS)); + commands.add(getPid()); + + LoggedExternalProcess process = new LoggedExternalProcess(commands); + int status = process.runAndReturnResult(); + if (status == 0) { + display(translator.localize(LocaleResources.SERVER_SHUTDOWN_COMPLETE, configuration.getDBPath().toString())); + display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); + // all went well, make sure to remove pid file. + try { + Files.delete(configuration.getPidFile().toPath()); + } catch (IOException e) { + // ignore + } + } else { + + String message = translator.localize(LocaleResources.CANNOT_SHUTDOWN_SERVER, + configuration.getDBPath().toString(), + String.valueOf(status)); + display(message); + throw new StorageStopException(configuration.getDBPath(), status, message); + } + } + + private boolean checkExistingProcess() { + String pid = getPid(); + if (pid == null) + return false; + + String processName = UnixProcessUtilities.getInstance().getProcessName(getPid()); + // TODO: check if we want mongos or mongod from the configs + return processName != null && processName.equalsIgnoreCase(MONGO_PROCESS); + } + + public void startService() throws IOException, InterruptedException, + ApplicationException, InvalidConfigurationException { + + String pid = getPid(); + if (pid != null) { + String message = null; + if (!checkExistingProcess()) { + message = translator.localize(LocaleResources.STALE_PID_FILE_NO_MATCHING_PROCESS, configuration.getPidFile().toString(), MONGO_PROCESS); + // Mongo didn't remove its PID file? Work around the issue. Log + // the event, remove the stale pid file and continue. + logger.log(Level.WARNING, message); + try { + Files.delete(configuration.getPidFile().toPath()); + } catch (IOException benign) { + // ignore this benign error + } + } else { + message = translator.localize(LocaleResources.STORAGE_ALREADY_RUNNING_WITH_PID, String.valueOf(pid)); + display(message); + throw new StorageAlreadyRunningException(Integer.valueOf(pid), message); + } + } + + String dbVersion = getDBVersion(); + List commands = null; + commands = getStartupCommand(dbVersion); + + display(translator.localize(LocaleResources.STARTING_STORAGE_SERVER)); + + LoggedExternalProcess process = new LoggedExternalProcess(commands); + int status = -1; + try { + status = process.runAndReturnResult(); + } catch (ApplicationException ae) { + String message = translator.localize(LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); + display(message); + throw ae; + } + + Thread.sleep(500); + + if (status == 0) { + pid = getPid(); + if (pid == null) status = -1; + } + + if (status == 0) { + display(translator.localize(LocaleResources.SERVER_LISTENING_ON, configuration.getDBConnectionString())); + display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); + display(translator.localize(LocaleResources.PID_IS, String.valueOf(pid))); + + } else { + + String message = translator.localize(LocaleResources.CANNOT_START_SERVER, + configuration.getDBPath().toString(), + String.valueOf(status)); + display(message); + throw new StorageStartException(configuration.getDBPath(), status, message); + } + } + + List getStartupCommand(String dbVersion) throws IOException, InvalidConfigurationException { + List commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS)); + + if (dbVersion.compareTo(NO_JOURNAL_FIRST_VERSION) >= 0) { + commands.add(1, NO_JOURNAL_ARGUMENT); + } + commands.add(configuration.getBindIP()); + + commands.add("--dbpath"); + commands.add(configuration.getDBPath().getCanonicalPath()); + + commands.add("--logpath"); + commands.add(configuration.getLogFile().getCanonicalPath()); + + commands.add("--pidfilepath"); + commands.add(configuration.getPidFile().getCanonicalPath()); + + commands.add("--port"); + commands.add(Long.toString(configuration.getPort())); + + if (configuration.isSslEnabled()) { + // check for configuration which has a chance of working :) + if (configuration.getSslPemFile() == null) { + throw new InvalidConfigurationException("No SSL PEM file specified!"); + } else if (configuration.getSslKeyPassphrase() == null) { + throw new InvalidConfigurationException("No SSL key passphrase set!"); + } + commands.add("--sslOnNormalPorts"); + commands.add("--sslPEMKeyFile"); + commands.add(configuration.getSslPemFile().getCanonicalPath()); + commands.add("--sslPEMKeyPassword"); + commands.add(configuration.getSslKeyPassphrase()); + } + + return commands; + } + + private String getDBVersion() throws IOException { + Process process; + try { + process = new ProcessBuilder(Arrays.asList("mongod", "--version")) + .start(); + } catch (IOException e) { + String message = translator.localize( + LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); + display(message); + throw e; + } + InputStream out = process.getInputStream(); + InputStreamReader reader = new InputStreamReader(out); + BufferedReader bufReader = new BufferedReader(reader); + String firstLine = bufReader.readLine(); + int commaIdx = firstLine.indexOf(",", 12); + String versionString = firstLine.substring(12, commaIdx); + return versionString; + } + + private void display(String message) { + if (!isQuiet) { + System.out.println(message); + } + } +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StalePidFileException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StalePidFileException.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; + +import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StalePidFileException extends ApplicationException { + + private static final Translate translator = LocaleResources.createLocalizer(); + + private final File pidFile; + + public StalePidFileException(File pidFile) { + super(translator.localize(LocaleResources.STALE_PID_FILE, pidFile.toString())); + this.pidFile = pidFile; + } + + public File getPidFile() { + return pidFile; + } + +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageAlreadyRunningException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageAlreadyRunningException.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StorageAlreadyRunningException extends ApplicationException { + + private final int storagePid; + + public StorageAlreadyRunningException(int pid, String message) { + super(message); + storagePid = pid; + } + + public int getStoragePid() { + return storagePid; + } + +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,149 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; +import java.io.IOException; + +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.tools.ApplicationException; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.common.tools.BasicCommand; + +public class StorageCommand extends BasicCommand { + + private static final String NAME = "storage"; + + private DBStartupConfiguration configuration; + private DBOptionParser parser; + + private MongoProcessRunner runner; + + private void parseArguments(Arguments args) throws InvalidConfigurationException { + + File dbPath = ConfigUtils.getStorageDirectory(); + File logFile = ConfigUtils.getStorageLogFile(); + File pidFile = ConfigUtils.getStoragePidFile(); + File propertyFile = ConfigUtils.getStorageConfigurationFile(); + if (!propertyFile.exists()) { + throw new InvalidConfigurationException("can't access database configuration file " + + propertyFile); + } + // read everything that is in the configs + this.configuration = new DBStartupConfiguration(propertyFile, dbPath, logFile, pidFile); + parser = new DBOptionParser(configuration, args); + parser.parse(); + } + + @Override + public void run(CommandContext ctx) throws CommandException { + + try { + parseArgsAndRun(ctx); + } catch (InvalidConfigurationException e) { + throw new CommandException(e); + } + } + + private void parseArgsAndRun(CommandContext ctx) + throws InvalidConfigurationException { + parseArguments(ctx.getArguments()); + + // dry run means we don't do anything at all + if (parser.isDryRun()) return; + + runner = createRunner(); + try { + switch (parser.getAction()) { + case START: + startService(); + break; + case STOP: + stopService(); + break; + default: + break; + } + getNotifier().fireAction(ApplicationState.SUCCESS); + } catch (InvalidConfigurationException e) { + // rethrow + throw e; + } catch (Exception e) { + getNotifier().fireAction(ApplicationState.FAIL, e); + } + } + + private void startService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { + runner.startService(); + getNotifier().fireAction(ApplicationState.START); + } + + + private void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { + check(); + runner.stopService(); + getNotifier().fireAction(ApplicationState.STOP); + } + + MongoProcessRunner createRunner() { + return new MongoProcessRunner(configuration, parser.isQuiet()); + } + + private void check() throws InvalidConfigurationException { + if (!configuration.getDBPath().exists() || + !configuration.getLogFile().getParentFile().exists() || + !configuration.getPidFile().getParentFile().exists()) + { + throw new InvalidConfigurationException("database directories do not exist..."); + } + } + + @Override + public DBStartupConfiguration getConfiguration() { + return configuration; + } + + @Override + public String getName() { + return NAME; + } + +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageStartException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageStartException.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; + +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StorageStartException extends ApplicationException { + + private final File dbFile; + private final int status; + + public StorageStartException(File dbPath, int status, String message) { + super(message); + this.dbFile = dbPath; + this.status = status; + } + + public File getDbPath() { + return dbFile; + } + + public int getStatus() { + return status; + } + +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageStopException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageStopException.java Fri Dec 21 14:19:06 2012 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; + +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StorageStopException extends ApplicationException { + + private final File dbConfig; + private final int status; + + public StorageStopException(File dbConfig, int status, String message) { + super(message); + this.dbConfig = dbConfig; + this.status = status; + } + + public File getDbConfig() { + return dbConfig; + } + + public int getStatus() { + return status; + } + +} diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java --- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java Tue Jan 08 19:22:32 2013 +0100 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java Fri Dec 21 14:19:06 2012 +0100 @@ -41,6 +41,7 @@ import org.junit.Test; +import com.redhat.thermostat.agent.cli.impl.db.StorageCommand; import com.redhat.thermostat.common.cli.Command; import com.redhat.thermostat.test.StubBundleContext; diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java --- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java Tue Jan 08 19:22:32 2013 +0100 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java Fri Dec 21 14:19:06 2012 +0100 @@ -144,6 +144,7 @@ // FIXME test the rest of AgentApplication + @SuppressWarnings("serial") private static class ThatsAllThatWeCareAbout extends RuntimeException { } diff -r 5a2d3c43b551 -r 40be72a1345c agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/StorageCommandTest.java --- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/StorageCommandTest.java Tue Jan 08 19:22:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,295 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat 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; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Collection; -import java.util.Properties; -import java.util.Random; -import java.util.concurrent.CountDownLatch; - -import junit.framework.Assert; - -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionGroup; -import org.apache.commons.cli.Options; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import com.redhat.thermostat.agent.cli.db.DBConfig; -import com.redhat.thermostat.agent.cli.db.DBStartupConfiguration; -import com.redhat.thermostat.agent.cli.db.MongoProcessRunner; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.cli.SimpleArguments; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.tools.ApplicationState; - -public class StorageCommandTest { - - private static final String PORT = "27518"; - private static final String BIND = "127.0.0.1"; - private static final String DB = "storage/db"; - - private String tmpDir; - - @Before - public void setup() { - // need to create a dummy config file for the test - try { - Random random = new Random(); - - tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar + - Math.abs(random.nextInt()) + File.separatorChar; - - System.setProperty("THERMOSTAT_HOME", tmpDir); - File base = new File(tmpDir + "storage"); - base.mkdirs(); - - File tmpConfigs = new File(base, "db.properties"); - - new File(base, "run").mkdirs(); - new File(base, "logs").mkdirs(); - new File(base, "db").mkdirs(); - - Properties props = new Properties(); - - props.setProperty(DBConfig.BIND.name(), BIND); - props.setProperty(DBConfig.PORT.name(), PORT); - - props.store(new FileOutputStream(tmpConfigs), "thermostat test properties"); - - } catch (IOException e) { - Assert.fail("cannot setup tests: " + e); - } - } - - @Test - public void testConfig() throws CommandException { - SimpleArguments args = new SimpleArguments(); - args.addArgument("quiet", null); - args.addArgument("start", null); - args.addArgument("dryRun", null); - CommandContext ctx = mock(CommandContext.class); - when(ctx.getArguments()).thenReturn(args); - - StorageCommand service = new StorageCommand() { - @Override - MongoProcessRunner createRunner() { - throw new AssertionError("dry run should never create an actual runner"); - } - }; - - service.run(ctx); - - DBStartupConfiguration conf = service.getConfiguration(); - - Assert.assertEquals(tmpDir + DB, conf.getDBPath().getPath()); - Assert.assertEquals(Integer.parseInt(PORT), conf.getPort()); - Assert.assertEquals("mongodb://" + BIND + ":" + PORT , conf.getDBConnectionString()); - } - - private StorageCommand prepareService(boolean startSuccess) throws IOException, - InterruptedException, InvalidConfigurationException, ApplicationException - { - final MongoProcessRunner runner = mock(MongoProcessRunner.class); - if (!startSuccess) { - doThrow(new ApplicationException("mock exception")).when(runner).startService(); - } - - // TODO: stop not tested yet, but be sure it's not called from the code - doThrow(new ApplicationException("mock exception")).when(runner).stopService(); - - StorageCommand service = new StorageCommand() { - @Override - MongoProcessRunner createRunner() { - return runner; - } - }; - - return service; - } - - @Test - public void testListeners() throws InterruptedException, IOException, ApplicationException, InvalidConfigurationException, CommandException - { - StorageCommand service = prepareService(true); - - final CountDownLatch latch = new CountDownLatch(2); - - final boolean[] result = new boolean[2]; - service.getNotifier().addActionListener(new ActionListener() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = false; - latch.countDown(); - latch.countDown(); - break; - - case SUCCESS: - result[0] = true; - latch.countDown(); - break; - - case START: - result[1] = true; - latch.countDown(); - break; - } - } - }); - - service.run(prepareContext()); - latch.await(); - - Assert.assertTrue(result[0]); - Assert.assertTrue(result[1]); - } - - @Test - public void testListenersFail() throws InterruptedException, IOException, ApplicationException, CommandException, InvalidConfigurationException - { - StorageCommand service = prepareService(false); - - final CountDownLatch latch = new CountDownLatch(1); - final boolean[] result = new boolean[1]; - service.getNotifier().addActionListener(new ActionListener() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - - case SUCCESS: - result[0] = false; - break; - } - latch.countDown(); - } - }); - - service.run(prepareContext()); - latch.await(); - - Assert.assertTrue(result[0]); - } - - private CommandContext prepareContext() { - SimpleArguments args = new SimpleArguments(); - args.addArgument("quiet", "--quiet"); - args.addArgument("start", "--start"); - CommandContext ctx = mock(CommandContext.class); - when(ctx.getArguments()).thenReturn(args); - return ctx; - } - - @Test - public void testName() { - StorageCommand dbService = new StorageCommand(); - String name = dbService.getName(); - assertEquals("storage", name); - } - - @Test - public void testDescAndUsage() { - StorageCommand dbService = new StorageCommand(); - assertNotNull(dbService.getDescription()); - assertNotNull(dbService.getUsage()); - } - - @Ignore - @Test - public void testOptions() { - StorageCommand dbService = new StorageCommand(); - Options options = dbService.getOptions(); - assertNotNull(options); - assertEquals(4, options.getOptions().size()); - - assertTrue(options.hasOption("dryRun")); - Option dry = options.getOption("dryRun"); - assertEquals("d", dry.getOpt()); - assertEquals("run the service in dry run mode", dry.getDescription()); - assertFalse(dry.isRequired()); - assertFalse(dry.hasArg()); - - assertTrue(options.hasOption("start")); - Option start = options.getOption("start"); - assertEquals("start the database", start.getDescription()); - assertFalse(start.isRequired()); - assertFalse(start.hasArg()); - - assertTrue(options.hasOption("stop")); - Option stop = options.getOption("stop"); - assertEquals("stop the database", stop.getDescription()); - assertFalse(stop.isRequired()); - assertFalse(stop.hasArg()); - - assertTrue(options.hasOption("quiet")); - Option quiet = options.getOption("quiet"); - assertEquals("q", quiet.getOpt()); - assertEquals("don't produce any output", quiet.getDescription()); - assertFalse(quiet.isRequired()); - assertFalse(quiet.hasArg()); - - OptionGroup startStop = options.getOptionGroup(start); - assertTrue(startStop.isRequired()); - @SuppressWarnings("unchecked") - Collection