added the concept of system integrity checking before a system starts

This commit is contained in:
Alex Huang 2011-03-16 17:58:24 -07:00
parent 570c7c532e
commit 8bec1e0b9f
15 changed files with 73 additions and 180 deletions

View File

@ -75,6 +75,7 @@
<property name="server.dir" location="${base.dir}/server" />
<property name="server.test.dir" location="${server.dir}/test" />
<property name="server.dist.dir" location="${dist.dir}/client" />
<property name="db.scripts.dir" location="${target.dir}/db"/>
<!-- directories for core code compilation-->
<property name="core.dir" location="${base.dir}/core" />
@ -287,6 +288,13 @@
<include name="*.xml" />
</fileset>
</copy>
<copy overwrite="true" todir="${db.scripts.dir}">
<fileset dir="${setup.db.dir}">
<include name="**/*"/>
<exclude name="**/override/*"/>
</fileset>
</copy>
</target>
<path id="console-common.classpath">

View File

@ -3,7 +3,7 @@
# major.minor.patch versioning scheme for vmops
company.major.version=2
company.minor.version=2
company.patch.version=1
company.patch.version=3
svn.revision=2

View File

@ -148,11 +148,12 @@
</condition>
<antcall target="unzip" inheritAll="true"/>
<unwar overwrite="true" src="${deploy.work.dir}/client/client.war" dest="${server.deploy.to.dir}/webapps/client"/>
<copy todir="${server.deploy.to.dir}/lib">
<!-- <copy todir="${server.deploy.to.dir}/lib">
<fileset dir="${deploy.work.dir}/client/lib/">
<include name="*.jar"/>
</fileset>
</copy>
-->
<touch file="${server.deploy.to.dir}/webapps/client/WEB-INF/lib/scripts/vm/hypervisor/xenserver/version"/>
<echo file="${server.deploy.to.dir}/webapps/client/WEB-INF/lib/scripts/vm/hypervisor/xenserver/version" append="false" message="${version}.${build.number}"/>
<copy overwrite="true" todir="${server.deploy.to.dir}/conf">

View File

@ -161,6 +161,9 @@
<zipfileset dir="${scripts.target.dir}" prefix="WEB-INF/lib/scripts" filemode="555">
<include name="**/*" />
</zipfileset>
<zipfileset dir="${db.scripts.dir}" prefix="WEB-INF/lib/db" filemode="555">
<include name="**/*"/>
</zipfileset>
</war>
</target>

View File

