Mercurial > hg > release > thermostat-0.13
changeset 172:c69bd1a12299
Merge
author | Roman Kennke <rkennke@redhat.com> |
---|---|
date | Thu, 29 Mar 2012 23:54:17 +0200 |
parents | ca53979873fb (current diff) e230498139ed (diff) |
children | cbe6f5b7e43c |
files | agent/src/main/java/com/redhat/thermostat/agent/Main.java |
diffstat | 55 files changed, 3395 insertions(+), 567 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/src/main/java/com/redhat/thermostat/agent/Agent.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/agent/Agent.java Thu Mar 29 23:54:17 2012 +0200 @@ -39,11 +39,11 @@ import java.util.UUID; import java.util.logging.Logger; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; import com.redhat.thermostat.agent.config.ConfigurationWatcher; import com.redhat.thermostat.backend.Backend; import com.redhat.thermostat.backend.BackendRegistry; import com.redhat.thermostat.common.LaunchException; -import com.redhat.thermostat.common.config.StartupConfiguration; import com.redhat.thermostat.common.storage.AgentInformation; import com.redhat.thermostat.common.storage.BackendInformation; import com.redhat.thermostat.common.storage.Storage; @@ -58,16 +58,16 @@ private final UUID id; private final BackendRegistry backendRegistry; - private final StartupConfiguration config; + private final AgentStartupConfiguration config; private Storage storage; private Thread configWatcherThread = null; - public Agent(BackendRegistry backendRegistry, StartupConfiguration config, Storage storage) { + public Agent(BackendRegistry backendRegistry, AgentStartupConfiguration config, Storage storage) { this(backendRegistry, UUID.randomUUID(), config, storage); } - public Agent(BackendRegistry registry, UUID agentId, StartupConfiguration config, Storage storage) { + public Agent(BackendRegistry registry, UUID agentId, AgentStartupConfiguration config, Storage storage) { this.id = agentId; this.backendRegistry = registry; this.config = config; @@ -133,9 +133,10 @@ configWatcherThread = null; storage.removeAgentInformation(); stopBackends(); - if (config.getLocalMode()) { - storage.purge(); - } + // TODO +// if (config.getLocalMode()) { +// storage.purge(); +// } } else { logger.warning("Attempt to stop agent which is not active"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/agent/AgentApplication.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,145 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.agent.config.AgentConfigsUtils; +import com.redhat.thermostat.agent.config.AgentOptionParser; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; +import com.redhat.thermostat.backend.BackendLoadException; +import com.redhat.thermostat.backend.BackendRegistry; +import com.redhat.thermostat.common.Constants; +import com.redhat.thermostat.common.LaunchException; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.dao.Connection; +import com.redhat.thermostat.common.dao.ConnectionProvider; +import com.redhat.thermostat.common.dao.MongoConnectionProvider; +import com.redhat.thermostat.common.storage.ConnectionFailedException; +import com.redhat.thermostat.common.storage.MongoStorage; +import com.redhat.thermostat.common.storage.Storage; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.tools.BasicApplication; + +public final class AgentApplication extends BasicApplication { + + private AgentStartupConfiguration configuration; + private AgentOptionParser parser; + + @Override + public void parseArguments(List<String> args) throws InvalidConfigurationException { + configuration = AgentConfigsUtils.createAgentConfigs(); + parser = new AgentOptionParser(configuration, args); + parser.parse(); + } + + @Override + public AgentStartupConfiguration getConfiguration() { + return configuration; + } + + private void runAgent() { + long startTime = System.currentTimeMillis(); + configuration.setStartTime(startTime); + + if (configuration.isDebugConsole()) { + LoggingUtils.useDevelConsole(); + } + + LoggingUtils.setGlobalLogLevel(configuration.getLogLevel()); + Logger logger = LoggingUtils.getLogger(AgentApplication.class); + + ConnectionProvider connProv = new MongoConnectionProvider(configuration); + Connection connection = connProv.createConnection(); + + Storage storage = new MongoStorage(connection); + try { + storage.connect(); + logger.fine("Storage configured with database URI."); + } catch (ConnectionFailedException ex) { + logger.log(Level.SEVERE, "Could not initialize storage layer.", ex); + System.exit(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE); + } + + BackendRegistry backendRegistry = null; + try { + backendRegistry = new BackendRegistry(configuration, storage); + } catch (BackendLoadException ble) { + logger.log(Level.SEVERE, "Could not get BackendRegistry instance.", ble); + System.exit(Constants.EXIT_BACKEND_LOAD_ERROR); + } + + Agent agent = new Agent(backendRegistry, configuration, storage); + storage.setAgentId(agent.getId()); + try { + logger.fine("Starting agent."); + agent.start(); + } catch (LaunchException le) { + logger.log(Level.SEVERE, + "Agent could not start, probably because a configured backend could not be activated.", + le); + System.exit(Constants.EXIT_BACKEND_START_ERROR); + } + logger.fine("Agent started."); + + try { + System.in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + + agent.stop(); + logger.fine("Agent stopped."); + } + + @Override + public void run() { + if (!parser.isHelp()) { + runAgent(); + } + } + + public static void main(String[] args) throws InvalidConfigurationException { + AgentApplication service = new AgentApplication(); + service.parseArguments(Arrays.asList(args)); + service.run(); + } +}
--- a/agent/src/main/java/com/redhat/thermostat/agent/Main.java Thu Mar 29 23:52:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +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 - * <http://www.gnu.org/licenses/>. - * - * 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; - -import java.io.IOException; -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.backend.BackendLoadException; -import com.redhat.thermostat.backend.BackendRegistry; -import com.redhat.thermostat.common.Constants; -import com.redhat.thermostat.common.LaunchException; -import com.redhat.thermostat.common.config.StartupConfiguration; -import com.redhat.thermostat.common.dao.Connection; -import com.redhat.thermostat.common.dao.ConnectionProvider; -import com.redhat.thermostat.common.dao.MongoConnectionProvider; -import com.redhat.thermostat.common.dao.Connection.ConnectionType; -import com.redhat.thermostat.common.storage.ConnectionFailedException; -import com.redhat.thermostat.common.storage.MongoStorage; -import com.redhat.thermostat.common.storage.Storage; -import com.redhat.thermostat.common.utils.LoggingUtils; - -public final class Main { - - private Main() { - throw new IllegalStateException("Should not be instantiated"); - } - - public static void main(String[] args) { - long startTimestamp = System.currentTimeMillis(); - - List<String> argsAsList = new ArrayList<String>(Arrays.asList(args)); - while (argsAsList.contains(Constants.AGENT_ARGUMENT_DEVEL)) { - argsAsList.remove(Constants.AGENT_ARGUMENT_DEVEL); - LoggingUtils.useDevelConsole(); - } - - LoggingUtils.setGlobalLogLevel(Level.ALL); - Logger logger = LoggingUtils.getLogger(Main.class); - - StartupConfiguration config = null; - try { - config = new StartupConfiguration(startTimestamp, argsAsList.toArray(new String[0])); - } catch (LaunchException le) { - logger.log(Level.SEVERE, - "Unable to instantiate startup configuration.", - le); - System.exit(Constants.EXIT_CONFIGURATION_ERROR); - } - - LoggingUtils.setGlobalLogLevel(config.getLogLevel()); - - ConnectionProvider connProv = new MongoConnectionProvider(config); - Connection connection = connProv.createConnection(); - if (config.getLocalMode()) { - connection.setType(ConnectionType.LOCAL); - } else { - connection.setType(ConnectionType.REMOTE); - } - - Storage storage = new MongoStorage(connection); - try { - storage.connect(); - logger.fine("Storage configured with database URI."); - } catch (ConnectionFailedException ex) { - logger.log(Level.SEVERE, "Could not initialize storage layer.", ex); - System.exit(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE); - } - - BackendRegistry backendRegistry = null; - try { - backendRegistry = new BackendRegistry(config, storage); - } catch (BackendLoadException ble) { - logger.log(Level.SEVERE, "Could not get BackendRegistry instance.", ble); - System.exit(Constants.EXIT_BACKEND_LOAD_ERROR); - } - - Agent agent = new Agent(backendRegistry, config, storage); - storage.setAgentId(agent.getId()); - try { - logger.fine("Starting agent."); - agent.start(); - } catch (LaunchException le) { - logger.log(Level.SEVERE, - "Agent could not start, probably because a configured backend could not be activated.", - le); - System.exit(Constants.EXIT_BACKEND_START_ERROR); - } - logger.fine("Agent started."); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - - agent.stop(); - logger.fine("Agent stopped."); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,136 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Level; + +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +public class AgentConfigsUtils { + + public static AgentStartupConfiguration createAgentConfigs() throws InvalidConfigurationException { + + AgentStartupConfiguration config = new AgentStartupConfiguration(); + + File propertyFile = ConfigUtils.getAgentConfigurationFile(); + + config.setLogLevel(Level.FINE); + readAndSetProperties(propertyFile, config); + + return config; + } + + private static void readAndSetProperties(File propertyFile, AgentStartupConfiguration configuration) + throws InvalidConfigurationException + { + Properties properties = new Properties(); + try { + properties.load(new FileInputStream(propertyFile)); + + } catch (IOException e) { + throw new InvalidConfigurationException(e); + } + + if (properties.containsKey(AgentProperties.BACKENDS.name())) { + // this is a command separated list of backends + String backends = properties.getProperty(AgentProperties.BACKENDS.name()); + configuration.parseBackends(backends.split(",")); + + } else { + throw new InvalidConfigurationException(AgentProperties.BACKENDS + " property missing"); + } + + if (properties.containsKey(AgentProperties.LOG_LEVEL.name())) { + String logLevel = properties.getProperty(AgentProperties.LOG_LEVEL.name()); + Level level = getLogLevel(logLevel); + configuration.setLogLevel(level); + } + + if (properties.containsKey(AgentProperties.DB_URL.name())) { + String db = properties.getProperty(AgentProperties.DB_URL.name()); + configuration.setDatabaseURL(db); + } + } + + public static Level getLogLevel(String logLevel) { + + Level level = Level.FINE; + switch (logLevel.toUpperCase()) { + case "SEVERE": + level = Level.SEVERE; + break; + + case "INFO": + level = Level.INFO; + break; + + case "CONFIG": + level = Level.CONFIG; + break; + + case "FINE": + level = Level.FINE; + break; + + case "FINER": + level = Level.FINER; + break; + + case "FINEST": + level = Level.FINEST; + break; + + case "WARNING": + level = Level.WARNING; + break; + + case "ALL": + level = Level.ALL; + break; + + default: + break; + } + + return level; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/agent/config/AgentOptionParser.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,134 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.config; + +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; + +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; + +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.ThermostatOptionParser; + +public class AgentOptionParser implements ThermostatOptionParser { + + private AgentStartupConfiguration configuration; + private OptionParser parser; + private List<String> args; + + private boolean isHelp; + + public AgentOptionParser(AgentStartupConfiguration configuration, List<String> args) { + this.configuration = configuration; + this.args = args; + parser = new OptionParser(); + isHelp = false; + } + + @Override + public void parse() throws InvalidConfigurationException { + + parser.accepts(Args.DEBUG.option, Args.DEBUG.description); + parser.accepts(Args.HELP.option, Args.HELP.description); + + OptionSpec<String> logLevel = + parser.accepts(Args.LEVEL.option, Args.LEVEL.description). + withRequiredArg(); + OptionSpec<String> dbUrl = + parser.accepts(Args.DB.option, Args.DB.description). + withRequiredArg(); + + OptionSet options = parser.parse(args.toArray(new String[0])); + if (options.has(Args.HELP.option)) { + displayHelp(); + isHelp = true; + return; + } + + if (options.has(Args.LEVEL.option)) { + String levelString = logLevel.value(options); + Level level = AgentConfigsUtils.getLogLevel(levelString); + configuration.setLogLevel(level); + } + + configuration.setDebugConsole(options.has(Args.DEBUG.option)); + + if (options.has(Args.DB.option)) { + String url = dbUrl.value(options); + configuration.setDatabaseURL(url); + } else { + if (configuration.getDBConnectionString() == null) { + System.err.println("database url not specified... must be " + + "either set in config or passed on " + + "the command line"); + displayHelp(); + isHelp = true; + } + } + } + + public boolean isHelp() { + return isHelp; + } + + @Override + public void displayHelp() { + try { + parser.printHelpOn(System.out); + } catch (IOException ignore) {} + } + + private static enum Args { + + // TODO: localize + LEVEL("logLevel", "log level"), + DB("dbUrl", "connect to the given url"), + DEBUG("debug", "launch with debug console enabled"), + HELP("help", "print this help and exit"); + + private String option; + private String description; + + Args(String option, String description) { + this.option = option; + this.description = description; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/agent/config/AgentProperties.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,46 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.config; + +public enum AgentProperties { + + // backend list, comma separated + BACKENDS, + LOG_LEVEL, + DEBUG_CONSOLE, + DB_URL +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/agent/config/AgentStartupConfiguration.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,134 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; + +import com.redhat.thermostat.backend.BackendID; +import com.redhat.thermostat.backend.BackendsProperties; +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.StartupConfiguration; + +public class AgentStartupConfiguration implements StartupConfiguration { + + private List<BackendID> backends; + + private Level logLevel; + private boolean debugConsole; + + private String url; + + private long startTime; + + AgentStartupConfiguration() { + this.backends = new ArrayList<>(); + } + + @Override + public String getDBConnectionString() { + return url; + } + + public Level getLogLevel() { + return this.logLevel; + } + + void setLogLevel(Level level) { + this.logLevel = level; + } + + void parseBackends(String[] backendsList) throws InvalidConfigurationException { + backends.clear(); + + for (String simpleName : backendsList) { + String backendName = simpleName.trim(); + + // a file must exist, at least with the class name + File backendSettings = ConfigUtils.getBackendPropertyFile(backendName); + Properties backendProps = new Properties(); + try { + backendProps.load(new FileInputStream(backendSettings)); + + } catch (IOException e) { + throw new InvalidConfigurationException(e); + } + + String backendClass = backendProps.getProperty(BackendsProperties.BACKEND_CLASS.name()); + if (backendClass == null) { + throw new InvalidConfigurationException("Class name not found for backend: " + + backendName); + } + + BackendID backend = new BackendID(backendName, backendClass); + backends.add(backend); + } + } + + public List<BackendID> getBackends() { + return backends; + } + + void setDebugConsole(boolean debugConsole) { + this.debugConsole = debugConsole; + } + + public boolean isDebugConsole() { + return debugConsole; + } + + public void setDatabaseURL(String url) { + this.url = url; + } + + // TODO: that should be a friend, we only want the Service to set this value + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public long getStartTime() { + return startTime; + } +}
--- a/agent/src/main/java/com/redhat/thermostat/backend/Backend.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/backend/Backend.java Thu Mar 29 23:54:17 2012 +0200 @@ -56,6 +56,12 @@ private Storage storage = null; private boolean observeNewJvm = attachToNewProcessByDefault(); + private String version; + private String vendor; + private String description; + + private BackendID id; + /** * * @param configMap a map containing the settings that this backend has been configured with. @@ -89,34 +95,67 @@ /** * Set the named configuration to the given value. + * The basic special properties {@code name}, {@code version} and + * {@code description} are parsed here. + * + * <br /><br /> + * + * Subclasses can just override the + * {@link #setConfigurationValueImpl(String, String)} + * method if they are not interested in parsing and setting those + * properties directly. + * * @param name * @param value * @throws IllegalArgumentException if either the key does not refer to a valid configuration option * for this backend or the value is not valid for the key */ protected void setConfigurationValue(String name, String value) { - throw new IllegalArgumentException("Backend " + getName() + " does not support any specific configuration values."); + + if (name.equals(BackendsProperties.DESCRIPTION.name())) { + this.description = value; + } else if (name.equals(BackendsProperties.VERSION.name())) { + this.version = value; + } else if (name.equals(BackendsProperties.VENDOR.name())) { + this.vendor = value; + } else { + setConfigurationValueImpl(name, value); + } } - + + /** + * Set the named configuration to the given value. + * By default, does nothing. + */ + protected void setConfigurationValueImpl(String name, String value) {} + /** * @return the name of the {@link Backend} */ - public abstract String getName(); + public String getName() { + return id.getSimpleName(); + } /** * @returns the description of the {@link Backend} */ - public abstract String getDescription(); + public String getDescription() { + return description; + } /** * @return the vendor of the {@link Backend} */ - public abstract String getVendor(); + public String getVendor() { + return vendor; + } /** * @return the version of the {@link Backend} */ - public abstract String getVersion(); + public String getVersion() { + return version; + } /** Get a map containing the current settings of this backend. * Implementors of this abstract class which have some settings that @@ -196,4 +235,12 @@ public void update(Chunk chunk) { storage.updateChunk(chunk); } + + void setID(BackendID backendID) { + this.id = backendID; + } + + public BackendID getID() { + return id; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendID.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,61 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend; + +public class BackendID { + + private String simpleName; + private String className; + + public BackendID(String simpleName, String className) { + this.simpleName = simpleName; + this.className = className; + } + + public String getSimpleName() { + return simpleName; + } + + public String getClassName() { + return className; + } + + @Override + public String toString() { + return simpleName + " = " + className; + } +}
--- a/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistry.java Thu Mar 29 23:54:17 2012 +0200 @@ -33,18 +33,18 @@ * 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.backend; import java.lang.reflect.Constructor; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.backend.system.SystemBackend; -import com.redhat.thermostat.common.config.StartupConfiguration; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; import com.redhat.thermostat.common.storage.Storage; import com.redhat.thermostat.common.utils.LoggingUtils; @@ -58,33 +58,30 @@ private final Map<String, Backend> registeredBackends; - public BackendRegistry(StartupConfiguration config, Storage storage) throws BackendLoadException { + public BackendRegistry(AgentStartupConfiguration config, Storage storage) throws BackendLoadException { + registeredBackends = new HashMap<String, Backend>(); - - /* - * Configure the always-on backends - */ - Backend systemBackend = new SystemBackend(); - logger.log(Level.FINE, "Initializing backend: \"" + systemBackend.getClass().getCanonicalName() + "\""); - systemBackend.setInitialConfiguration(config.getStartupBackendConfigMap(systemBackend.getName())); - systemBackend.setStorage(storage); - register(systemBackend); - + + List<BackendID> backends = config.getBackends(); + /* * Configure the dynamic/custom backends */ - for (String backendClassName : config.getStartupBackendClassNames()) { - logger.log(Level.FINE, "Initializing backend: \"" + backendClassName + "\""); + for (BackendID backendID : backends) { + logger.log(Level.FINE, "Initializing backend: \"" + backendID.getClassName() + "\""); Backend backend = null; try { - Class<? > c = Class.forName(backendClassName); + Class<? > c = Class.forName(backendID.getClassName()); Class<? extends Backend> narrowed = c.asSubclass(Backend.class); Constructor<? extends Backend> backendConstructor = narrowed.getConstructor(); backend = backendConstructor.newInstance(); - backend.setInitialConfiguration(config.getStartupBackendConfigMap(backend.getName())); + + backend.setID(backendID); + + backend.setInitialConfiguration(BackendRegistryUtils.retrieveBackendConfigs(backend.getName())); backend.setStorage(storage); } catch (Exception e) { - throw new BackendLoadException("Could not instantiate configured backend class: " + backendClassName, e); + throw new BackendLoadException("Could not instantiate configured backend class: " + backendID.getClassName(), e); } register(backend); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendRegistryUtils.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,82 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +class BackendRegistryUtils { + + public static Map<String, String> retrieveBackendConfigs(String name) throws InvalidConfigurationException { + + // reads the backend + File backend = new File(ConfigUtils.getBackendsBaseDirectory(), name); + backend = new File(backend, BackendsProperties.PROPERTY_FILE); + if (!backend.isFile() || !backend.canRead()) { + throw new InvalidConfigurationException("invalid backend configuration file: " + backend); + } + + Properties props = new Properties(); + try { + props.load(new FileInputStream(backend)); + } catch (IOException e) { + throw new InvalidConfigurationException("invalid backend configuration file", e); + } + + return getStartupBackendConfigMap(props); + } + + private static Map<String, String> getStartupBackendConfigMap(Properties props) { + + Map<String, String> configMap = new HashMap<>(); + for (Entry<Object, Object> e : props.entrySet()) { + String key = (String) e.getKey(); + String value = (String) e.getValue(); + + configMap.put(key, value); + } + return configMap; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/main/java/com/redhat/thermostat/backend/BackendsProperties.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,50 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend; + +/** + * Properties that any Backend needs to have, at minimum. + */ +public enum BackendsProperties { + + DESCRIPTION, + VENDOR, + VERSION, + BACKEND_CLASS; + + public static final String PROPERTY_FILE = "backend.properties"; +}
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java Thu Mar 29 23:54:17 2012 +0200 @@ -55,6 +55,8 @@ import com.redhat.thermostat.agent.JvmStatusListener; import com.redhat.thermostat.agent.JvmStatusNotifier; import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.common.SystemClock; import com.redhat.thermostat.common.dao.CpuStatConverter; import com.redhat.thermostat.common.dao.CpuStatDAO; import com.redhat.thermostat.common.dao.HostInfoConverter; @@ -75,11 +77,6 @@ public class SystemBackend extends Backend implements JvmStatusNotifier, JvmStatusListener { - private static final String NAME = "system"; - private static final String DESCRIPTION = "gathers basic information from the system"; - private static final String VENDOR = "thermostat project"; - private static final String VERSION = "0.01"; - private static final Logger logger = LoggingUtils.getLogger(SystemBackend.class); private long procCheckInterval = 1000; // TODO make this configurable. @@ -92,8 +89,16 @@ private Set<Integer> pidsToMonitor = new CopyOnWriteArraySet<Integer>(); + private final VmCpuStatBuilder vmCpuBuilder; + private static List<Category> categories = new ArrayList<Category>(); + public SystemBackend() { + Clock clock = new SystemClock(); + ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(new ProcDataSource()); + long ticksPerSecond = SysConf.getClockTicksPerSecond(); + vmCpuBuilder = new VmCpuStatBuilder(clock, ticksPerSecond, builder); + } static { // Set up categories that will later be registered. @@ -109,26 +114,6 @@ } @Override - public String getName() { - return NAME; - } - - @Override - public String getDescription() { - return DESCRIPTION; - } - - @Override - public String getVendor() { - return VENDOR; - } - - @Override - public String getVersion() { - return VERSION; - } - - @Override public synchronized boolean activate() { if (timer != null) { return true; @@ -153,8 +138,11 @@ store(new MemoryStatConverter().memoryStatToChunk(new MemoryStatBuilder(dataSource).build())); for (Integer pid : pidsToMonitor) { - new VmCpuStatBuilder(); - store(new VmCpuStatConverter().vmCpuStatToChunk(VmCpuStatBuilder.build(pid))); + if (vmCpuBuilder.knowsAbout(pid)) { + store(new VmCpuStatConverter().vmCpuStatToChunk(vmCpuBuilder.build(pid))); + } else { + vmCpuBuilder.learnAbout(pid); + } } } }, 0, procCheckInterval); @@ -234,5 +222,6 @@ @Override public void jvmStopped(int vmId) { pidsToMonitor.remove(vmId); + vmCpuBuilder.forgetAbout(vmId); } }
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/VmCpuStatBuilder.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/main/java/com/redhat/thermostat/backend/system/VmCpuStatBuilder.java Thu Mar 29 23:54:17 2012 +0200 @@ -39,16 +39,25 @@ import java.util.HashMap; import java.util.Map; +import com.redhat.thermostat.common.Clock; import com.redhat.thermostat.common.model.VmCpuStat; public class VmCpuStatBuilder { // pid -> ticks - private static Map<Integer, Long> lastProcessTicks = new HashMap<Integer, Long>(); + private final Map<Integer, Long> lastProcessTicks = new HashMap<Integer, Long>(); // pid -> last time the ticks were updated - private static Map<Integer, Long> lastProcessTickTime = new HashMap<Integer, Long>(); + private final Map<Integer, Long> lastProcessTickTime = new HashMap<Integer, Long>(); + + private final Clock clock; + private final long ticksPerSecond; + private final ProcessStatusInfoBuilder statusBuilder; - private static long clockTicksPerSecond = SysConf.getClockTicksPerSecond(); + public VmCpuStatBuilder(Clock clock, long ticksPerSecond, ProcessStatusInfoBuilder statusBuilder) { + this.clock = clock; + this.ticksPerSecond = ticksPerSecond; + this.statusBuilder = statusBuilder; + } /** * To build the stat, this method needs to be called repeatedly. The first @@ -58,26 +67,43 @@ * @param pid * @return */ - public static synchronized VmCpuStat build(Integer pid) { + public synchronized VmCpuStat build(Integer pid) { + if (!lastProcessTicks.containsKey(pid) || !lastProcessTickTime.containsKey(pid)) { + throw new IllegalArgumentException("unknown pid"); + } - ProcDataSource dataSource = new ProcDataSource(); - ProcessStatusInfo info = new ProcessStatusInfoBuilder(dataSource).build(pid); - long miliTime = System.currentTimeMillis(); - long time = System.nanoTime(); + ProcessStatusInfo info = statusBuilder.build(pid); + long miliTime = clock.getRealTimeMillis(); + long time = clock.getMonotonicTimeNanos(); long programTicks = (info.getKernelTime() + info.getUserTime()); double cpuLoad = 0.0; - if (lastProcessTicks.containsKey(pid)) { - double timeDelta = (time - lastProcessTickTime.get(pid)) * 1E-9; - long programTicksDelta = programTicks - lastProcessTicks.get(pid); - cpuLoad = programTicksDelta * (100.0 / timeDelta / clockTicksPerSecond); - } + double timeDelta = (time - lastProcessTickTime.get(pid)) * 1E-9; + long programTicksDelta = programTicks - lastProcessTicks.get(pid); + // 100 as in 100 percent. + cpuLoad = programTicksDelta * (100.0 / timeDelta / ticksPerSecond); lastProcessTicks.put(pid, programTicks); lastProcessTickTime.put(pid, time); - return new VmCpuStat(miliTime, pid, cpuLoad); } + public synchronized boolean knowsAbout(int pid) { + return (lastProcessTickTime.containsKey(pid) && lastProcessTicks.containsKey(pid)); + } + + public synchronized void learnAbout(int pid) { + long time = clock.getMonotonicTimeNanos(); + ProcessStatusInfo info = statusBuilder.build(pid); + + lastProcessTickTime.put(pid, time); + lastProcessTicks.put(pid, info.getUserTime()+ info.getKernelTime()); + } + + public synchronized void forgetAbout(int pid) { + lastProcessTicks.remove(pid); + lastProcessTickTime.remove(pid); + } + }
--- a/agent/src/test/java/com/redhat/thermostat/TestUtils.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/test/java/com/redhat/thermostat/TestUtils.java Thu Mar 29 23:54:17 2012 +0200 @@ -36,7 +36,19 @@ package com.redhat.thermostat; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.lang.management.ManagementFactory; +import java.util.Properties; +import java.util.Random; + +import junit.framework.Assert; + +import org.junit.BeforeClass; + +import com.redhat.thermostat.agent.config.AgentProperties; +import com.redhat.thermostat.backend.BackendsProperties; public class TestUtils { @@ -49,5 +61,47 @@ public static boolean isLinux() { return (System.getProperty("os.name").toLowerCase().contains("linux")); } + + public static String setupAgentConfigs() throws IOException { + // need to create dummy config files for the tests + Random random = new Random(); + String tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar + + Math.abs(random.nextInt()) + File.separatorChar; + + System.setProperty("THERMOSTAT_HOME", tmpDir); + File agent = new File(tmpDir, "agent"); + agent.mkdirs(); + + File tmpConfigs = new File(agent, "agent.properties"); + + new File(agent, "run").mkdirs(); + new File(agent, "logs").mkdirs(); + + File backends = new File(tmpDir, "backends"); + File system = new File(backends, "system"); + system.mkdirs(); + + Properties props = new Properties(); + + props.setProperty(AgentProperties.BACKENDS.name(), "system"); + props.setProperty(AgentProperties.LOG_LEVEL.name(), "WARNING"); + + props.store(new FileOutputStream(tmpConfigs), "thermostat agent test properties"); + + // now write the configs for the backends + tmpConfigs = new File(system, "backend.properties"); + props = new Properties(); + props.setProperty(BackendsProperties.BACKEND_CLASS.name(), + "com.redhat.thermostat.backend.system.SystemBackend"); + props.setProperty(BackendsProperties.DESCRIPTION.name(), + "fluff backend for tests"); + props.setProperty(BackendsProperties.VENDOR.name(), + "Red Hat, Inc."); + props.setProperty(BackendsProperties.VERSION.name(), + "1.0"); + props.store(new FileOutputStream(tmpConfigs), "thermostat system backend properties"); + + return tmpDir; + } }
--- a/agent/src/test/java/com/redhat/thermostat/agent/AgentTest.java Thu Mar 29 23:52:18 2012 +0200 +++ b/agent/src/test/java/com/redhat/thermostat/agent/AgentTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -48,9 +48,9 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; import com.redhat.thermostat.backend.Backend; import com.redhat.thermostat.backend.BackendRegistry; -import com.redhat.thermostat.common.config.StartupConfiguration; import com.redhat.thermostat.common.storage.AgentInformation; import com.redhat.thermostat.common.storage.BackendInformation; import com.redhat.thermostat.common.storage.Storage; @@ -60,7 +60,7 @@ @Test public void testStartAgent() throws Exception { // Setup class under test and test data (config, backendRegistry). - StartupConfiguration config = mock(StartupConfiguration.class); + AgentStartupConfiguration config = mock(AgentStartupConfiguration.class); when(config.getStartTime()).thenReturn(123L); Storage storage = mock(Storage.class);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,69 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.config; + +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.TestUtils; +import com.redhat.thermostat.backend.BackendID; +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +public class AgentConfigsUtilsTest { + + @Before + public void setUp() throws IOException, InvalidConfigurationException { + TestUtils.setupAgentConfigs(); + } + + @Test + public void test() throws InvalidConfigurationException { + AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs(); + List<BackendID> backends = config.getBackends(); + + // the test property only define the system backend so far + Assert.assertEquals(1, backends.size()); + Assert.assertEquals("system", backends.get(0).getSimpleName()); + + Assert.assertEquals(Level.WARNING, config.getLogLevel()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/test/java/com/redhat/thermostat/agent/config/AgentOptionParserTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,106 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.config; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; + +import junit.framework.Assert; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.redhat.thermostat.TestUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +public class AgentOptionParserTest { + + private static File tmpFile; + + @BeforeClass + public static void setup() throws IOException { + tmpFile = new File(TestUtils.setupAgentConfigs()); + } + + @AfterClass + public static void shutdown() { + tmpFile.delete(); + } + + @Test + public void testConfigs1() throws IOException, InvalidConfigurationException { + + List<String> args = new ArrayList<>(); + args.add("--logLevel"); + args.add("ALL"); + args.add("--dbUrl"); + args.add("testURL"); + args.add("--debug"); + + AgentStartupConfiguration configs = new AgentStartupConfiguration(); + AgentOptionParser parser = new AgentOptionParser(configs, args); + parser.parse(); + + Assert.assertEquals("testURL", configs.getDBConnectionString()); + Assert.assertEquals(Level.ALL, configs.getLogLevel()); + Assert.assertTrue(configs.isDebugConsole()); + } + + @Test + public void testConfigs2() throws IOException, InvalidConfigurationException { + + List<String> args = new ArrayList<>(); + args.add("--logLevel"); + args.add("FINE"); + args.add("--dbUrl"); + args.add("testURL2"); + + AgentStartupConfiguration configs = new AgentStartupConfiguration(); + AgentOptionParser parser = new AgentOptionParser(configs, args); + parser.parse(); + + Assert.assertEquals("testURL2", configs.getDBConnectionString()); + Assert.assertEquals(Level.FINE, configs.getLogLevel()); + Assert.assertFalse(configs.isDebugConsole()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/test/java/com/redhat/thermostat/backend/BackendRegistryTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,76 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.TestUtils; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; +import com.redhat.thermostat.backend.system.SystemBackend; +import com.redhat.thermostat.common.storage.Storage; + +public class BackendRegistryTest { + + @Before + public void setUp() throws IOException { + TestUtils.setupAgentConfigs(); + } + + @Test + public void test() throws BackendLoadException { + + List<BackendID> backends = new ArrayList<>(); + backends.add(new BackendID("system", SystemBackend.class.getCanonicalName())); + + Storage storage = mock(Storage.class); + AgentStartupConfiguration config = mock(AgentStartupConfiguration.class); + when(config.getBackends()).thenReturn(backends); + + BackendRegistry registry = new BackendRegistry(config, storage); + Assert.assertEquals(1, registry.getAll().size()); + Assert.assertNotNull(registry.getByName("system")); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/test/java/com/redhat/thermostat/backend/BackendRegistryUtilsTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,66 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend; + +import java.io.IOException; +import java.util.Map; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.TestUtils; +import com.redhat.thermostat.backend.system.SystemBackend; +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +public class BackendRegistryUtilsTest { + + @Before + public void setUp() throws IOException { + TestUtils.setupAgentConfigs(); + } + + @Test + public void test() throws InvalidConfigurationException { + Map<String, String> backendProps = BackendRegistryUtils.retrieveBackendConfigs("system"); + Assert.assertTrue(backendProps.containsKey(BackendsProperties.BACKEND_CLASS.name())); + + String className = backendProps.get(BackendsProperties.BACKEND_CLASS.name()); + Assert.assertEquals(SystemBackend.class.getCanonicalName(), className); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/test/java/com/redhat/thermostat/backend/system/VmCpuStatBuilderTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,117 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend.system; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.common.model.VmCpuStat; + +public class VmCpuStatBuilderTest { + + @Test + public void testBuilderKnowsNothing() { + Clock clock = mock(Clock.class); + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + long ticksPerSecond = 0; + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, ticksPerSecond, statusBuilder); + + assertFalse(builder.knowsAbout(0)); + assertFalse(builder.knowsAbout(1)); + assertFalse(builder.knowsAbout(Integer.MIN_VALUE)); + assertFalse(builder.knowsAbout(Integer.MAX_VALUE)); + + } + + @Test(expected = IllegalArgumentException.class) + public void testBuilderThrowsOnBuildOfUnknownPid() { + Clock clock = mock(Clock.class); + long ticksPerSecond = 0; + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, ticksPerSecond, statusBuilder); + builder.build(0); + } + + @Test + public void testSaneBuild() { + final int PID = 0; + final long USER_INITIAL_TICKS = 1; + final long KERNEL_INITIAL_TICKS = 1; + + final long USER_LATER_TICKS = 10; + final long KERNEL_LATER_TICKS = 10; + + final long CLOCK1 = 10000; + final long CLOCK2 = 20000; + + final long TICKS_PER_SECOND = 100; + + final double CPU_LOAD_PERCENT = + 100.0 + * ((USER_LATER_TICKS + KERNEL_LATER_TICKS) - (USER_INITIAL_TICKS + KERNEL_INITIAL_TICKS)) + / TICKS_PER_SECOND + / ((CLOCK2 - CLOCK1) * 1E-3 /* millis to seconds */); + + final ProcessStatusInfo initialInfo = new ProcessStatusInfo(PID, USER_INITIAL_TICKS, KERNEL_INITIAL_TICKS); + final ProcessStatusInfo laterInfo = new ProcessStatusInfo(PID, USER_LATER_TICKS, KERNEL_LATER_TICKS); + + Clock clock = mock(Clock.class); + when(clock.getRealTimeMillis()).thenReturn(CLOCK2); + when(clock.getMonotonicTimeNanos()).thenReturn((long) (CLOCK1 * 1E6)).thenReturn((long) (CLOCK2 * 1E6)); + + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + when(statusBuilder.build(any(Integer.class))).thenReturn(initialInfo).thenReturn(laterInfo).thenReturn(null); + + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, TICKS_PER_SECOND, statusBuilder); + + builder.learnAbout(PID); + VmCpuStat stat = builder.build(PID); + + assertNotNull(stat); + assertEquals(PID, stat.getVmId()); + assertEquals(CLOCK2, stat.getTimeStamp()); + assertEquals(CPU_LOAD_PERCENT, stat.getCpuLoad(), 0.0001); + } + +}
--- a/client/src/main/java/com/redhat/thermostat/client/Main.java Thu Mar 29 23:52:18 2012 +0200 +++ b/client/src/main/java/com/redhat/thermostat/client/Main.java Thu Mar 29 23:54:17 2012 +0200 @@ -48,6 +48,7 @@ import javax.swing.SwingUtilities; import com.redhat.thermostat.client.appctx.ApplicationContext; +import com.redhat.thermostat.client.config.ConnectionConfiguration; import com.redhat.thermostat.client.locale.LocaleResources; import com.redhat.thermostat.client.ui.ConnectionSelectionDialog; import com.redhat.thermostat.client.ui.LayoutDebugHelper; @@ -82,15 +83,7 @@ System.exit(-1); } - StartupConfiguration config = null; - try { - config = new StartupConfiguration(System.currentTimeMillis(), args); - } catch (LaunchException le) { - logger.log(Level.SEVERE, - "Unable to instantiate startup configuration.", - le); - System.exit(Constants.EXIT_CONFIGURATION_ERROR); - } + StartupConfiguration config = new ConnectionConfiguration(); ConnectionProvider connProv = new MongoConnectionProvider(config); DAOFactory daoFactory = new MongoDAOFactory(connProv);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/main/java/com/redhat/thermostat/client/config/ConnectionConfiguration.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,49 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.client.config; + +import com.redhat.thermostat.common.config.StartupConfiguration; + +public class ConnectionConfiguration implements StartupConfiguration { + + @Override + public String getDBConnectionString() { + // TODO: this needs to be read from preferences or from the agent + // configuration + return "mongodb://127.0.0.1:27518"; + } +}
--- a/common/pom.xml Thu Mar 29 23:52:18 2012 +0200 +++ b/common/pom.xml Thu Mar 29 23:54:17 2012 +0200 @@ -101,6 +101,11 @@ <artifactId>easymock</artifactId> <version>3.1</version> </dependency> + <dependency> + <groupId>net.sf.jopt-simple</groupId> + <artifactId>jopt-simple</artifactId> + <version>4.3</version> + </dependency> </dependencies> <properties>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/Clock.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,52 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common; + +public interface Clock { + + /** + * Returns the current real time in milliseconds (measured since the UNIX epoch). + */ + long getRealTimeMillis(); + + /** + * Returns a time value corresponding to a monotonic clock measuring time + * in nanoseconds since some unspecified epoch. + */ + long getMonotonicTimeNanos(); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/SystemClock.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,51 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common; + +public class SystemClock implements Clock { + + @Override + public long getRealTimeMillis() { + return System.currentTimeMillis(); + } + + @Override + public long getMonotonicTimeNanos() { + return System.nanoTime(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/config/ConfigUtils.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,109 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common.config; + +import java.io.File; + +public class ConfigUtils { + + public static String getThermostatHome() throws InvalidConfigurationException { + // allow this to be specified also as a property, especially for + // tests, this overrides the env setting + String home = System.getProperty("THERMOSTAT_HOME"); + if (home == null) { + home = System.getenv("THERMOSTAT_HOME"); + } + + if (home == null) { + throw new InvalidConfigurationException("THERMOSTAT_HOME not defined..."); + } + return home; + } + + public static File getBackendsBaseDirectory() throws InvalidConfigurationException { + String loc = getThermostatHome() + File.separatorChar + "backends"; + File file = new File(loc); + return file; + } + + public static File getStorageBaseDirectory() throws InvalidConfigurationException { + String loc = getThermostatHome() + File.separatorChar + "storage"; + File file = new File(loc); + return file; + } + + public static File getStorageDirectory() throws InvalidConfigurationException { + return new File(getStorageBaseDirectory(), "db"); + } + + public static File getStorageConfigurationFile() throws InvalidConfigurationException { + return new File(getStorageBaseDirectory(), "db.properties"); + } + + public static File getStorageLogFile() throws InvalidConfigurationException { + File logDir = new File(getStorageBaseDirectory(), "logs"); + File logFile = new File(logDir, "db.log"); + + return logFile; + } + + public static File getStoragePidFile() throws InvalidConfigurationException { + File logDir = new File(getStorageBaseDirectory(), "run"); + File logFile = new File(logDir, "db.pid"); + + return logFile; + } + + public static File getBackendPropertyFile(String backendName) + throws InvalidConfigurationException + { + File backendsConfigDir = ConfigUtils.getBackendsBaseDirectory(); + File backendConfig = new File(backendsConfigDir, backendName); + backendConfig = new File(backendConfig, "backend.properties"); + if (!backendConfig.exists()) + throw new InvalidConfigurationException("backends configuration " + + "directory doesn't exist: " + + backendConfig); + return backendConfig; + } + + public static File getAgentConfigurationFile() throws InvalidConfigurationException { + + File agent = new File(getThermostatHome(), "agent"); + return new File(agent, "agent.properties"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/config/InvalidConfigurationException.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,56 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common.config; + +public class InvalidConfigurationException extends Exception { + + public InvalidConfigurationException() { + super(); + } + + public InvalidConfigurationException(String message) { + super(message); + } + + public InvalidConfigurationException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidConfigurationException(Throwable cause) { + super(cause); + } +}
--- a/common/src/main/java/com/redhat/thermostat/common/config/StartupConfiguration.java Thu Mar 29 23:52:18 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/common/config/StartupConfiguration.java Thu Mar 29 23:54:17 2012 +0200 @@ -36,246 +36,7 @@ package com.redhat.thermostat.common.config; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.config.Defaults; -import com.redhat.thermostat.common.Constants; -import com.redhat.thermostat.common.LaunchException; -import com.redhat.thermostat.common.utils.LoggingUtils; - -public class StartupConfiguration { - - private static Logger logger = LoggingUtils.getLogger(StartupConfiguration.class); - - private final long startTimestamp; - - private Properties props = new Properties(); - private Level logLevel; - private boolean localMode; - private int mongodPort; - private String mongoScript; - private int mongosPort; - private String databaseURI; - private String completeDatabaseURI; - private Arguments arguments; - - private String hostname; - - public StartupConfiguration(long startTime, String[] args) throws LaunchException { - - initFromDefaults(); - initFromArguments(args); - initFromProperties(); - - try { - InetAddress addr = InetAddress.getLocalHost(); - hostname = addr.getCanonicalHostName(); - } catch (UnknownHostException e) { - logger.log(Level.FINE, "Error determining local hostname."); - } - - startTimestamp = startTime; - } - - private void initFromDefaults() { - logLevel = Defaults.LOGGING_LEVEL; - localMode = Defaults.LOCAL_MODE; - mongodPort = Defaults.MONGOD_PORT; - mongosPort = Defaults.MONGOS_PORT; - databaseURI = Defaults.DATABASE_URI; - } - - private void initFromProperties() throws LaunchException { - if (props.getProperty(Constants.AGENT_PROPERTY_MONGOD_PORT) != null) { - mongodPort = Integer.valueOf(props.getProperty(Constants.AGENT_PROPERTY_MONGOD_PORT)); - } - if (props.getProperty(Constants.AGENT_PROPERTY_MONGO_LAUNCH_SCRIPT) != null) { - mongoScript = props.getProperty(Constants.AGENT_PROPERTY_MONGO_LAUNCH_SCRIPT); - logger.finest("Mongo launch script at: " + mongoScript); - } else { - throw new LaunchException("No mongo launch script in properties."); - } - if (props.getProperty(Constants.AGENT_PROPERTY_MONGOS_PORT) != null) { - mongosPort = Integer.valueOf(props.getProperty(Constants.AGENT_PROPERTY_MONGOS_PORT)); - } - } - - private void initFromArguments(String[] args) throws LaunchException { - arguments = new Arguments(args); - if (arguments.isModeSpecified()) { - localMode = arguments.getLocalMode(); - } - if (arguments.isLogLevelSpecified()) { - logLevel = arguments.getLogLevel(); - } - } - - public Level getLogLevel() { - return logLevel; - } - - public String getMongoLaunchScript() { - return mongoScript; - } - - public synchronized String getDatabaseURIAsString() { - if (completeDatabaseURI == null) { - if (localMode) { - completeDatabaseURI = getDBUriString(); - } else { - completeDatabaseURI = getClusterDBUriString(); - } - } - return completeDatabaseURI; - } - - public String getDBUriString() { - return databaseURI + ":" + mongodPort; - } - - // FIXME: this needs to go away, it's an implementation detail - public String getClusterDBUriString() { - return databaseURI + ":" + mongosPort; - } - - - public String getHostname() { - return hostname; - } +public interface StartupConfiguration { - public boolean getLocalMode() { - boolean local = false; - try { - local = arguments.getLocalMode(); - } catch (IllegalStateException ise) { - local = false; - } - return local; - } - - public List<String> getStartupBackendClassNames() { - String fullPropertyString = props.getProperty(Constants.AGENT_PROPERTY_BACKENDS); - if ((fullPropertyString == null) // Avoid NPE - || (fullPropertyString.length() == 0)) { /* If we do the split() on this empty string, - * it will produce an array of size 1 containing - * the empty string, which we do not want. - */ - return new ArrayList<String>(); - } else { - return Arrays.asList(fullPropertyString.trim().split(",")); - } - } - - public Map<String, String> getStartupBackendConfigMap(String backendName) { - String prefix = backendName + "."; - Map<String, String> configMap = new HashMap<String, String>(); - for (Entry<Object, Object> e : props.entrySet()) { - String key = (String) e.getKey(); - if (key.startsWith(prefix)) { - String value = (String) e.getValue(); - String mapKey = key.substring(prefix.length()); - configMap.put(mapKey, value); - } - } - return configMap; - } - - public long getStartTime() { - return startTimestamp; - } - - /** - * Exposes the command line arguments in a more object-oriented style. - * <p> - * Please check that an option was specified (using the various is*Specified() methods) before using its value. - */ - private class Arguments { - private final boolean localMode; - private final boolean modeSpecified; - private final Level logLevel; - private final boolean logLevelSpecified; - - public Arguments(String[] args) throws LaunchException { - boolean local = false; - boolean explicitMode = false; - Level level = null; - boolean explicitLogLevel = false; - boolean noProps = true; - for (int index = 0; index < args.length; index++) { - if (args[index].equals(Constants.AGENT_ARGUMENT_LOGLEVEL)) { - index++; - if (index < args.length) { - try { - level = Level.parse(args[index].toUpperCase()); - explicitLogLevel = true; - } catch (IllegalArgumentException iae) { - throw new LaunchException("Invalid argument for " + Constants.AGENT_ARGUMENT_LOGLEVEL, iae); - } - } else { - throw new LaunchException("Missing argument for " + Constants.AGENT_ARGUMENT_LOGLEVEL); - } - } else if (args[index].equals(Constants.AGENT_ARGUMENT_LOCAL)) { - explicitMode = true; - local = true; - } else if (args[index].equals(Constants.AGENT_ARGUMENT_PROPERTIES)) { - logger.finest("Properties argument specified."); - index++; - if (index < args.length) { - String propFile = args[index]; - logger.finest("Properties file: " + propFile); - try (Reader reader = new FileReader(propFile)) { - props.load(reader); - } catch (IOException ioe) { - throw new LaunchException("Unable to read properties file at " + propFile); - } - noProps = false; - } else { - throw new LaunchException("Missing argument for " + Constants.AGENT_ARGUMENT_PROPERTIES); - } - } - } - if (noProps) { - throw new LaunchException("Required properties file not specified."); - } - logLevel = level; - logLevelSpecified = explicitLogLevel; - localMode = local; - modeSpecified = explicitMode; - } - - public boolean isModeSpecified() { - return modeSpecified; - } - - public boolean getLocalMode() { - if (!isModeSpecified()) { - throw new IllegalStateException("local mode is not valid"); - } - return localMode; - } - - public boolean isLogLevelSpecified() { - return logLevelSpecified; - } - - public Level getLogLevel() { - if (!isLogLevelSpecified()) { - throw new IllegalStateException("log level not explicitly specified"); - } - return logLevel; - } - } + String getDBConnectionString(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/config/ThermostatOptionParser.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,42 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common.config; + +public interface ThermostatOptionParser { + void parse() throws InvalidConfigurationException; + void displayHelp(); +}
--- a/common/src/main/java/com/redhat/thermostat/common/dao/MongoConnection.java Thu Mar 29 23:52:18 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/common/dao/MongoConnection.java Thu Mar 29 23:54:17 2012 +0200 @@ -88,16 +88,7 @@ } private MongoURI getMongoURI() { - MongoURI uri = null; - switch (getType()) { - case LOCAL: - uri = new MongoURI(conf.getDBUriString()); - break; - case REMOTE: - throw new NotImplementedException("No mongo URI implemented for REMOTE."); - case CLUSTER: - throw new NotImplementedException("No mongo URI implemented for CLUSTER."); - } + MongoURI uri = new MongoURI(conf.getDBConnectionString()); return uri; }
--- a/common/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java Thu Mar 29 23:52:18 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/common/model/VmCpuStat.java Thu Mar 29 23:54:17 2012 +0200 @@ -56,6 +56,9 @@ return vmId; } + /** + * The cpu load in percent (as in 100.0 for 100%) + */ public double getCpuLoad() { return cpuLoad; }
--- a/common/src/main/java/com/redhat/thermostat/common/utils/LoggedExternalProcess.java Thu Mar 29 23:52:18 2012 +0200 +++ b/common/src/main/java/com/redhat/thermostat/common/utils/LoggedExternalProcess.java Thu Mar 29 23:54:17 2012 +0200 @@ -40,6 +40,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; +import java.util.List; import java.util.logging.Logger; public class LoggedExternalProcess extends Thread { @@ -48,6 +49,10 @@ private BufferedReader reader; private String[] commands; + public LoggedExternalProcess(List<String> commands) { + this(commands.toArray(new String[0])); + } + public LoggedExternalProcess(String[] commands) { this.commands = Arrays.copyOf(commands, commands.length); setDaemon(true);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/tools/Application.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,52 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools; + +import java.util.List; + +import com.redhat.thermostat.common.ActionNotifier; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.StartupConfiguration; + +public interface Application { + + void parseArguments(List<String> args) throws InvalidConfigurationException; + void run(); + void printHelp(); + ActionNotifier<ApplicationState> getNotifier(); + StartupConfiguration getConfiguration(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/tools/ApplicationState.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,50 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools; + +/** + * Denotes the condition this application is in. + */ +public enum ApplicationState { + + NONE, + SUCCESS, + FAIL, + HELP, + START, + STOP; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/tools/BasicApplication.java Thu Mar 29 23:54:17 2012 +0200 @@ -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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools; + +import com.redhat.thermostat.common.ActionNotifier; + +/** + * Common base class for all daemon and application + */ +public abstract class BasicApplication implements Application { + + private ActionNotifier<ApplicationState> notifier; + + public BasicApplication() { + this.notifier = new ActionNotifier<>(this); + } + + protected void notifyFail() { + notifier.fireAction(ApplicationState.FAIL); + } + + protected void notifySuccess() { + notifier.fireAction(ApplicationState.SUCCESS); + } + + @Override + public ActionNotifier<ApplicationState> getNotifier() { + return notifier; + } + + @Override + public void printHelp() {} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/TestUtils.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,100 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.Properties; +import java.util.Random; + +public class TestUtils { + + public static int getProcessId() { + String name = ManagementFactory.getRuntimeMXBean().getName(); + String pidPart = name.split("@")[0]; + return Integer.parseInt(pidPart); + } + + public static boolean isLinux() { + return (System.getProperty("os.name").toLowerCase().contains("linux")); + } + + public static String setupAgentConfigs() throws IOException { + // need to create dummy config files for the tests + Random random = new Random(); + + String tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar + + Math.abs(random.nextInt()) + File.separatorChar; + + System.setProperty("THERMOSTAT_HOME", tmpDir); + File agent = new File(tmpDir, "agent"); + agent.mkdirs(); + + File tmpConfigs = new File(agent, "agent.properties"); + + new File(agent, "run").mkdirs(); + new File(agent, "logs").mkdirs(); + + File backends = new File(tmpDir, "backends"); + File system = new File(backends, "system"); + system.mkdirs(); + + Properties props = new Properties(); + + props.setProperty("BACKENDS", "system"); + props.setProperty("LOG_LEVEL", "WARNING"); + + props.store(new FileOutputStream(tmpConfigs), "thermostat agent test properties"); + + // now write the configs for the backends + tmpConfigs = new File(system, "backend.properties"); + props = new Properties(); + props.setProperty("BACKEND_CLASS", + "com.redhat.thermostat.backend.system.SystemBackend"); + props.setProperty("DESCRIPTION", + "fluff backend for tests"); + props.setProperty("VENDOR", + "Red Hat, Inc."); + props.setProperty("VERSION", + "1.0"); + props.store(new FileOutputStream(tmpConfigs), "thermostat system backend properties"); + + return tmpDir; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/config/ConfigUtilsTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,82 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.common.config; + +import java.io.File; +import java.io.IOException; +import java.util.Random; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.TestUtils; + +public class ConfigUtilsTest { + + private String oldLocation; + + @Before + public void setUp() throws IOException { + TestUtils.setupAgentConfigs(); + } + + @Test + public void testLocations() throws InvalidConfigurationException, IOException { + String path = System.getProperty("THERMOSTAT_HOME"); + char s = File.separatorChar; + + Assert.assertEquals(path, ConfigUtils.getThermostatHome()); + + Assert.assertEquals(path + "backends", ConfigUtils.getBackendsBaseDirectory().getCanonicalPath()); + Assert.assertEquals(path + "storage", ConfigUtils.getStorageBaseDirectory().getCanonicalPath()); + Assert.assertEquals(path + "storage" + s + "db.properties", + ConfigUtils.getStorageConfigurationFile().getCanonicalPath()); + Assert.assertEquals(path + "storage" + s + "db", + ConfigUtils.getStorageDirectory().getCanonicalPath()); + Assert.assertEquals(path + "storage" + s + "logs" + s + "db.log", + ConfigUtils.getStorageLogFile().getCanonicalPath()); + Assert.assertEquals(path + "storage" + s + "run" + s + "db.pid", + ConfigUtils.getStoragePidFile().getCanonicalPath()); + + Assert.assertEquals(path + "backends" + s + "system" + s + "backend.properties", + ConfigUtils.getBackendPropertyFile("system").getCanonicalPath()); + + } +}
--- a/common/src/test/java/com/redhat/thermostat/common/dao/ConnectionTest.java Thu Mar 29 23:52:18 2012 +0200 +++ b/common/src/test/java/com/redhat/thermostat/common/dao/ConnectionTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -103,7 +103,7 @@ public void testInvalidLocalConnection() throws InterruptedException { StartupConfiguration conf = mock(StartupConfiguration.class); - when(conf.getDBUriString()).thenReturn("fluff"); + when(conf.getDBConnectionString()).thenReturn("fluff"); ConnectionProvider connProv = new MongoConnectionProvider(conf); Connection connection = connProv.createConnection();
--- a/distribution/config/agent.properties Thu Mar 29 23:52:18 2012 +0200 +++ b/distribution/config/agent.properties Thu Mar 29 23:54:17 2012 +0200 @@ -1,43 +1,5 @@ -## Mongo storage configuration -# To be used when agent is running with --local argument -mongod_port=27518 -mongo_launch_script=@project.build.directory@/scripts/localmongo.sh -# To be used when connecting on localhost without --local argument (cluster) -mongos_port=27517 -### Next few settings are used only by the mongo launch script -config_port=27519 -config_url=mongodb://127.0.0.1 -### End section specific to launch script -### Properties needed by client -agent_launch_script=@project.build.directory@/scripts/thermostat-agent -### End properties needed by client -# ## Backend Configuration -# This must be a comma separated list naming the fully qualified class name for -# each backend that should run -backends= -# Backends may also use their name as prefix for backend-specific configuration. -# For example, if backend foo requires a property called bar, then a line -# containing 'foo.bar=baz' should be included. 'foo' in this case should be -# the human-friendly alias for the backend, ie the string returned by the -# getName() method of the class listed in the backends string. -# -# For each backend, there may be a .active property specified. -# ie: for backend 'foo' there should be a 'foo.active = bar' line. 'bar' -# must be a comma separated list including one or more of: -# 'new' - The backend should attempt to attach to any new java process that -# starts. Existing processes should not be instrumented. -# 'all' - The backend should attempt to attach to all existing java -# java processes currently running on the machine. -# '[lvmid]' - One or more Local Virtual Machine IDs may be specified. These -# are equivalent to the Linux process id. This allows for the case -# of specific existing java processes to be instrumented. -# -# Alternatively, you may specify 'none' and the backend will not begin collecting -# from any VM, but will be available to clients who wish to activate it. -# -# If there is no .active property specified, then 'none' is implied. -# -## Sample backend configuration -#sample-backend.active=none -#sample-backend.myconfiguration=property \ No newline at end of file +# This must be a comma separated list naming the backend +# specific backend configurations will be searched under the +# $THERMOSTAT_HOME/backends/[backend_name.properties] +BACKENDS=system
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/config/db.properties Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,4 @@ +LOCAL=27518 +CLUSTER=27517 +BIND=127.0.0.1 +URL=mongodb://127.0.0.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/config/system/backend.properties Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,4 @@ +BACKEND_CLASS=com.redhat.thermostat.backend.system.SystemBackend +DESCRIPTION=gathers basic information from the system +VENDOR=thermostat project +VERSION=0.01
--- a/distribution/pom.xml Thu Mar 29 23:52:18 2012 +0200 +++ b/distribution/pom.xml Thu Mar 29 23:54:17 2012 +0200 @@ -139,5 +139,10 @@ <artifactId>thermostat-common</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-tools</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> </project>
--- a/distribution/scripts/thermostat-agent Thu Mar 29 23:52:18 2012 +0200 +++ b/distribution/scripts/thermostat-agent Thu Mar 29 23:54:17 2012 +0200 @@ -39,60 +39,20 @@ # Some necessary variables. JAVA_DIR="@java.dir@" JAVA="@java.home@/bin/java" -JCOMMON_JAR="${JAVA_DIR}/jcommon.jar" -MONGO_JAR="${JAVA_DIR}/mongo.jar" -BSON_JAR="${JAVA_DIR}/bson.jar" + +THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs" + +JCOMMON_JAR="${THERMOSTAT_LIBS}/jcommon.jar" +MONGO_JAR="${THERMOSTAT_LIBS}/mongo.jar" +BSON_JAR="${THERMOSTAT_LIBS}/bson.jar" +JOPT_JAR="${THERMOSTAT_LIBS}/jopt-simple-4.3.jar" TOOLS_JAR="@java.home@/../lib/tools.jar" -AGENT_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}" -# Find the directory where thermostat is installed. -# Note this will not work if there are symlinks to resolve that -# are not full paths. -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done -THERM_DIR=`dirname "$( cd -P "$( dirname "$SOURCE" )" && pwd )"` -# Some other necessary variables. -AGENT_CLASSPATH="${AGENT_CLASSPATH}:${THERM_DIR}/lib/thermostat-agent-@project.version@.jar:${THERM_DIR}/lib/thermostat-common-@project.version@.jar" -AGENT_MAIN="com.redhat.thermostat.agent.Main" - -AGENT_ARGS="--properties ${THERM_DIR}/config/agent.properties" - -function usage { - echo "Usage:" - echo " thermostat-agent <--local|--remote|--cluster>" -} - -function run_agent { - ${JAVA} -cp ${AGENT_CLASSPATH} ${AGENT_MAIN} ${AGENT_ARGS} -} -function run_local { - AGENT_ARGS="${AGENT_ARGS} --local" - run_agent - exit $? -} +SERVICE_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}:${JOPT_JAR}" -function run_remote { - echo "Remote agent not yet supported." - exit -1 -} - -function run_cluster { - echo "Cluster agent not yet supported." - exit -1 -} +THERM_DIR=${THERMOSTAT_LIBS} -if [ $# != 1 ]; then - usage - exit -1 -fi +SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERM_DIR}/thermostat-agent-@project.version@.jar:${THERM_DIR}/thermostat-common-@project.version@.jar:${THERM_DIR}/thermostat-tools-@project.version@.jar" +SERVICE_MAIN="com.redhat.thermostat.agent.AgentApplication" -if [ $1 = "--local" ]; then - run_local -elif [ $1 = "--remote" ]; then - run_remote -elif [ $1 = "--cluster" ]; then - run_cluster -else - usage - exit -1 -fi +${JAVA} -cp ${SERVICE_CLASSPATH} ${SERVICE_MAIN} $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/scripts/thermostat-db Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,58 @@ +#!/bin/bash +# +# 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 +# <http://www.gnu.org/licenses/>. +# +# 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. +# +##################################################################### +# +# Some necessary variables. +JAVA_DIR="@java.dir@" +JAVA="@java.home@/bin/java" + +THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs" + +JCOMMON_JAR="${THERMOSTAT_LIBS}/jcommon.jar" +MONGO_JAR="${THERMOSTAT_LIBS}/mongo.jar" +BSON_JAR="${THERMOSTAT_LIBS}/bson.jar" +JOPT_JAR="${THERMOSTAT_LIBS}/jopt-simple-4.3.jar" +TOOLS_JAR="@java.home@/../lib/tools.jar" + +SERVICE_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}:${JOPT_JAR}" + +THERM_DIR=${THERMOSTAT_LIBS} + +SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERM_DIR}/thermostat-agent-@project.version@.jar:${THERM_DIR}/thermostat-common-@project.version@.jar:${THERM_DIR}/thermostat-tools-@project.version@.jar" +SERVICE_MAIN="com.redhat.thermostat.tools.db.DBService" + +${JAVA} -cp ${SERVICE_CLASSPATH} ${SERVICE_MAIN} $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/scripts/thermostat-init-layout Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,76 @@ +#!/bin/bash +# +# 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 +# <http://www.gnu.org/licenses/>. +# +# 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. +# +##################################################################### +# +# Some necessary variables. +if [ "$THERMOSTAT_HOME" = "" ]; then + echo "THERMOSTAT_HOME not set!" + +else + THERMOSTAT_STORAGE="${THERMOSTAT_HOME}/storage/db" + THERMOSTAT_LOG="${THERMOSTAT_HOME}/storage/log" + THERMOSTAT_PID="${THERMOSTAT_HOME}/storage/run" + THERMOSTAT_BACKEND="${THERMOSTAT_HOME}/backends/system" + THERMOSTAT_BIN="${THERMOSTAT_HOME}/bin" + THERMOSTAT_AGENT_LOG="${THERMOSTAT_HOME}/agent/logs" + THERMOSTAT_AGENT_RUN="${THERMOSTAT_HOME}/agent/run" + THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs" + + echo "creating $THERMOSTAT_STORAGE" + mkdir -p $THERMOSTAT_STORAGE + + echo "creating $THERMOSTAT_LOG" + mkdir -p $THERMOSTAT_LOG + + echo "creating $THERMOSTAT_PID" + mkdir -p $THERMOSTAT_PID + + echo "creating $THERMOSTAT_BACKEND" + mkdir -p $THERMOSTAT_BACKEND + + echo "creating $THERMOSTAT_BIN" + mkdir -p $THERMOSTAT_BIN + + echo "creating $THERMOSTAT_AGENT_LOG" + mkdir -p $THERMOSTAT_AGENT_LOG + + echo "creating $THERMOSTAT_AGENT_RUN" + mkdir -p $THERMOSTAT_AGENT_RUN + + echo "creating $THERMOSTAT_LIBS" + mkdir -p $THERMOSTAT_LIBS +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/scripts/thermostat-service Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,58 @@ +#!/bin/bash +# +# 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 +# <http://www.gnu.org/licenses/>. +# +# 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. +# +##################################################################### +# +# Some necessary variables. +JAVA_DIR="@java.dir@" +JAVA="@java.home@/bin/java" + +THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs" + +JCOMMON_JAR="${THERMOSTAT_LIBS}/jcommon.jar" +MONGO_JAR="${THERMOSTAT_LIBS}/mongo.jar" +BSON_JAR="${THERMOSTAT_LIBS}/bson.jar" +JOPT_JAR="${THERMOSTAT_LIBS}/jopt-simple-4.3.jar" +TOOLS_JAR="@java.home@/../lib/tools.jar" + +SERVICE_CLASSPATH="${JCOMMON_JAR}:${MONGO_JAR}:${BSON_JAR}:${TOOLS_JAR}:${JOPT_JAR}" + +THERM_DIR=${THERMOSTAT_LIBS} + +SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERM_DIR}/thermostat-agent-@project.version@.jar:${THERM_DIR}/thermostat-common-@project.version@.jar:${THERM_DIR}/thermostat-tools-@project.version@.jar" +SERVICE_MAIN="com.redhat.thermostat.tools.ThermostatService" + +${JAVA} -cp ${SERVICE_CLASSPATH} ${SERVICE_MAIN} "$@"
--- a/pom.xml Thu Mar 29 23:52:18 2012 +0200 +++ b/pom.xml Thu Mar 29 23:54:17 2012 +0200 @@ -62,6 +62,7 @@ <module>agent</module> <module>client</module> <module>distribution</module> + <module>tools</module> </modules> <build>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/pom.xml Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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 + <http://www.gnu.org/licenses/>. + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat</artifactId> + <version>0.2-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>thermostat-tools</artifactId> + <packaging>jar</packaging> + + <name>Thermostat Tools</name> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.10</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.9.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-agent</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/src/main/java/com/redhat/thermostat/tools/ThermostatService.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,138 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.redhat.thermostat.agent.AgentApplication; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ActionNotifier; +import com.redhat.thermostat.common.NotImplementedException; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.StartupConfiguration; +import com.redhat.thermostat.tools.db.DBService; + +/** + * Simple service that allows starting Agent and DB Backend + * in a single step. + */ +public class ThermostatService implements Application, ActionListener<ApplicationState> { + + private Application database; + private AgentApplication agent; + + private ActionNotifier<ApplicationState> notifier; + + public ThermostatService() { + database = new DBService(); + agent = new AgentApplication(); + notifier = new ActionNotifier<>(this); + } + + @Override + public void parseArguments(List<String> args) throws InvalidConfigurationException { + // Currently, all the arguments are for the db. We only configure the + // agent accordingly to the database settings. + // so nothing else is done here at this stage + database.parseArguments(args); + database.getNotifier().addActionListener(this); + agent.getNotifier().addActionListener(this); + } + + @Override + public void run() { + // just run the database, if the database is successful, let the + // listeners start the agent for us. + database.run(); + } + + @Override + public void printHelp() { + // TODO, no, really, seriously + } + + @Override + public ActionNotifier<ApplicationState> getNotifier() { + return notifier; + } + + @Override + public StartupConfiguration getConfiguration() { + throw new NotImplementedException("NYI"); + } + + public static void main(String[] args) throws IOException, InvalidConfigurationException { + ThermostatService service = new ThermostatService(); + // TODO: other than failing, this should really print the help + // from the appropriate application instead, see the printHelp comment + // too. + service.parseArguments(Arrays.asList(args)); + service.run(); + } + + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + if (actionEvent.getSource().equals(database)) { + switch (actionEvent.getActionId()) { + case SUCCESS: + String dbUrl = database.getConfiguration().getDBConnectionString(); + List<String> args = new ArrayList<>(); + args.add("--dbUrl"); + args.add(dbUrl); + try { + agent.parseArguments(args); + System.err.println("starting agent now..."); + agent.run(); + } catch (InvalidConfigurationException e) { + notifier.fireAction(ApplicationState.FAIL); + } + break; + } + } else if (actionEvent.getSource().equals(agent)) { + // agent is running + switch (actionEvent.getActionId()) { + case START: + notifier.fireAction(ApplicationState.SUCCESS); + break; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBConfig.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,48 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools.db; + +/** + * Set of configuration option that the {@link DBService} understands. + */ +enum DBConfig { + + BIND, + LOCAL, + CLUSTER, + URL, +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBOptionParser.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,160 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools.db; + +import java.io.IOException; +import java.util.List; + +import joptsimple.OptionParser; +import joptsimple.OptionSet; + +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.ThermostatOptionParser; +import com.redhat.thermostat.tools.ApplicationState; + +class DBOptionParser implements ThermostatOptionParser { + + private boolean quiet; + + private DBStartupConfiguration configuration; + + private List<String> args; + private OptionParser parser; + + private DBArgs serviceAction; + + private boolean dryRun; + + DBOptionParser(DBStartupConfiguration configuration, List<String> args) { + this.args = args; + this.configuration = configuration; + parser = new OptionParser(); + } + + @Override + public void parse() throws InvalidConfigurationException { + + parser.accepts(DBArgs.START.option, DBArgs.START.description); + parser.accepts(DBArgs.STOP.option, DBArgs.STOP.description); + + parser.accepts(DBArgs.DRY.option, DBArgs.DRY.description); + + parser.accepts(DBArgs.HELP.option, DBArgs.HELP.description); + parser.accepts(DBArgs.QUIET.option, DBArgs.QUIET.description); + + OptionSet options = parser.parse(args.toArray(new String[0])); + if (!options.hasOptions() || options.has(DBArgs.HELP.option)) { + displayHelp(); + return; + } + + if (options.has(DBArgs.START.option)) { + serviceAction = DBArgs.START; + } else if (options.has(DBArgs.STOP.option)) { + serviceAction = DBArgs.STOP; + + } else { + throw new InvalidConfigurationException("either --start or --stop must be given"); + } + + if (options.has(DBArgs.DRY.option)) { + dryRun = true; + } + + if (options.has(DBArgs.QUIET.option)) { + quiet = true; + } + + // leave at the end, since it depends on the previous settings + String url = configuration.getUrl(); + long port = configuration.getLocalPort(); + configuration.setLocal(true); + if (options.has(DBArgs.CLUSTER.option)) { + port = configuration.getClusterPort(); + configuration.setLocal(false); + } + configuration.setDBConnectionString(url + ":" + port); + } + + boolean isDryRun() { + return dryRun; + } + + @Override + public void displayHelp() { + + if (quiet) return; + + try { + System.out.println("Module [DBService]"); + parser.printHelpOn(System.out); + } catch (IOException ignore) {} + } + + ApplicationState getAction() { + return serviceAction.state; + } + + static enum DBArgs { + + CLUSTER("cluster", "launch the db in cluster mode, if not specified, " + + "local mode is the default", ApplicationState.NONE), + + DRY("dry-run", "run the service in dry run mode", ApplicationState.NONE), + + HELP("help", "print this usage help", ApplicationState.HELP), + + START("start", "start the database", ApplicationState.START), + STOP("stop", "stop the database", ApplicationState.STOP), + + QUIET("quiet", "don't produce any output", ApplicationState.NONE); + + private String option; + private String description; + private ApplicationState state; + + DBArgs(String option, String description, ApplicationState state) { + this.option = option; + this.description = description; + this.state = state; + } + } + + boolean isQuiet() { + return quiet; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBService.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,277 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools.db; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +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.Properties; + +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.utils.LoggedExternalProcess; +import com.redhat.thermostat.tools.BasicApplication; + +public class DBService extends BasicApplication { + + private DBStartupConfiguration configuration; + private DBOptionParser parser; + + private static final String [] MONGO_BASIC_ARGS = { + "mongod", "--quiet", "--fork", "--nojournal", "--noauth", "--bind_ip" + }; + + private static final String [] MONGO_SHUTDOWN_ARGS = { + "mongod", "--shutdown", "--dbpath" + }; + + @Override + public void parseArguments(List<String> 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(); + + } + + 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.LOCAL.name())) { + String port = (String) properties.get(DBConfig.LOCAL.name()); + int localPort = Integer.parseInt(port); + configuration.setLocalPort(localPort); + } else { + throw new InvalidConfigurationException(DBConfig.LOCAL + " property missing"); + } + + if (properties.containsKey(DBConfig.CLUSTER.name())) { + String port = (String) properties.get(DBConfig.CLUSTER.name()); + int localPort = Integer.parseInt(port); + configuration.setClusterPort(localPort); + } else { + throw new InvalidConfigurationException(DBConfig.CLUSTER + " property missing"); + } + + if (properties.containsKey(DBConfig.URL.name())) { + String url = (String) properties.get(DBConfig.URL.name()); + configuration.setUrl(url); + } else { + throw new InvalidConfigurationException(DBConfig.URL + " 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 { + + String pid = checkPid(); + if (pid != null) { + String message = "cannot start server " + configuration.getDBPath() + + ", found pid file rom previous run, please, cleanup"; + display(message); + notifyFail(); + return; + } + + List<String> commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS)); + + // check that the db directory exist + display("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"); + if (configuration.isLocal()) { + commands.add(Long.toString(configuration.getLocalPort())); + } else { + commands.add(Long.toString(configuration.getClusterPort())); + } + + LoggedExternalProcess process = new LoggedExternalProcess(commands); + int status = process.runAndReturnResult(); + if (status == 0) { + pid = checkPid(); + if (pid == null) status = -1; + } + + if (status == 0) { + display("server listening on ip: " + configuration.getDBConnectionString()); + display("log file is here: " + configuration.getLogFile()); + display("pid: " + pid); + notifySuccess(); + + } else { + + String message = "cannot start server " + configuration.getDBPath() + + ", exit status: " + status + + ". Please check that your configuration is valid"; + display(message); + notifyFail(); + } + } + + private String checkPid() { + String pid = null; + // check the pid to be sure + 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 ignore) { + ignore.printStackTrace(); + pid = null; + } + } + + return pid; + } + + private void stopService() throws IOException, InterruptedException, InvalidConfigurationException { + check(); + + List<String> commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS)); + commands.add(configuration.getDBPath().getCanonicalPath()); + + LoggedExternalProcess process = new LoggedExternalProcess(commands); + int status = process.runAndReturnResult(); + if (status == 0) { + display("server shutdown complete: " + configuration.getDBPath()); + display("log file is here: " + configuration.getLogFile()); + notifySuccess(); + + } else { + // TODO: check the pid and see if it's running or not + // perhaps was already down + String message = "cannot shutdown server " + configuration.getDBPath() + + ", exit status: " + status + + ". Please check that your configuration is valid"; + display(message); + notifyFail(); + } + } + + @Override + public void run() { + + if (parser.isDryRun()) return; + + try { + switch (parser.getAction()) { + case START: + startService(); + break; + case STOP: + stopService(); + break; + } + } catch (Exception e) { + // TODO: exception should be at least logged + notifyFail(); + } + } + + 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 void printHelp() { + parser.displayHelp(); + } + + @Override + public DBStartupConfiguration getConfiguration() { + return configuration; + } + + private void display(String message) { + if (!parser.isQuiet()) { + System.out.println(message); + } + } + + public static void main(String[] args) throws InvalidConfigurationException { + DBService service = new DBService(); + service.parseArguments(Arrays.asList(args)); + service.run(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/src/main/java/com/redhat/thermostat/tools/db/DBStartupConfiguration.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,128 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools.db; + +import java.io.File; + +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.StartupConfiguration; + +class DBStartupConfiguration implements StartupConfiguration { + + private File dbPath; + private File logFile; + private File pidFile; + + private long localPort; + private long clusterPort; + + private String url; + + private String dbConnectionString; + + private String ip; + + private boolean local; + + 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; + } + + void setLocalPort(long localPort) { + this.localPort = localPort; + } + + public long getLocalPort() { + return localPort; + } + + public long getClusterPort() { + return clusterPort; + } + + void setClusterPort(long clusterPort) { + this.clusterPort = clusterPort; + } + + void setUrl(String url) { + this.url = url; + } + + public String getUrl() { + return url; + } + + 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; + } + + void setLocal(boolean local) { + this.local = local; + } + + public boolean isLocal() { + return local; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/src/test/java/com/redhat/thermostat/tools/db/DBServiceTest.java Thu Mar 29 23:54:17 2012 +0200 @@ -0,0 +1,202 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.tools.db; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.tools.ApplicationState; + +public class DBServiceTest { + + private static final String LOCAL = "27518"; + private static final String CLUSTER = "27517"; + + private static final String BIND = "127.0.0.1"; + + private static final String URL = "mongodb://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.LOCAL.name(), LOCAL); + props.setProperty(DBConfig.CLUSTER.name(), CLUSTER); + props.setProperty(DBConfig.URL.name(), URL); + + props.store(new FileOutputStream(tmpConfigs), "thermostat test properties"); + + } catch (IOException e) { + Assert.fail("cannot setup tests: " + e); + } + } + + @Test + public void testConfig() throws InvalidConfigurationException { + + List<String> args = new ArrayList<>(); + args.add("--quiet"); + args.add("--start"); + args.add("--dry-run"); + + DBService service = new DBService(); + service.parseArguments(args); + + service.run(); + + DBStartupConfiguration conf = service.getConfiguration(); + + Assert.assertEquals(tmpDir + DB, conf.getDBPath().getPath()); + Assert.assertEquals(Integer.parseInt(LOCAL), conf.getLocalPort()); + Assert.assertEquals(Integer.parseInt(CLUSTER), conf.getClusterPort()); + Assert.assertEquals(URL, conf.getUrl()); + } + + @Test + public void testListeners() throws InvalidConfigurationException, InterruptedException { + List<String> args = new ArrayList<>(); + args.add("--quiet"); + args.add("--start"); + + DBService service = new DBService(); + service.parseArguments(args); + + final CountDownLatch latch = new CountDownLatch(0); + final boolean[] result = new boolean[1]; + service.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = false; + break; + case SUCCESS: + result[0] = true; + break; + } + latch.countDown(); + } + }); + + service.run(); + latch.await(); + + Assert.assertTrue(result[0]); + + // FIXME: the server doesn't stop right away, but it's detached + // so we need to give some time... but there should be a better + // way than sleep... + Thread.sleep(2500); + + args = new ArrayList<>(); + args.add("--quiet"); + args.add("--stop"); + + // stop everything + service.parseArguments(args); + service.run(); + } + + @Test + public void testListenersFail() throws InvalidConfigurationException, InterruptedException { + List<String> args = new ArrayList<>(); + args.add("--quiet"); + + // unlikely is already running, since it's a random db directory... + args.add("--stop"); + + DBService service = new DBService(); + service.parseArguments(args); + + final CountDownLatch latch = new CountDownLatch(0); + final boolean[] result = new boolean[1]; + service.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = true; + break; + case SUCCESS: + result[0] = false; + break; + } + latch.countDown(); + } + }); + + service.run(); + latch.await(); + + Assert.assertTrue(result[0]); + } +}