/**
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2010], VMware, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
*/
package org.hyperic.bootstrap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.sigar.OperatingSystem;
import org.hyperic.sigar.SigarException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* Impl of {@link EmbeddedDatabaseController} that controls our built-in
* Postgres DB
* @author jhickey
*
*/
@Service
public class PostgresEmbeddedDatabaseController implements EmbeddedDatabaseController {
static final long DEFAUT_DB_PORT = 5432;
static final int DB_PROCESS_TIMEOUT = 60 * 1000;
private final String serverHome;
private final ProcessManager processManager;
private final OperatingSystem osInfo;
int dbPortStopCheckTries = 30;
private final Log log = LogFactory.getLog(PostgresEmbeddedDatabaseController.class);
@Autowired
public PostgresEmbeddedDatabaseController(
@Value("#{ systemProperties['server.home'] }") String serverHome,
ProcessManager processManager, OperatingSystem osInfo) {
this.serverHome = serverHome;
this.processManager = processManager;
this.osInfo = osInfo;
}
public boolean startBuiltInDB() throws SigarException, IOException {
String dbPidFile = serverHome + "/hqdb/data/postmaster.pid";
log
.debug("Checking if HQ built-in database is already running using pidfile: " +
dbPidFile);
long dbPid = processManager.getPidFromPidFile(dbPidFile);
if (dbPid != -1) {
log.info("HQ built-in database already running (pid file found: " + dbPidFile +
"), not starting it again.");
return true;
}
boolean fileDeleted = new File(dbPidFile).delete();
if (fileDeleted) {
log.info("Removed stale pid file " + dbPidFile);
}
log.info("Starting HQ built-in database...");
if (OperatingSystem.isWin32(osInfo.getName())) {
processManager.executeProcess(new String[] { serverHome + "/bin/db-start.bat" }, serverHome,
false, PostgresEmbeddedDatabaseController.DB_PROCESS_TIMEOUT);
} else {
processManager.executeProcess(new String[] { serverHome + "/bin/db-start.sh" }, serverHome,
false, PostgresEmbeddedDatabaseController.DB_PROCESS_TIMEOUT);
}
try {
if (!processManager.isPortInUse(getDBPort(), 10)) {
log.error("HQ built-in database failed to start");
log.error("The log file " + serverHome +
"/logs/hqdb.log may contain further details on why it failed to start");
return false;
}
} catch (Exception e) {
log.error("Unable to determine if HQ built-in database started: " + e.getMessage());
return false;
}
log.info("HQ built-in database started.");
return true;
}
public boolean stopBuiltInDB() throws SigarException, IOException {
String dbPidFile = serverHome + "/hqdb/data/postmaster.pid";
log.debug("Checking if HQ built-in database is running using pidfile: " + dbPidFile);
long dbPid = processManager.getPidFromPidFile(dbPidFile);
if (dbPid == -1) {
log.info("HQ built-in database not running");
return true;
}
log.info("Stopping HQ built-in database...");
if (OperatingSystem.isWin32(osInfo.getName())) {
processManager.executeProcess(new String[] { serverHome + "/bin/db-stop.bat" }, serverHome,
false, PostgresEmbeddedDatabaseController.DB_PROCESS_TIMEOUT);
} else {
processManager.executeProcess(new String[] { serverHome + "/bin/db-stop.sh" }, serverHome,
false, PostgresEmbeddedDatabaseController.DB_PROCESS_TIMEOUT);
}
//Guys 12/10/2011 - DB stop operation is fast enough but the port is left opened in a WAIT_FIN2 status
//for another 30-40 secs. As at this stage no further action can be taken, removing the isDBStopped check
//shall speed up the shutdown without removing functionality
log.info("Triggered stop script for HQ built in database.");
return true;
}
public long getDBPort() throws IOException {
log.debug("loading dbport...");
long port = PostgresEmbeddedDatabaseController.DEFAUT_DB_PORT;
FileInputStream fi = null;
File confFile = new File(serverHome + "/hqdb/data/postgresql.conf");
if (!confFile.exists()) {
log.warn("No postgresql.conf file found. Assuming default port " + port);
return port;
}
try {
fi = new FileInputStream(confFile);
Properties props = new Properties();
props.load(fi);
if (props.getProperty("port") != null) {
// postgres puts a comment on the same line as the prop value.
String fullPropString = props.getProperty("port");
String portStr = fullPropString.split("#")[0];
try {
port = Long.valueOf(portStr.trim());
} catch (NumberFormatException e) {
log.warn("Error getting built-in DB port from config file: " + e.getMessage() +
". Will try default port: " +
PostgresEmbeddedDatabaseController.DEFAUT_DB_PORT);
}
}
} finally {
if (fi != null)
fi.close();
}
log.debug("loaded dbport=" + port);
return port;
}
public boolean shouldUse() {
log.debug("checking hqdb dir exists: " + serverHome + "/hqdb");
return new File(serverHome + "/hqdb").exists();
}
boolean isDBStopped(int maxTries) throws Exception {
long dbPort = getDBPort();
boolean dbPortInUse = true;
for (int i = 0; i < maxTries; i++) {
dbPortInUse = processManager.isPortInUse(dbPort, 1);
if (dbPortInUse == false) {
return true;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// ignore
}
}
return false;
}
}