From 8bec1e0b9fcfe98accb45023c3e7efc98c965ed3 Mon Sep 17 00:00:00 2001 From: Alex Huang Date: Wed, 16 Mar 2011 17:58:24 -0700 Subject: [PATCH] added the concept of system integrity checking before a system starts --- build/build-cloud.xml | 8 + build/cloud.properties | 2 +- build/developer.xml | 3 +- build/package.xml | 3 + .../DefaultComponentLibrary.java | 9 ++ server/src/com/cloud/maint/Version.java | 5 + .../com/cloud/upgrade/dao/Upgrade217to22.java | 10 +- .../upgrade/dao/UpgradeSnapshot217to223.java | 10 +- .../src/com/cloud/upgrade/dao/VersionDao.java | 4 +- .../com/cloud/upgrade/dao/VersionDaoImpl.java | 146 ++---------------- .../dao/AdvanceZone217To223UpgradeTest.java | 10 +- .../dao/BasicZone217To223UpgradeTest.java | 10 +- .../dao/InstanceGroup217To223UpgradeTest.java | 10 +- .../utils/component/ComponentLibrary.java | 7 + .../utils/component/ComponentLocator.java | 16 +- 15 files changed, 73 insertions(+), 180 deletions(-) diff --git a/build/build-cloud.xml b/build/build-cloud.xml index f2e531008ce..767d6744f8d 100755 --- a/build/build-cloud.xml +++ b/build/build-cloud.xml @@ -75,6 +75,7 @@ + @@ -287,6 +288,13 @@ + + + + + + + diff --git a/build/cloud.properties b/build/cloud.properties index 095f394a7fe..1e91844ae54 100755 --- a/build/cloud.properties +++ b/build/cloud.properties @@ -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 diff --git a/build/developer.xml b/build/developer.xml index cf470203911..d5f1ebe80e8 100755 --- a/build/developer.xml +++ b/build/developer.xml @@ -148,11 +148,12 @@ - + diff --git a/build/package.xml b/build/package.xml index 854eb601143..dc2e77c2867 100755 --- a/build/package.xml +++ b/build/package.xml @@ -161,6 +161,9 @@ + + + diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 9c3821ee245..076e0b5d6a1 100644 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -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 getSystemIntegrityCheckers() { + ArrayList checkers = new ArrayList(); +// checkers.add(new DatabaseUpgradeChecker()); + return checkers; + } protected void populateDaos() { addDao("StackMaidDao", StackMaidDaoImpl.class); diff --git a/server/src/com/cloud/maint/Version.java b/server/src/com/cloud/maint/Version.java index e2e1da179c2..0c600b2c706 100644 --- a/server/src/com/cloud/maint/Version.java +++ b/server/src/com/cloud/maint/Version.java @@ -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])); } diff --git a/server/src/com/cloud/upgrade/dao/Upgrade217to22.java b/server/src/com/cloud/upgrade/dao/Upgrade217to22.java index acccfd8103d..086379354d0 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade217to22.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade217to22.java @@ -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 diff --git a/server/src/com/cloud/upgrade/dao/UpgradeSnapshot217to223.java b/server/src/com/cloud/upgrade/dao/UpgradeSnapshot217to223.java index 0eaa83a8cff..408d18eceba 100644 --- a/server/src/com/cloud/upgrade/dao/UpgradeSnapshot217to223.java +++ b/server/src/com/cloud/upgrade/dao/UpgradeSnapshot217to223.java @@ -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 diff --git a/server/src/com/cloud/upgrade/dao/VersionDao.java b/server/src/com/cloud/upgrade/dao/VersionDao.java index a922bd63627..300684eeeb5 100644 --- a/server/src/com/cloud/upgrade/dao/VersionDao.java +++ b/server/src/com/cloud/upgrade/dao/VersionDao.java @@ -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 findByVersion(String version, Step step); + String getCurrentVersion(); } diff --git a/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java b/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java index 3a5e33311d7..9811cb8ddb1 100644 --- a/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java +++ b/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java @@ -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 implements VersionDao { private static final Logger s_logger = Logger.getLogger(VersionDaoImpl.class); - protected HashMap, DbUpgrade[]> _upgradeMap = new HashMap, DbUpgrade[]>(); - - String _dumpPath = null; - final GenericSearchBuilder CurrentVersionSearch; final SearchBuilder AllFieldsSearch; protected VersionDaoImpl() { super(); - _upgradeMap.put(new Pair("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 implements V } - protected VersionVO findByVersion(String version, Step step) { + public VersionVO findByVersion(String version, Step step) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("version", version); sc.setParameters("step", step); @@ -86,14 +70,12 @@ public class VersionDaoImpl extends GenericDaoBase 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 implements V } } catch (SQLException e) { throw new CloudRuntimeException("Unable to get the current version", e); - } + } finally { + try { + conn.close(); + } catch (SQLException e) { + } + } SearchCriteria sc = CurrentVersionSearch.create(); @@ -126,119 +113,4 @@ public class VersionDaoImpl extends GenericDaoBase implements V List 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(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 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; - } } diff --git a/server/test/com/cloud/upgrade/dao/AdvanceZone217To223UpgradeTest.java b/server/test/com/cloud/upgrade/dao/AdvanceZone217To223UpgradeTest.java index a95633a7fb9..af9c02e98b0 100644 --- a/server/test/com/cloud/upgrade/dao/AdvanceZone217To223UpgradeTest.java +++ b/server/test/com/cloud/upgrade/dao/AdvanceZone217To223UpgradeTest.java @@ -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 { diff --git a/server/test/com/cloud/upgrade/dao/BasicZone217To223UpgradeTest.java b/server/test/com/cloud/upgrade/dao/BasicZone217To223UpgradeTest.java index 07b9da3666c..d8d25066a65 100644 --- a/server/test/com/cloud/upgrade/dao/BasicZone217To223UpgradeTest.java +++ b/server/test/com/cloud/upgrade/dao/BasicZone217To223UpgradeTest.java @@ -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 { diff --git a/server/test/com/cloud/upgrade/dao/InstanceGroup217To223UpgradeTest.java b/server/test/com/cloud/upgrade/dao/InstanceGroup217To223UpgradeTest.java index 58eba1ccbaa..59419697fda 100644 --- a/server/test/com/cloud/upgrade/dao/InstanceGroup217To223UpgradeTest.java +++ b/server/test/com/cloud/upgrade/dao/InstanceGroup217To223UpgradeTest.java @@ -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 { diff --git a/utils/src/com/cloud/utils/component/ComponentLibrary.java b/utils/src/com/cloud/utils/component/ComponentLibrary.java index 5ed4c9512e7..e6b91e5b539 100644 --- a/utils/src/com/cloud/utils/component/ComponentLibrary.java +++ b/utils/src/com/cloud/utils/component/ComponentLibrary.java @@ -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 getSystemIntegrityCheckers(); + /** * @return all of the daos */ diff --git a/utils/src/com/cloud/utils/component/ComponentLocator.java b/utils/src/com/cloud/utils/component/ComponentLocator.java index 9b4ae31ae38..f40eac4ecde 100755 --- a/utils/src/com/cloud/utils/component/ComponentLocator.java +++ b/utils/src/com/cloud/utils/component/ComponentLocator.java @@ -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>>> parse2(String filename) { + protected Ternary>>, List> 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 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>>>(handler, adapters); + return new Ternary>>, List>(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>>> result = parse2(filename); + Ternary>>, List> 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>> 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;