AMBARI-20055 - Add Upgrade Logic For Removal of clusterconfigmapping (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/9386eed4 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/9386eed4 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/9386eed4 Branch: refs/heads/trunk Commit: 9386eed4073cb8b75800f516ddfe01c3f6528bb4 Parents: e8e2df2 Author: Jonathan Hurley <[email protected]> Authored: Mon Feb 20 13:59:55 2017 -0500 Committer: Jonathan Hurley <[email protected]> Committed: Mon Feb 20 16:49:10 2017 -0500 ---------------------------------------------------------------------- .../orm/helpers/dbms/GenericDbmsHelper.java | 2 +- .../server/upgrade/UpgradeCatalog300.java | 92 ++++++++++- .../server/upgrade/UpgradeCatalog300Test.java | 155 +++++++++++++++++-- 3 files changed, 233 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/9386eed4/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java index 36fab83..f60c138 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/helpers/dbms/GenericDbmsHelper.java @@ -426,7 +426,7 @@ public class GenericDbmsHelper implements DbmsHelper { // org.eclipse.persistence.internal.databaseaccess.appendParameterInternal Object dbValue = databasePlatform.convertToDatabaseType(value); String valueString = value.toString(); - if (dbValue instanceof String) { + if (dbValue instanceof String || dbValue instanceof Enum) { valueString = "'" + value.toString() + "'"; } http://git-wip-us.apache.org/repos/asf/ambari/blob/9386eed4/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java index 0267a5e..d9b9b57 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java @@ -18,7 +18,9 @@ package org.apache.ambari.server.upgrade; +import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -44,6 +46,7 @@ import org.apache.ambari.server.state.Config; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.jdbc.support.JdbcUtils; import com.google.inject.Inject; import com.google.inject.Injector; @@ -55,11 +58,15 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog { */ private static final Logger LOG = LoggerFactory.getLogger(UpgradeCatalog300.class); - private static final String STAGE_TABLE = "stage"; - private static final String STAGE_STATUS_COLUMN = "status"; - private static final String STAGE_DISPLAY_STATUS_COLUMN = "display_status"; - private static final String REQUEST_TABLE = "request"; - private static final String REQUEST_DISPLAY_STATUS_COLUMN = "display_status"; + protected static final String STAGE_TABLE = "stage"; + protected static final String STAGE_STATUS_COLUMN = "status"; + protected static final String STAGE_DISPLAY_STATUS_COLUMN = "display_status"; + protected static final String REQUEST_TABLE = "request"; + protected static final String REQUEST_DISPLAY_STATUS_COLUMN = "display_status"; + protected static final String CLUSTER_CONFIG_TABLE = "clusterconfig"; + protected static final String CLUSTER_CONFIG_SELECTED_COLUMN = "selected"; + protected static final String CLUSTER_CONFIG_SELECTED_TIMESTAMP_COLUMN = "selected_timestamp"; + protected static final String CLUSTER_CONFIG_MAPPING_TABLE = "clusterconfigmapping"; @Inject DaoUtils daoUtils; @@ -104,6 +111,7 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog { @Override protected void executeDDLUpdates() throws AmbariException, SQLException { updateStageTable(); + updateClusterConfigurationTable(); } protected void updateStageTable() throws SQLException { @@ -120,6 +128,7 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog { */ @Override protected void executePreDMLUpdates() throws AmbariException, SQLException { + setSelectedConfigurationsAndRemoveMappingTable(); } /** @@ -189,7 +198,80 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog { } } }); + } + + /** + * Performs the following operations on {@code clusterconfig}: + * <ul> + * <li>Adds the {@link #CLUSTER_CONFIG_SELECTED_COLUMN} to + * {@link #CLUSTER_CONFIG_TABLE}. + * <li>Adds the {@link #CLUSTER_CONFIG_SELECTED_TIMESTAMP} to + * {@link #CLUSTER_CONFIG_TABLE}. + * </ul> + */ + protected void updateClusterConfigurationTable() throws SQLException { + dbAccessor.addColumn(CLUSTER_CONFIG_TABLE, + new DBAccessor.DBColumnInfo(CLUSTER_CONFIG_SELECTED_COLUMN, Short.class, null, 0, false)); + dbAccessor.addColumn(CLUSTER_CONFIG_TABLE, + new DBAccessor.DBColumnInfo(CLUSTER_CONFIG_SELECTED_TIMESTAMP_COLUMN, Long.class, null, 0, + false)); } + /** + * Performs the following operations on {@code clusterconfig} and + * {@code clusterconfigmapping}: + * <ul> + * <li>Sets both selected columns to the current config by querying + * {@link #CLUSTER_CONFIG_MAPPING_TABLE}. + * <li>Removes {@link #CLUSTER_CONFIG_MAPPING_TABLE}. + * </ul> + */ + protected void setSelectedConfigurationsAndRemoveMappingTable() throws SQLException { + // update the new selected columns + executeInTransaction(new Runnable() { + /** + * {@inheritDoc} + */ + @Override + public void run() { + String selectSQL = String.format( + "SELECT cluster_id, type_name, version_tag FROM %s WHERE selected = 1 ORDER BY cluster_id ASC, type_name ASC, version_tag ASC", + CLUSTER_CONFIG_MAPPING_TABLE); + + Statement statement = null; + ResultSet resultSet = null; + + long now = System.currentTimeMillis(); + + try { + statement = dbAccessor.getConnection().createStatement(); + resultSet = statement.executeQuery(selectSQL); + + while (resultSet.next()) { + final Long clusterId = resultSet.getLong("cluster_id"); + final String typeName = resultSet.getString("type_name"); + final String versionTag = resultSet.getString("version_tag"); + + // inefficient since this can be done with a single nested SELECT, + // but this way we can log what's happening which is more useful + String updateSQL = String.format( + "UPDATE %s SET selected = 1, selected_timestamp = %d WHERE cluster_id = %d AND type_name = '%s' AND version_tag = '%s'", + CLUSTER_CONFIG_TABLE, now, clusterId, typeName, versionTag); + + dbAccessor.executeQuery(updateSQL); + } + } catch (SQLException sqlException) { + throw new RuntimeException(sqlException); + } finally { + JdbcUtils.closeResultSet(resultSet); + JdbcUtils.closeStatement(statement); + } + } + }); + + // if the above execution and committed the transaction, then we can remove + // the cluster configuration mapping table + dbAccessor.dropTable(CLUSTER_CONFIG_MAPPING_TABLE); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/9386eed4/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java index ec001ec..a44c2b3 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java @@ -17,16 +17,84 @@ */ package org.apache.ambari.server.upgrade; +import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMockBuilder; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.newCapture; import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; import java.lang.reflect.Method; - +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +import javax.persistence.Cache; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; + +import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.controller.MaintenanceStateHelper; +import org.apache.ambari.server.orm.DBAccessor; +import org.apache.ambari.server.state.stack.OsFamily; +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.easymock.EasyMockRunner; +import org.easymock.Mock; +import org.easymock.MockType; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; + +import com.google.gson.Gson; +import com.google.inject.Binder; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.Provider; +@RunWith(EasyMockRunner.class) public class UpgradeCatalog300Test { + @Mock(type = MockType.STRICT) + private Provider<EntityManager> entityManagerProvider; + + @Mock(type = MockType.NICE) + private Injector injector; + + @Mock(type = MockType.NICE) + private EntityManager entityManager; + + @Mock(type = MockType.NICE) + private DBAccessor dbAccessor; + + @Mock(type = MockType.NICE) + private OsFamily osFamily; + + @Mock(type = MockType.NICE) + private Configuration configuration; + + @Before + public void init() { + reset(entityManagerProvider, injector); + + expect(entityManagerProvider.get()).andReturn(entityManager).anyTimes(); + + expect(injector.getInstance(Gson.class)).andReturn(null).anyTimes(); + expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null).anyTimes(); + + replay(entityManagerProvider, injector); + } + + @After + public void tearDown() { + } + @Test public void testExecuteDMLUpdates() throws Exception { Method addNewConfigurationsFromXml = AbstractUpgradeCatalog.class.getDeclaredMethod("addNewConfigurationsFromXml"); @@ -54,19 +122,86 @@ public class UpgradeCatalog300Test { @Test public void testExecuteDDLUpdates() throws Exception { - Method updateStageTable = UpgradeCatalog300.class.getDeclaredMethod("updateStageTable"); - UpgradeCatalog300 upgradeCatalog300 = createMockBuilder(UpgradeCatalog300.class) - .addMockedMethod(updateStageTable) - .createMock(); - - upgradeCatalog300.updateStageTable(); + Module module = new Module() { + @Override + public void configure(Binder binder) { + binder.bind(DBAccessor.class).toInstance(dbAccessor); + binder.bind(OsFamily.class).toInstance(osFamily); + binder.bind(EntityManager.class).toInstance(entityManager); + binder.bind(Configuration.class).toInstance(configuration); + } + }; + + Capture<DBAccessor.DBColumnInfo> clusterConfigSelectedColumn = newCapture(); + Capture<DBAccessor.DBColumnInfo> clusterConfigSelectedTimestampColumn = newCapture(); + dbAccessor.addColumn(eq(UpgradeCatalog300.CLUSTER_CONFIG_TABLE), capture(clusterConfigSelectedColumn)); + dbAccessor.addColumn(eq(UpgradeCatalog300.CLUSTER_CONFIG_TABLE), capture(clusterConfigSelectedTimestampColumn)); + + replay(dbAccessor, configuration); + + Injector injector = Guice.createInjector(module); + UpgradeCatalog300 upgradeCatalog300 = injector.getInstance(UpgradeCatalog300.class); + upgradeCatalog300.executeDDLUpdates(); - replay(upgradeCatalog300); + DBAccessor.DBColumnInfo capturedSelectedColumn = clusterConfigSelectedColumn.getValue(); + Assert.assertNotNull(capturedSelectedColumn); + Assert.assertEquals(UpgradeCatalog300.CLUSTER_CONFIG_SELECTED_COLUMN, capturedSelectedColumn.getName()); + Assert.assertEquals(Short.class, capturedSelectedColumn.getType()); - upgradeCatalog300.executeDDLUpdates(); + DBAccessor.DBColumnInfo capturedSelectedTimestampColumn = clusterConfigSelectedTimestampColumn.getValue(); + Assert.assertNotNull(capturedSelectedTimestampColumn); + Assert.assertEquals(UpgradeCatalog300.CLUSTER_CONFIG_SELECTED_TIMESTAMP_COLUMN, capturedSelectedTimestampColumn.getName()); + Assert.assertEquals(Long.class, capturedSelectedTimestampColumn.getType()); - verify(upgradeCatalog300); + verify(dbAccessor); } + /** + * Tests pre-DML executions. + * + * @throws Exception + */ + @Test + public void testExecutePreDMLUpdates() throws Exception { + Module module = new Module() { + @Override + public void configure(Binder binder) { + binder.bind(DBAccessor.class).toInstance(dbAccessor); + binder.bind(OsFamily.class).toInstance(osFamily); + binder.bind(EntityManager.class).toInstance(entityManager); + binder.bind(Configuration.class).toInstance(configuration); + } + }; + + EntityManagerFactory emFactory = EasyMock.createNiceMock(EntityManagerFactory.class); + Cache emCache = EasyMock.createNiceMock(Cache.class); + + expect(entityManager.getEntityManagerFactory()).andReturn(emFactory).atLeastOnce(); + expect(emFactory.getCache()).andReturn(emCache).atLeastOnce(); + + EntityTransaction mockTransaction = EasyMock.createNiceMock(EntityTransaction.class); + Connection mockConnection = EasyMock.createNiceMock(Connection.class); + Statement mockStatement = EasyMock.createNiceMock(Statement.class); + expect(dbAccessor.getConnection()).andReturn(mockConnection).once(); + expect(mockConnection.createStatement()).andReturn(mockStatement).once(); + + expect(mockStatement.executeQuery(EasyMock.anyString())).andReturn( + EasyMock.createNiceMock(ResultSet.class)); + + expect(entityManager.getTransaction()).andReturn( + mockTransaction).atLeastOnce(); + + dbAccessor.dropTable(UpgradeCatalog300.CLUSTER_CONFIG_MAPPING_TABLE); + EasyMock.expectLastCall().once(); + + replay(dbAccessor, entityManager, emFactory, emCache, mockConnection, mockTransaction, + mockStatement, configuration); + + Injector injector = Guice.createInjector(module); + UpgradeCatalog300 upgradeCatalog300 = injector.getInstance(UpgradeCatalog300.class); + upgradeCatalog300.executePreDMLUpdates(); + + verify(dbAccessor, entityManager, emFactory, emCache); + } }