@ -18,6 +18,7 @@
package com.cloud.configuration;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -132,6 +133,7 @@ import com.cloud.utils.component.ComponentLibrary;
import com.cloud.utils.component.ComponentLibraryBase;
import com.cloud.utils.component.ComponentLocator.ComponentInfo;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.SystemIntegrityChecker;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.ClusteredVirtualMachineManagerImpl;
import com.cloud.vm.ItWorkDaoImpl;
@ -148,6 +150,13 @@ import com.cloud.vm.dao.UserVmDetailsDaoImpl;
import com.cloud.vm.dao.VMInstanceDaoImpl;
public class DefaultComponentLibrary extends ComponentLibraryBase implements ComponentLibrary {
@Override
public List<SystemIntegrityChecker> getSystemIntegrityCheckers() {
ArrayList<SystemIntegrityChecker> checkers = new ArrayList<SystemIntegrityChecker>();
// checkers.add(new DatabaseUpgradeChecker());
return checkers;
}
protected void populateDaos() {
addDao("StackMaidDao", StackMaidDaoImpl.class);

View File

@ -47,6 +47,11 @@ public class Version {
return 0;
}
public static String trimToPatch(String version) {
String[] tokens = version.split("[.]");
return tokens[0] + "." + tokens[1]+ "." + tokens[2];
}
public static void main(String[] args) {
System.out.println("Result is " + compare(args[0], args[1]));
}

View File

@ -28,9 +28,9 @@ import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;
public class Upgrade217to22 implements DbUpgrade {
final static Logger s_logger = Logger.getLogger(Upgrade217to22.class);
@ -38,12 +38,12 @@ public class Upgrade217to22 implements DbUpgrade {
@Override
public File[] getPrepareScripts() {
File file = PropertiesUtil.findConfigFile("schema-21to22.sql");
String file = Script.findScript("","db/schema-21to22.sql");
if (file == null) {
throw new CloudRuntimeException("Unable to find the upgrade script, schema-21to22.sql");
}
return new File[] {file};
return new File[] {new File(file)};
}
protected void upgradeStoragePools(Connection conn) {
@ -864,12 +864,12 @@ public class Upgrade217to22 implements DbUpgrade {
public File[] getCleanupScripts() {
return null;
// File file = PropertiesUtil.findConfigFile("schema-21to22-cleanup.sql");
// String file = Script.findScript("", "db/schema-21to22-cleanup.sql");
// if (file == null) {
// throw new CloudRuntimeException("Unable to find the upgrade script, schema-21to22-cleanup.sql");
// }
//
// return new File[] { file };
// return new File[] { new File(file) };
}
@Override

View File

@ -19,24 +19,20 @@ package com.cloud.upgrade.dao;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
public class UpgradeSnapshot217to223 implements DbUpgrade {
@Override
public File[] getPrepareScripts() {
File file = PropertiesUtil.findConfigFile("schema-snapshot-217to223.sql");
String file = Script.findScript("", "db/schema-snapshot-217to223.sql");
if (file == null) {
throw new CloudRuntimeException("Unable to find the upgrade script, chema-snapshot-217to223.sql");
}
return new File[] {file};
return new File[] { new File(file)};
}
@Override

View File

@ -17,8 +17,10 @@
*/
package com.cloud.upgrade.dao;
import com.cloud.upgrade.dao.VersionVO.Step;
import com.cloud.utils.db.GenericDao;
public interface VersionDao extends GenericDao<VersionVO, Long> {
VersionVO findByVersion(String version, Step step);
String getCurrentVersion();
}

View File

@ -17,32 +17,21 @@
*/
package com.cloud.upgrade.dao;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.maint.Version;
import com.cloud.upgrade.dao.VersionVO.Step;
import com.cloud.utils.Pair;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.ScriptRunner;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Func;
@ -54,16 +43,11 @@ import com.cloud.utils.exception.CloudRuntimeException;
public class VersionDaoImpl extends GenericDaoBase<VersionVO, Long> implements VersionDao {
private static final Logger s_logger = Logger.getLogger(VersionDaoImpl.class);
protected HashMap<Pair<String, String>, DbUpgrade[]> _upgradeMap = new HashMap<Pair<String, String>, DbUpgrade[]>();
String _dumpPath = null;
final GenericSearchBuilder<VersionVO, String> CurrentVersionSearch;
final SearchBuilder<VersionVO> AllFieldsSearch;
protected VersionDaoImpl() {
super();
_upgradeMap.put(new Pair<String, String>("2.1.7", "2.2.3"), new DbUpgrade[] { new Upgrade217to22(), new UpgradeSnapshot217to223()});
CurrentVersionSearch = createSearchBuilder(String.class);
CurrentVersionSearch.select(null, Func.FIRST, CurrentVersionSearch.entity().getVersion());
@ -78,7 +62,7 @@ public class VersionDaoImpl extends GenericDaoBase<VersionVO, Long> implements V
}
protected VersionVO findByVersion(String version, Step step) {
public VersionVO findByVersion(String version, Step step) {
SearchCriteria<VersionVO> sc = AllFieldsSearch.create();
sc.setParameters("version", version);
sc.setParameters("step", step);
@ -86,14 +70,12 @@ public class VersionDaoImpl extends GenericDaoBase<VersionVO, Long> implements V
return findOneBy(sc);
}
@DB
protected String getCurrentVersion() {
Transaction txn = Transaction.currentTxn();
public String getCurrentVersion() {
Connection conn = null;
try {
s_logger.debug("Checking to see if the database is at a version before it was the version table is created");
conn = txn.getConnection();
conn = Transaction.getStandaloneConnection();
PreparedStatement pstmt = conn.prepareStatement("SHOW TABLES LIKE 'VERSION'");
ResultSet rs = pstmt.executeQuery();
@ -116,7 +98,12 @@ public class VersionDaoImpl extends GenericDaoBase<VersionVO, Long> implements V
}
} catch (SQLException e) {
throw new CloudRuntimeException("Unable to get the current version", e);
}
} finally {
try {
conn.close();
} catch (SQLException e) {
}
}
SearchCriteria<String> sc = CurrentVersionSearch.create();
@ -126,119 +113,4 @@ public class VersionDaoImpl extends GenericDaoBase<VersionVO, Long> implements V
List<String> vers = customSearch(sc, filter);
return vers.get(0);
}
protected void runScript(File file) {
try {
FileReader reader = new FileReader(file);
Connection conn = Transaction.getStandaloneConnection();
ScriptRunner runner = new ScriptRunner(conn, false, true);
runner.runScript(reader);
} catch (FileNotFoundException e) {
throw new CloudRuntimeException("Unable to find upgrade script, schema-21to22.sql", e);
} catch (IOException e) {
throw new CloudRuntimeException("Unable to read upgrade script, schema-21to22.sql", e);
} catch (SQLException e) {
throw new CloudRuntimeException("Unable to execute upgrade script, schema-21to22.sql", e);
}
}
@DB
protected void upgrade(String dbVersion, String currentVersion) throws ConfigurationException {
s_logger.info("Database upgrade must be performed from " + dbVersion + " to " + currentVersion);
DbUpgrade[] upgrades = _upgradeMap.get(new Pair<String, String>(dbVersion, currentVersion));
if (upgrades == null) {
throw new ConfigurationException("There is no upgrade path from " + dbVersion + " to " + currentVersion);
}
if (Version.compare(currentVersion, upgrades[upgrades.length - 1].getUpgradedVersion()) != 0) {
throw new ConfigurationException("The end upgrade version is actually at " + upgrades[upgrades.length - 1].getUpgradedVersion() + " but our management server code version is at " + currentVersion);
}
boolean supportsRollingUpgrade = true;
for (DbUpgrade upgrade : upgrades) {
if (!upgrade.supportsRollingUpgrade()) {
supportsRollingUpgrade = false;
break;
}
}
if (!supportsRollingUpgrade) {
// TODO: Check if the other management server is still running by looking at the database. If so, then throw an exception.
}
for (DbUpgrade upgrade : upgrades) {
s_logger.info("Running upgrade " + upgrade.getClass().getSimpleName() + " to upgrade from " + upgrade.getUpgradableVersionRange()[0] + "-" + upgrade.getUpgradableVersionRange()[1] + " to " + upgrade.getUpgradedVersion());
Transaction txn = Transaction.currentTxn();
txn.start();
Connection conn;
try {
conn = txn.getConnection();
} catch (SQLException e) {
throw new CloudRuntimeException("Unable to upgrade the database", e);
}
File[] scripts = upgrade.getPrepareScripts();
if (scripts != null) {
for (File script : scripts) {
runScript(script);
}
}
upgrade.performDataMigration(conn);
VersionVO version = new VersionVO(upgrade.getUpgradedVersion());
persist(version);
txn.commit();
}
for (DbUpgrade upgrade : upgrades) {
s_logger.info("Cleanup upgrade " + upgrade.getClass().getSimpleName() + " to upgrade from " + upgrade.getUpgradableVersionRange()[0] + "-" + upgrade.getUpgradableVersionRange()[1] + " to " + upgrade.getUpgradedVersion());
VersionVO version = findByVersion(upgrade.getUpgradedVersion(), Step.Upgrade);
Transaction txn = Transaction.currentTxn();
txn.start();
File[] scripts = upgrade.getCleanupScripts();
if (scripts != null) {
for (File script : scripts) {
runScript(script);
}
}
version.setStep(Step.Complete);
version.setUpdated(new Date());
update(version.getId(), version);
txn.commit();
}
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
_dumpPath = (String)params.get("upgrade.dump.path");
if (_dumpPath == null) {
_dumpPath = System.getenv("upgrade.dump.path");
if (_dumpPath == null) {
_dumpPath = "/var/log/";
}
}
String dbVersion = getCurrentVersion();
String currentVersion = this.getClass().getPackage().getImplementationVersion();
if (currentVersion == null) {
currentVersion = this.getClass().getSuperclass().getPackage().getImplementationVersion();
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("DB version = " + dbVersion + " Code Version = " + currentVersion);
}
if (Version.compare(dbVersion, currentVersion) > 0) {
throw new ConfigurationException("Database version " + dbVersion + " is higher than management software version " + currentVersion);
}
if (Version.compare(dbVersion, currentVersion) == 0) {
return true;
}
upgrade(dbVersion, currentVersion);
return true;
}
}

View File

@ -23,8 +23,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.ConfigurationException;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
@ -61,16 +59,12 @@ public class AdvanceZone217To223UpgradeTest extends TestCase {
PreparedStatement pstmt;
VersionDaoImpl dao = ComponentLocator.inject(VersionDaoImpl.class);
DatabaseUpgradeChecker checker = ComponentLocator.inject(DatabaseUpgradeChecker.class);
String version = dao.getCurrentVersion();
assert version.equals("2.1.7") : "Version returned is not 2.1.7 but " + version;
try {
dao.upgrade("2.1.7", "2.2.3");
} catch (ConfigurationException e) {
s_logger.warn("Exception: ", e);
assert false : "The test failed. Check logs";
}
checker.upgrade("2.1.7", "2.2.3");
conn = Transaction.getStandaloneConnection();
try {

View File

@ -23,8 +23,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.ConfigurationException;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
@ -61,6 +59,7 @@ public class BasicZone217To223UpgradeTest extends TestCase {
PreparedStatement pstmt;
VersionDaoImpl dao = ComponentLocator.inject(VersionDaoImpl.class);
DatabaseUpgradeChecker checker = ComponentLocator.inject(DatabaseUpgradeChecker.class);
String version = dao.getCurrentVersion();
@ -70,12 +69,7 @@ public class BasicZone217To223UpgradeTest extends TestCase {
s_logger.debug("Basic zone test version is " + version);
}
try {
dao.upgrade("2.1.7", "2.2.3");
} catch (ConfigurationException e) {
s_logger.warn("Exception: ", e);
assert false : "The test failed. Check logs";
}
checker.upgrade("2.1.7", "2.2.3");
conn = Transaction.getStandaloneConnection();
try {

View File

@ -24,8 +24,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.naming.ConfigurationException;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
@ -62,6 +60,7 @@ public class InstanceGroup217To223UpgradeTest extends TestCase {
PreparedStatement pstmt;
VersionDaoImpl dao = ComponentLocator.inject(VersionDaoImpl.class);
DatabaseUpgradeChecker checker = ComponentLocator.inject(DatabaseUpgradeChecker.class);
String version = dao.getCurrentVersion();
@ -71,12 +70,7 @@ public class InstanceGroup217To223UpgradeTest extends TestCase {
s_logger.debug("Basic zone test version is " + version);
}
try {
dao.upgrade("2.1.7", "2.2.3");
} catch (ConfigurationException e) {
s_logger.warn("Exception: ", e);
assert false : "The test failed. Check logs";
}
checker.upgrade("2.1.7", "2.2.3");
conn = Transaction.getStandaloneConnection();
try {

View File

@ -34,6 +34,13 @@ import com.cloud.utils.db.GenericDao;
*
*/
public interface ComponentLibrary {
/**
* @return a list of SytemIntegrityCheckers which is run before other
* components are started to check if the system are fit to check
* the system.
*/
List<SystemIntegrityChecker> getSystemIntegrityCheckers();
/**
* @return all of the daos
*/

View File

@ -62,6 +62,7 @@ import org.xml.sax.helpers.DefaultHandler;
import com.cloud.utils.Pair;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.Ternary;
import com.cloud.utils.db.DatabaseCallback;
import com.cloud.utils.db.DatabaseCallbackFilter;
import com.cloud.utils.db.GenericDao;
@ -113,7 +114,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
return getLocatorName();
}
protected Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>> parse2(String filename) {
protected Ternary<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>, List<SystemIntegrityChecker>> parse2(String filename) {
try {
SAXParserFactory spfactory = SAXParserFactory.newInstance();
SAXParser saxParser = spfactory.newSAXParser();
@ -147,6 +148,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
ComponentLibrary library = null;
List<SystemIntegrityChecker> checkers = null;
if (handler.library != null) {
Class<?> clazz = Class.forName(handler.library);
library = (ComponentLibrary)clazz.newInstance();
@ -154,13 +156,14 @@ public class ComponentLocator implements ComponentLocatorMBean {
_managerMap.putAll(library.getManagers());
adapters.putAll(library.getAdapters());
_factories.putAll(library.getFactories());
checkers = library.getSystemIntegrityCheckers();
}
_daoMap.putAll(handler.daos);
_managerMap.putAll(handler.managers);
adapters.putAll(handler.adapters);
return new Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>>(handler, adapters);
return new Ternary<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>, List<SystemIntegrityChecker>>(handler, adapters, checkers);
} catch (ParserConfigurationException e) {
s_logger.error("Unable to load " + _serverName + " due to errors while parsing " + filename, e);
@ -182,7 +185,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
protected void parse(String filename) {
Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>> result = parse2(filename);
Ternary<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>, List<SystemIntegrityChecker>> result = parse2(filename);
if (result == null) {
s_logger.info("Skipping configuration using " + filename);
return;
@ -191,6 +194,11 @@ public class ComponentLocator implements ComponentLocatorMBean {
XmlHandler handler = result.first();
HashMap<String, List<ComponentInfo<Adapter>>> adapters = result.second();
try {
if (result.third() != null) {
for (SystemIntegrityChecker checker : result.third()) {
checker.check();
}
}
startDaos(); // daos should not be using managers and adapters.
instantiateAdapters(adapters);
instantiateManagers();
@ -1019,7 +1027,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
itManagers.remove();
if (manager.singleton == true) {
Singleton singleton = s_singletons.get(manager.clazz);
if (singleton.state == Singleton.State.Started) {
if (singleton != null && singleton.state == Singleton.State.Started) {
s_logger.info("Asking Manager " + manager.getName() + " to shutdown.");
manager.instance.stop();
singleton.state = Singleton.State.Stopped;