# HG changeset patch # User Elliott Baron # Date 1358190290 18000 # Node ID 2930e0c260cca05d353185263a1edda8eb81a1ab # Parent 1e51015e63e5a970a3d6432cee575b584cb42ddf# Parent b1b81446c8922bfeff4958108eff531ff468b362 Merge diff -r 1e51015e63e5 -r 2930e0c260cc agent/cli/pom.xml --- a/agent/cli/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/pom.xml Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,236 +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; - ApplicationException ex = null; - if (!checkExistingProcess()) { - message = translator.localize(LocaleResources.STALE_PID_FILE_NO_MATCHING_PROCESS, configuration.getPidFile().toString(), MONGO_PROCESS); - ex = new StalePidFileException(configuration.getPidFile()); - } else { - message = translator.localize(LocaleResources.STORAGE_ALREADY_RUNNING_WITH_PID, String.valueOf(pid)); - ex = new StorageAlreadyRunningException(Integer.valueOf(pid), message); - } - - display(message); - throw ex; - } - - 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 1e51015e63e5 -r 2930e0c260cc agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StalePidFileException.java --- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StalePidFileException.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +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.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.locale.Translate; -import com.redhat.thermostat.common.tools.ApplicationException; - -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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/impl/strings.properties --- a/agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/impl/strings.properties Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/impl/strings.properties Mon Jan 14 14:04:50 2013 -0500 @@ -10,7 +10,7 @@ CANNOT_START_SERVER = cannot start server {0}, exit status: {1}. Please check that your configuration is valid CANNOT_SHUTDOWN_SERVER = cannot shutdown server {0}, exit status: {1}. Please check that your configuration is valid STALE_PID_FILE = stale pid file: {0} -STALE_PID_FILE_NO_MATCHING_PROCESS = A stale pid file ({0}) is present but there is no matching {1} process. Please remove the file if it has been shut down +STALE_PID_FILE_NO_MATCHING_PROCESS = A stale pid file ({0}) is present but there is no matching {1} process. Removing stale pid file. STARTING_STORAGE_SERVER = starting storage server... CANNOT_EXECUTE_PROCESS = can not execute {0} process. is it installed? SERVER_LISTENING_ON = server listening on ip: {0} diff -r 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -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 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -144,6 +144,7 @@ // FIXME test the rest of AgentApplication + @SuppressWarnings("serial") private static class ThatsAllThatWeCareAbout extends RuntimeException { } diff -r 1e51015e63e5 -r 2930e0c260cc 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 Wed Jan 09 14:59:30 2013 -0500 +++ /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