This is an automated email from the ASF dual-hosted git repository.

rlevas pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 249af2b  [AMBARI-23129] Multiple issues while executing Ambari server 
upgrade to Ambari 2.7.0 (#608)
249af2b is described below

commit 249af2b0cc03d57b05ce3a259524b16e870363e3
Author: Robert Levas <[email protected]>
AuthorDate: Sat Mar 10 16:35:14 2018 -0500

    [AMBARI-23129] Multiple issues while executing Ambari server upgrade to 
Ambari 2.7.0 (#608)
    
    * [AMBARI-23129] Multiple issues while executing Ambari server upgrade to 
Ambari 2.7.0
    
    * [AMBARI-23129] Multiple issues while executing Ambari server upgrade to 
Ambari 2.7.0
---
 .../ambari/server/controller/AmbariServer.java     |   4 +-
 .../org/apache/ambari/server/orm/DBAccessor.java   |  34 ++-
 .../apache/ambari/server/orm/DBAccessorImpl.java   | 174 ++++++++++++---
 .../ambari/server/orm/GuiceJpaInitializer.java     |  29 ++-
 .../security/ldap/AmbariLdapDataPopulator.java     |  29 ++-
 .../ambari/server/state/cluster/ClustersImpl.java  | 234 +++++++++++++++------
 .../ambari/server/upgrade/SchemaUpgradeHelper.java |  13 +-
 .../ambari/server/upgrade/UpgradeCatalog270.java   | 234 +++++++++++++++++++++
 .../ambari/server/orm/DBAccessorImplTest.java      |  70 ++++++
 .../security/ldap/AmbariLdapDataPopulatorTest.java |   1 -
 .../server/upgrade/UpgradeCatalog270Test.java      | 139 ++++++++++++
 .../apache/ambari/server/upgrade/UpgradeTest.java  |   4 -
 12 files changed, 853 insertions(+), 112 deletions(-)

diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 1651f1a..9eedd26 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -1077,7 +1077,9 @@ public class AmbariServer {
 
       setupProxyAuth();
 
-      injector.getInstance(GuiceJpaInitializer.class);
+      // Start and Initialize JPA
+      GuiceJpaInitializer jpaInitializer = 
injector.getInstance(GuiceJpaInitializer.class);
+      jpaInitializer.setInitialized(); // This must be called to alert Ambari 
that JPA is initialized.
 
       DatabaseConsistencyCheckHelper.checkDBVersionCompatible();
 
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java
index f0431e9..731cf00 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessor.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.ambari.server.configuration.Configuration.DatabaseType;
 import org.apache.commons.lang.builder.EqualsBuilder;
@@ -372,16 +373,33 @@ public interface DBAccessor {
    * Execute select {@code columnName} from {@code tableName}
    * where {@code columnNames} values = {@code values}
    *
-   * @param tableName
-   * @param columnName
-   * @param columnNames
-   * @param values
-   * @param ignoreFailure
-   * @return
+   * @param tableName            the table name
+   * @param columnName           the name of the column with the data to select
+   * @param conditionColumnNames an array of column names to use in the where 
clause
+   * @param conditionValues      an array of value to pair with the column 
names in conditionColumnNames
+   * @param ignoreFailure        true to ignore failures executing the query; 
false otherwise (errors building the query will be thrown, however)
+   * @return a list of integers
    * @throws SQLException
    */
-  List<Integer> getIntColumnValues(String tableName, String columnName, 
String[] columnNames,
-                                   String[] values, boolean ignoreFailure) 
throws SQLException;
+  List<Integer> getIntColumnValues(String tableName, String columnName, 
String[] conditionColumnNames,
+                                   String[] conditionValues, boolean 
ignoreFailure) throws SQLException;
+
+  /**
+   * Execute select {@code keyColumnName}, {@code valueColumnName} from {@code 
tableName}
+   * where {@code columnNames} values = {@code values}
+   *
+   * @param tableName            the table name
+   * @param keyColumnName        the name of the column with the key data to 
select
+   * @param valueColumnName      the name of the column with the value data to 
select
+   * @param conditionColumnNames an array of column names to use in the where 
clause
+   * @param conditionValues      an array of value to pair with the column 
names in conditionColumnNames
+   * @param ignoreFailure        true to ignore failures executing the query; 
false otherwise (errors building the query will be thrown, however)
+   * @return a map of key to values
+   * @throws SQLException
+   */
+  Map<Long, String> getKeyToStringColumnMap(String tableName, String 
keyColumnName, String valueColumnName,
+                                            String[] conditionColumnNames, 
String[] conditionValues,
+                                            boolean ignoreFailure) throws 
SQLException;
 
   /**
    * Drop table from schema
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java
index 3a42342..ed3f8f2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/DBAccessorImpl.java
@@ -35,8 +35,10 @@ import java.sql.Statement;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.configuration.Configuration;
@@ -1446,41 +1448,73 @@ public class DBAccessorImpl implements DBAccessor {
    * {@inheritDoc}
    */
   @Override
-  public List<Integer> getIntColumnValues(String tableName, String columnName, 
String[] ConditionColumnNames,
+  public List<Integer> getIntColumnValues(String tableName, String columnName, 
String[] conditionColumnNames,
                                           String[] values, boolean 
ignoreFailure) throws SQLException {
+    return executeQuery(tableName, new String[]{columnName}, 
conditionColumnNames, values, ignoreFailure,
+        new ResultGetter<List<Integer>>() {
+          private List<Integer> results = new ArrayList<>();
 
-    if (!tableExists(tableName)) {
-      throw new IllegalArgumentException(String.format("%s table does not 
exist", tableName));
-    }
-    if (!tableHasColumn(tableName, columnName)) {
-      throw new IllegalArgumentException(String.format("%s table does not 
contain %s column", tableName, columnName));
-    }
-    StringBuilder builder = new StringBuilder();
-    builder.append("SELECT ").append(columnName).append(" FROM 
").append(tableName);
-    if (ConditionColumnNames != null && ConditionColumnNames.length > 0) {
-      for (String name : ConditionColumnNames) {
-        if (!tableHasColumn(tableName, name)) {
-          throw new IllegalArgumentException(String.format("%s table does not 
contain %s column", tableName, name));
-        }
-      }
-      if (ConditionColumnNames.length != values.length) {
-        throw new IllegalArgumentException("number of columns should be equal 
to number of values");
-      }
-      builder.append(" WHERE 
").append(ConditionColumnNames[0]).append("='").append(values[0]).append("'");
-      for (int i = 1; i < ConditionColumnNames.length; i++) {
-        builder.append(" AND 
").append(ConditionColumnNames[i]).append("='").append(values[i]).append("'");
-      }
-    }
+          @Override
+          public void collect(ResultSet resultSet) throws SQLException {
+            results.add(resultSet.getInt(1));
+          }
 
-    List<Integer> result = new ArrayList<>();
+          @Override
+          public List<Integer> getResult() {
+            return results;
+          }
+        });
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Map<Long, String> getKeyToStringColumnMap(String tableName, String 
keyColumnName, String valueColumnName,
+                                            String[] conditionColumnNames, 
String[] values, boolean ignoreFailure) throws SQLException {
+    return executeQuery(tableName, new String[]{keyColumnName, 
valueColumnName}, conditionColumnNames, values, ignoreFailure,
+        new ResultGetter<Map<Long, String>>() {
+          Map<Long, String> map = new HashMap<>();
+
+          @Override
+          public void collect(ResultSet resultSet) throws SQLException {
+            map.put(resultSet.getLong(1), resultSet.getString(2));
+          }
+
+          @Override
+          public Map<Long, String> getResult() {
+            return map;
+          }
+        });
+  }
+
+  /**
+   * Executes a query returning data as specified by the {@link ResultGetter} 
implementation.
+   *
+   * @param tableName            the table name
+   * @param requestedColumnNames an array of column names to select
+   * @param conditionColumnNames an array of column names to use in the where 
clause
+   * @param conditionValues      an array of value to pair with the column 
names in conditionColumnNames
+   * @param ignoreFailure        true to ignore failures executing the query; 
false otherwise (errors building the query will be thrown, however)
+   * @param resultGetter         a {@link ResultGetter} implementation used to 
format the data into the expected return value
+   * @return the result from the resultGetter
+   * @throws SQLException
+   */
+  protected <T> T executeQuery(String tableName, String[] requestedColumnNames,
+                               String[] conditionColumnNames, String[] 
conditionValues,
+                               boolean ignoreFailure, ResultGetter<T> 
resultGetter) throws SQLException {
+
+    // Build the query...
+    String query = buildQuery(tableName, requestedColumnNames, 
conditionColumnNames, conditionValues);
+
+    // Execute the query
     Statement statement = getConnection().createStatement();
     ResultSet resultSet = null;
-    String query = builder.toString();
     try {
       resultSet = statement.executeQuery(query);
       if (resultSet != null) {
         while (resultSet.next()) {
-          result.add(resultSet.getInt(1));
+          resultGetter.collect(resultSet);
         }
       }
     } catch (SQLException e) {
@@ -1496,7 +1530,72 @@ public class DBAccessorImpl implements DBAccessor {
         statement.close();
       }
     }
-    return result;
+
+    return resultGetter.getResult();
+  }
+
+  /**
+   * Build a SELECT statement using the supplied table name, request columns 
and conditional column/value pairs.
+   * <p>
+   * The conditional pairs are optional but multiple pairs will be ANDed 
together.
+   * <p>
+   * Examples:
+   * <ul>
+   * <li>SELECT id FROM table1</li>
+   * <li>SELECT id FROM table1 WHERE name='value1'</li>
+   * <li>SELECT id FROM table1 WHERE name='value1' AND key='key1'</li>
+   * <li>SELECT id, name FROM table1 WHERE key='key1'</li>
+   * <li>SELECT id, name FROM table1 WHERE key='key1' AND allowed='1'</li>
+   * </ul>
+   *
+   * @param tableName            the table name
+   * @param requestedColumnNames an array of column names to select
+   * @param conditionColumnNames an array of column names to use in the where 
clause
+   * @param conditionValues      an array of value to pair with the column 
names in conditionColumnNames
+   * @return a query string
+   * @throws SQLException
+   */
+  protected String buildQuery(String tableName, String[] requestedColumnNames, 
String[] conditionColumnNames, String[] conditionValues) throws SQLException {
+    if (!tableExists(tableName)) {
+      throw new IllegalArgumentException(String.format("%s table does not 
exist", tableName));
+    }
+    StringBuilder builder = new StringBuilder();
+    builder.append("SELECT ");
+
+    // Append the requested column names:
+    if ((requestedColumnNames == null) || (requestedColumnNames.length == 0)) {
+      throw new IllegalArgumentException("no columns for the select have been 
set");
+    }
+    for (String name : requestedColumnNames) {
+      if (!tableHasColumn(tableName, name)) {
+        throw new IllegalArgumentException(String.format("%s table does not 
contain %s column", tableName, name));
+      }
+    }
+    builder.append(requestedColumnNames[0]);
+    for (int i = 1; i < requestedColumnNames.length; i++) {
+      builder.append(", ").append(requestedColumnNames[1]);
+    }
+
+    // Append the source table
+    builder.append(" FROM ").append(tableName);
+
+    // Add the WHERE clause using the conditionColumnNames and the 
conditionValues
+    if (conditionColumnNames != null && conditionColumnNames.length > 0) {
+      for (String name : conditionColumnNames) {
+        if (!tableHasColumn(tableName, name)) {
+          throw new IllegalArgumentException(String.format("%s table does not 
contain %s column", tableName, name));
+        }
+      }
+      if (conditionColumnNames.length != conditionValues.length) {
+        throw new IllegalArgumentException("number of columns should be equal 
to number of values");
+      }
+      builder.append(" WHERE 
").append(conditionColumnNames[0]).append("='").append(conditionValues[0]).append("'");
+      for (int i = 1; i < conditionColumnNames.length; i++) {
+        builder.append(" AND 
").append(conditionColumnNames[i]).append("='").append(conditionValues[i]).append("'");
+      }
+    }
+
+    return builder.toString();
   }
 
   /**
@@ -1582,4 +1681,25 @@ public class DBAccessorImpl implements DBAccessor {
       LOG.warn("{} table doesn't exists, skipping", tableName);
     }
   }
+
+  /**
+   * {@link ResultGetter} is an interface to implement to help compile results
+   * from a SQL query.
+   */
+  private interface ResultGetter<T> {
+    /**
+     * Collect results from the query's {@link ResultSet}
+     *
+     * @param resultSet the result set
+     * @throws SQLException
+     */
+    void collect(ResultSet resultSet) throws SQLException;
+
+    /**
+     * Return the compiled results in the expected data type
+     *
+     * @return the results
+     */
+    T getResult();
+  }
 }
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/GuiceJpaInitializer.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/GuiceJpaInitializer.java
index 8947df0..c049c72 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/GuiceJpaInitializer.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/GuiceJpaInitializer.java
@@ -22,16 +22,41 @@ import org.apache.ambari.server.events.JpaInitializedEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import com.google.inject.persist.PersistService;
 
 /**
- * This class needs to be instantiated with guice to initialize Guice-persist
+ * This class needs to be instantiated with Guice to initialize Guice-persist
  */
+@Singleton
 public class GuiceJpaInitializer {
-  
+
+  private final AmbariEventPublisher publisher;
+
+  /**
+   * GuiceJpaInitializer constructor.
+   * <p>
+   * Starts the JPA service and holds on to an {@link AmbariEventPublisher} 
for future use.
+   *
+   * @param service   the persist service
+   * @param publisher the Ambari event publisher
+   */
   @Inject
   public GuiceJpaInitializer(PersistService service, AmbariEventPublisher 
publisher) {
+    this.publisher = publisher;
     service.start();
+  }
+
+  /**
+   * Called to indicate that the JPA service is initialized and ready for use.
+   * <p>
+   * This means that the schema for the underlying database matches the JPA 
entity objects expectations
+   * and the PersistService has been started.
+   * <p>
+   * A {@link JpaInitializedEvent} is published so that subscribers can 
perform database-related tasks
+   * when the infrastructure is ready.
+   */
+  public void setInitialized() {
     publisher.publish(new JpaInitializedEvent());
   }
 
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
index 40bcd7f..121e7a6 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
@@ -105,14 +105,24 @@ public class AmbariLdapDataPopulator {
   /**
    * Construct an AmbariLdapDataPopulator.
    *
-   * @param configuration the Ambari configuration
-   * @param users         utility that provides access to Users
+   * @param configurationProvider the Ambari configuration
+   * @param users                 utility that provides access to Users
    */
   @Inject
   public AmbariLdapDataPopulator(Provider<AmbariLdapConfiguration> 
configurationProvider, Users users) {
     this.configurationProvider = configurationProvider;
     this.users = users;
-    this.ldapServerProperties = getConfiguration().getLdapServerProperties();
+    this.ldapServerProperties = null;
+  }
+
+  /**
+   * Load the initial LDAP configuration if the JPA infrastructure is 
initialized.
+   */
+  synchronized private LdapServerProperties getLdapProperties() {
+    if (ldapServerProperties == null) {
+      ldapServerProperties = getConfiguration().getLdapServerProperties();
+    }
+    return ldapServerProperties;
   }
 
   /**
@@ -126,7 +136,7 @@ public class AmbariLdapDataPopulator {
     }
     try {
       final LdapTemplate ldapTemplate = loadLdapTemplate();
-      ldapTemplate.search(ldapServerProperties.getBaseDN(), 
"uid=dummy_search", new AttributesMapper() {
+      ldapTemplate.search(getLdapProperties().getBaseDN(), "uid=dummy_search", 
new AttributesMapper() {
 
         @Override
         public Object mapFromAttributes(Attributes arg0) throws 
NamingException {
@@ -447,6 +457,7 @@ public class AmbariLdapDataPopulator {
    * @return the set of LDAP groups for the given name
    */
   protected Set<LdapGroupDto> getLdapGroups(String groupName) {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     Filter groupObjectFilter = new EqualsFilter(OBJECT_CLASS_ATTRIBUTE,
         ldapServerProperties.getGroupObjectClass());
     Filter groupNameFilter = new 
LikeFilter(ldapServerProperties.getGroupNamingAttr(), groupName);
@@ -460,6 +471,7 @@ public class AmbariLdapDataPopulator {
    * @return the set of LDAP users for the given name
    */
   protected Set<LdapUserDto> getLdapUsers(String username) {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     Filter userObjectFilter = new EqualsFilter(OBJECT_CLASS_ATTRIBUTE, 
ldapServerProperties.getUserObjectClass());
     Filter userNameFilter = new 
LikeFilter(ldapServerProperties.getUsernameAttribute(), username);
     return getFilteredLdapUsers(ldapServerProperties.getBaseDN(), 
userObjectFilter, userNameFilter);
@@ -472,6 +484,7 @@ public class AmbariLdapDataPopulator {
    * @return the user for the given member attribute; null if not found
    */
   protected LdapUserDto getLdapUserByMemberAttr(String memberAttributeValue) {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     Set<LdapUserDto> filteredLdapUsers;
 
     memberAttributeValue = getUniqueIdByMemberPattern(memberAttributeValue,
@@ -504,6 +517,7 @@ public class AmbariLdapDataPopulator {
    * @return the group for the given member attribute; null if not found
    */
   protected LdapGroupDto getLdapGroupByMemberAttr(String memberAttributeValue) 
{
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     Set<LdapGroupDto> filteredLdapGroups;
 
     memberAttributeValue = getUniqueIdByMemberPattern(memberAttributeValue,
@@ -602,6 +616,7 @@ public class AmbariLdapDataPopulator {
    * Determines that the member attribute can be used as a 'dn'
    */
   protected boolean isMemberAttributeBaseDn(String memberAttributeValue) {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     Pattern pattern = Pattern.compile(String.format(IS_MEMBER_DN_REGEXP,
         ldapServerProperties.getUsernameAttribute(), 
ldapServerProperties.getGroupNamingAttr()));
     return pattern.matcher(memberAttributeValue).find();
@@ -613,6 +628,7 @@ public class AmbariLdapDataPopulator {
    * @return set of info about LDAP groups
    */
   protected Set<LdapGroupDto> getExternalLdapGroupInfo() {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     EqualsFilter groupObjectFilter = new EqualsFilter(OBJECT_CLASS_ATTRIBUTE,
         ldapServerProperties.getGroupObjectClass());
     return getFilteredLdapGroups(ldapServerProperties.getBaseDN(), 
groupObjectFilter);
@@ -620,6 +636,7 @@ public class AmbariLdapDataPopulator {
 
   // get a filter based on the given member attribute
   private Filter getMemberFilter(String memberAttributeValue) {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     String dnAttribute = ldapServerProperties.getDnAttribute();
 
     return new OrFilter().or(new EqualsFilter(dnAttribute, 
memberAttributeValue)).
@@ -637,6 +654,7 @@ public class AmbariLdapDataPopulator {
   private Set<LdapGroupDto> getFilteredLdapGroups(String baseDn, Filter 
filter) {
     final Set<LdapGroupDto> groups = new HashSet<>();
     final LdapTemplate ldapTemplate = loadLdapTemplate();
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     LOG.trace("LDAP Group Query - Base DN: '{}' ; Filter: '{}'", baseDn, 
filter.encode());
     ldapTemplate.search(baseDn, filter.encode(),
         new LdapGroupContextMapper(groups, ldapServerProperties));
@@ -649,6 +667,7 @@ public class AmbariLdapDataPopulator {
    * @return set of info about LDAP users
    */
   protected Set<LdapUserDto> getExternalLdapUserInfo() {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     EqualsFilter userObjectFilter = new EqualsFilter(OBJECT_CLASS_ATTRIBUTE,
         ldapServerProperties.getUserObjectClass());
     return getFilteredLdapUsers(ldapServerProperties.getBaseDN(), 
userObjectFilter);
@@ -665,6 +684,7 @@ public class AmbariLdapDataPopulator {
   private Set<LdapUserDto> getFilteredLdapUsers(String baseDn, Filter filter) {
     final Set<LdapUserDto> users = new HashSet<>();
     final LdapTemplate ldapTemplate = loadLdapTemplate();
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     PagedResultsDirContextProcessor processor = createPagingProcessor();
     SearchControls searchControls = new SearchControls();
     searchControls.setReturningObjFlag(true);
@@ -740,6 +760,7 @@ public class AmbariLdapDataPopulator {
    * @return LdapTemplate instance
    */
   protected LdapTemplate loadLdapTemplate() {
+    LdapServerProperties ldapServerProperties = getLdapProperties();
     final LdapServerProperties properties = 
getConfiguration().getLdapServerProperties();
     if (ldapTemplate == null || !properties.equals(ldapServerProperties)) {
       LOG.info("Reloading properties");
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
index eadcc32..55ef12f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
@@ -99,12 +99,12 @@ public class ClustersImpl implements Clusters {
 
   private static final Logger LOG = 
LoggerFactory.getLogger(ClustersImpl.class);
 
-  private final ConcurrentHashMap<String, Cluster> clusters = new 
ConcurrentHashMap<>();
-  private final ConcurrentHashMap<Long, Cluster> clustersById = new 
ConcurrentHashMap<>();
-  private final ConcurrentHashMap<String, Host> hosts = new 
ConcurrentHashMap<>();
-  private final ConcurrentHashMap<Long, Host> hostsById = new 
ConcurrentHashMap<>();
-  private final ConcurrentHashMap<String, Set<Cluster>> hostClusterMap = new 
ConcurrentHashMap<>();
-  private final ConcurrentHashMap<String, Set<Host>> clusterHostMap = new 
ConcurrentHashMap<>();
+  private ConcurrentHashMap<String, Cluster> clustersByName = null;
+  private ConcurrentHashMap<Long, Cluster> clustersById = null;
+  private ConcurrentHashMap<String, Host> hostsByName = null;
+  private ConcurrentHashMap<Long, Host> hostsById = null;
+  private ConcurrentHashMap<String, Set<Cluster>> hostClustersMap = null;
+  private ConcurrentHashMap<String, Set<Host>> clusterHostsMap1 = null;
 
   @Inject
   private ClusterDAO clusterDAO;
@@ -169,41 +169,142 @@ public class ClustersImpl implements Clusters {
   }
 
   /**
-   * Inititalizes all of the in-memory state collections that this class
-   * unfortunately uses. It's annotated with {@link Inject} as a way to define 
a
-   * very simple lifecycle with Guice where the constructor is instantiated
-   * (allowing injected members) followed by this method which initiailizes the
-   * state of the instance.
+   * Gets the internal clusters-by-name map, ensuring that the relevant data 
has been previously initialized.
+   *
+   * @return a map of the requested data
+   */
+  private ConcurrentHashMap<String, Cluster> getClustersByName() {
+    if (clustersByName == null) {
+      safelyLoadClustersAndHosts();
+    }
+    return clustersByName;
+  }
+
+  /**
+   * Gets the internal clusters-by-id map, ensuring that the relevant data has 
been previously initialized.
+   *
+   * @return a map of the requested data
+   */
+  private ConcurrentHashMap<Long, Cluster> getClustersById() {
+    if (clustersById == null) {
+      safelyLoadClustersAndHosts();
+    }
+    return clustersById;
+  }
+
+  /**
+   * Gets the internal hosts-by-name map, ensuring that the relevant data has 
been previously initialized.
+   *
+   * @return a map of the requested data
+   */
+  private ConcurrentHashMap<String, Host> getHostsByName() {
+    if (hostsByName == null) {
+      safelyLoadClustersAndHosts();
+    }
+    return hostsByName;
+  }
+
+  /**
+   * Gets the internal hosts-by-id map, ensuring that the relevant data has 
been previously initialized.
+   *
+   * @return a map of the requested data
+   */
+  private ConcurrentHashMap<Long, Host> getHostsById() {
+    if (hostsById == null) {
+      safelyLoadClustersAndHosts();
+    }
+    return hostsById;
+  }
+
+  /**
+   * Gets the internal host/clusters map, ensuring that the relevant data has 
been previously initialized.
+   *
+   * @return a map of the requested data
+   */
+  private ConcurrentHashMap<String, Set<Cluster>> getHostClustersMap() {
+    if (hostClustersMap == null) {
+      safelyLoadClustersAndHosts();
+    }
+    return hostClustersMap;
+  }
+
+  /**
+   * Gets the internal cluster/hosts map, ensuring that the relevant data has 
been previously initialized.
+   *
+   * @return a map of the requested data
+   */
+  private ConcurrentHashMap<String, Set<Host>> getClusterHostsMap() {
+    if (clusterHostsMap1 == null) {
+      safelyLoadClustersAndHosts();
+    }
+    return clusterHostsMap1;
+  }
+
+  /**
+   * Safely initializes all of the in-memory state collections that this class.
+   * <p>
+   * This method is synchronized so that the data can be loaded only if 
needed.  If most than one of
+   * the relevant get methods are concurrently invoked, this method should 
ensure that {@link #loadClustersAndHosts()}
+   * will be entered once.  Subsequent calls will bypass {@link 
#loadClustersAndHosts()} since the
+   * relevant variables will no longer be null.
+   *
+   * @see #getClustersByName()
+   * @see #getClustersById()
+   * @see #getHostsByName()
+   * @see #getHostsById()
+   * @see #getClusterHostsMap()
+   * @see #getHostClustersMap()
+   */
+  synchronized private void safelyLoadClustersAndHosts() {
+    if (clustersByName == null || clustersById == null ||
+        hostsByName == null || hostsById == null ||
+        hostClustersMap == null || clusterHostsMap1 == null) {
+      loadClustersAndHosts();
+    }
+  }
+
+  /**
+   * Initializes all of the in-memory state collections that this class
+   * unfortunately uses.
+   * <p>
+   * This method should be called only once, when the data is first needed.
    * <p/>
    * Because some of these stateful initializations may actually reference this
    * {@link Clusters} instance, we must do this after the object has been
    * instantiated and injected.
    */
-  @Inject
-  @Transactional
-  void loadClustersAndHosts() {
+  private void loadClustersAndHosts() {
+    LOG.info("Initializing cluster and host data.");
+
+    clustersByName = new ConcurrentHashMap<>();
+    clustersById = new ConcurrentHashMap<>();
+    hostsByName = new ConcurrentHashMap<>();
+    hostsById = new ConcurrentHashMap<>();
+    hostClustersMap = new ConcurrentHashMap<>();
+    clusterHostsMap1 = new ConcurrentHashMap<>();
+
     List<HostEntity> hostEntities = hostDAO.findAll();
     for (HostEntity hostEntity : hostEntities) {
       Host host = hostFactory.create(hostEntity);
-      hosts.put(hostEntity.getHostName(), host);
+      hostsByName.put(hostEntity.getHostName(), host);
       hostsById.put(hostEntity.getHostId(), host);
     }
 
     for (ClusterEntity clusterEntity : clusterDAO.findAll()) {
       Cluster currentCluster = clusterFactory.create(clusterEntity);
-      clusters.put(clusterEntity.getClusterName(), currentCluster);
+      clustersByName.put(clusterEntity.getClusterName(), currentCluster);
       clustersById.put(currentCluster.getClusterId(), currentCluster);
-      clusterHostMap.put(currentCluster.getClusterName(), 
Collections.newSetFromMap(new ConcurrentHashMap<>()));
+      clusterHostsMap1.put(currentCluster.getClusterName(), 
Collections.newSetFromMap(new ConcurrentHashMap<>()));
     }
 
     for (HostEntity hostEntity : hostEntities) {
       Set<Cluster> cSet = Collections.newSetFromMap(new 
ConcurrentHashMap<Cluster, Boolean>());
-      hostClusterMap.put(hostEntity.getHostName(), cSet);
+      hostClustersMap.put(hostEntity.getHostName(), cSet);
 
-      Host host = hosts.get(hostEntity.getHostName());
+      Host host = getHostsByName().get(hostEntity.getHostName());
       for (ClusterEntity clusterEntity : hostEntity.getClusterEntities()) {
-        clusterHostMap.get(clusterEntity.getClusterName()).add(host);
-        cSet.add(clusters.get(clusterEntity.getClusterName()));
+        clusterHostsMap1.get(clusterEntity.getClusterName()).add(host);
+        cSet.add(clustersByName.get(clusterEntity.getClusterName()));
       }
     }
   }
@@ -219,7 +320,7 @@ public class ClustersImpl implements Clusters {
       throws AmbariException {
     Cluster cluster = null;
 
-    if (clusters.containsKey(clusterName)) {
+    if (getClustersByName().containsKey(clusterName)) {
       throw new DuplicateResourceException(
           "Attempted to create a Cluster which already exists" + ", 
clusterName=" + clusterName);
     }
@@ -256,9 +357,9 @@ public class ClustersImpl implements Clusters {
     }
 
     cluster = clusterFactory.create(clusterEntity);
-    clusters.put(clusterName, cluster);
-    clustersById.put(cluster.getClusterId(), cluster);
-    clusterHostMap.put(clusterName,
+    getClustersByName().put(clusterName, cluster);
+    getClustersById().put(cluster.getClusterId(), cluster);
+    getClusterHostsMap().put(clusterName,
         Collections.newSetFromMap(new ConcurrentHashMap<>()));
 
     cluster.setCurrentStackVersion(stackId);
@@ -277,7 +378,7 @@ public class ClustersImpl implements Clusters {
       throws AmbariException {
     Cluster cluster = null;
     if (clusterName != null) {
-      cluster = clusters.get(clusterName);
+      cluster = getClustersByName().get(clusterName);
     }
     if (null == cluster) {
       throw new ClusterNotFoundException(clusterName);
@@ -291,7 +392,7 @@ public class ClustersImpl implements Clusters {
     throws AmbariException {
     Cluster cluster = null;
     if (clusterId != null) {
-      cluster = clustersById.get(clusterId);
+      cluster = getClustersById().get(clusterId);
     }
     if (null == cluster) {
       throw new ClusterNotFoundException(clusterId);
@@ -302,6 +403,7 @@ public class ClustersImpl implements Clusters {
 
   @Override
   public Cluster getClusterById(long id) throws AmbariException {
+    ConcurrentHashMap<Long, Cluster> clustersById = getClustersById();
     Cluster cluster = clustersById.get(id);
     if (null == cluster) {
       throw new ClusterNotFoundException("clusterID=" + id);
@@ -312,13 +414,13 @@ public class ClustersImpl implements Clusters {
 
   @Override
   public List<Host> getHosts() {
-    return new ArrayList<>(hosts.values());
+    return new ArrayList<>(getHostsByName().values());
   }
 
   @Override
   public Set<Cluster> getClustersForHost(String hostname)
       throws AmbariException {
-    Set<Cluster> clusters = hostClusterMap.get(hostname);
+    Set<Cluster> clusters = getHostClustersMap().get(hostname);
     if(clusters == null){
       throw new HostNotFoundException(hostname);
     }
@@ -331,7 +433,7 @@ public class ClustersImpl implements Clusters {
 
   @Override
   public Host getHost(String hostname) throws AmbariException {
-    Host host = hosts.get(hostname);
+    Host host = getHostsByName().get(hostname);
     if (null == host) {
       throw new HostNotFoundException(hostname);
     }
@@ -341,7 +443,7 @@ public class ClustersImpl implements Clusters {
 
   @Override
   public boolean hostExists(String hostname){
-    return hosts.containsKey(hostname);
+    return getHostsByName().containsKey(hostname);
   }
 
   /**
@@ -349,7 +451,7 @@ public class ClustersImpl implements Clusters {
    */
   @Override
   public boolean isHostMappedToCluster(long clusterId, String hostName) {
-    Set<Cluster> clusters = hostClusterMap.get(hostName);
+    Set<Cluster> clusters = getHostClustersMap().get(hostName);
     for (Cluster cluster : clusters) {
       if (clusterId == cluster.getClusterId()) {
         return true;
@@ -361,11 +463,11 @@ public class ClustersImpl implements Clusters {
 
   @Override
   public Host getHostById(Long hostId) throws AmbariException {
-    if (!hostsById.containsKey(hostId)) {
+    if (!getHostsById().containsKey(hostId)) {
       throw new HostNotFoundException("Host Id = " + hostId);
     }
 
-    return hostsById.get(hostId);
+    return getHostsById().get(hostId);
   }
 
   /**
@@ -376,7 +478,7 @@ public class ClustersImpl implements Clusters {
     Long hostId = host.getHostId();
 
     if (null != hostId) {
-      hostsById.put(hostId, host);
+      getHostsById().put(hostId, host);
     }
   }
 
@@ -388,7 +490,7 @@ public class ClustersImpl implements Clusters {
    */
   @Override
   public void addHost(String hostname) throws AmbariException {
-    if (hosts.containsKey(hostname)) {
+    if (getHostsByName().containsKey(hostname)) {
       throw new AmbariException(MessageFormat.format("Duplicate entry for Host 
{0}", hostname));
     }
 
@@ -407,9 +509,9 @@ public class ClustersImpl implements Clusters {
 
     // the hosts by ID map is updated separately since the host has not yet
     // been persisted yet - the below event is what causes the persist
-    hosts.put(hostname, host);
+    getHostsByName().put(hostname, host);
 
-    hostClusterMap.put(hostname,
+    getHostClustersMap().put(hostname,
         Collections.newSetFromMap(new ConcurrentHashMap<>()));
 
     if (LOG.isDebugEnabled()) {
@@ -469,7 +571,7 @@ public class ClustersImpl implements Clusters {
     Host host = null;
     for (String hostName : hostSet) {
       if (null != hostName) {
-          host= hosts.get(hostName);
+          host= getHostsByName().get(hostName);
         if (host == null) {
           throw new HostNotFoundException(hostName);
         }
@@ -516,9 +618,10 @@ public class ClustersImpl implements Clusters {
 
     Host host = getHost(hostname);
     Cluster cluster = getCluster(clusterName);
+    ConcurrentHashMap<String, Set<Cluster>> hostClustersMap = 
getHostClustersMap();
 
     // check to ensure there are no duplicates
-    for (Cluster c : hostClusterMap.get(hostname)) {
+    for (Cluster c : hostClustersMap.get(hostname)) {
       if (c.getClusterName().equals(clusterName)) {
         throw new DuplicateResourceException("Attempted to create a host which 
already exists: clusterName=" +
           clusterName + ", hostName=" + hostname);
@@ -532,8 +635,8 @@ public class ClustersImpl implements Clusters {
     }
 
     mapHostClusterEntities(hostname, clusterId);
-    hostClusterMap.get(hostname).add(cluster);
-    clusterHostMap.get(clusterName).add(host);
+    hostClustersMap.get(hostname).add(cluster);
+    getClusterHostsMap().get(clusterName).add(host);
   }
 
   @Transactional
@@ -550,13 +653,16 @@ public class ClustersImpl implements Clusters {
 
   @Override
   public Map<String, Cluster> getClusters() {
-    return Collections.unmodifiableMap(clusters);
+    return Collections.unmodifiableMap(getClustersByName());
   }
 
   @Override
   public void updateClusterName(String oldName, String newName) {
+    ConcurrentHashMap<String, Cluster> clusters = getClustersByName();
     clusters.put(newName, clusters.remove(oldName));
-    clusterHostMap.put(newName, clusterHostMap.remove(oldName));
+
+    ConcurrentHashMap<String, Set<Host>> clusterHostsMap = 
getClusterHostsMap();
+    clusterHostsMap.put(newName, clusterHostsMap.remove(oldName));
 
     //TODO metadata update
   }
@@ -566,7 +672,7 @@ public class ClustersImpl implements Clusters {
   public void debugDump(StringBuilder sb) {
     sb.append("Clusters=[ ");
     boolean first = true;
-    for (Cluster c : clusters.values()) {
+    for (Cluster c : getClustersByName().values()) {
       if (!first) {
         sb.append(" , ");
       }
@@ -583,7 +689,7 @@ public class ClustersImpl implements Clusters {
       throws AmbariException {
 
     Map<String, Host> hosts = new HashMap<>();
-    for (Host h : clusterHostMap.get(clusterName)) {
+    for (Host h : getClusterHostsMap().get(clusterName)) {
       hosts.put(h.getHostName(), h);
     }
 
@@ -595,7 +701,7 @@ public class ClustersImpl implements Clusters {
       throws AmbariException {
     Map<Long, Host> hosts = new HashMap<>();
 
-    for (Host h : clusterHostMap.get(clusterName)) {
+    for (Host h : getClusterHostsMap().get(clusterName)) {
       HostEntity hostEntity = hostDAO.findByName(h.getHostName());
       hosts.put(hostEntity.getHostId(), h);
     }
@@ -615,11 +721,11 @@ public class ClustersImpl implements Clusters {
     cluster.delete();
 
     // clear maps
-    for (Set<Cluster> clusterSet : hostClusterMap.values()) {
+    for (Set<Cluster> clusterSet : getHostClustersMap().values()) {
       clusterSet.remove(cluster);
     }
-    clusterHostMap.remove(cluster.getClusterName());
-    clusters.remove(clusterName);
+    getClusterHostsMap().remove(cluster.getClusterName());
+    getClustersByName().remove(clusterName);
   }
 
   @Override
@@ -652,8 +758,8 @@ public class ClustersImpl implements Clusters {
 
       unmapHostClusterEntities(hostname, cluster.getClusterId());
 
-      hostClusterMap.get(hostname).remove(cluster);
-      clusterHostMap.get(cluster.getClusterName()).remove(host);
+      getHostClustersMap().get(hostname).remove(cluster);
+      getClusterHostsMap().get(cluster.getClusterName()).remove(host);
     }
 
     deleteConfigGroupHostMapping(hostEntity.getHostId());
@@ -677,7 +783,7 @@ public class ClustersImpl implements Clusters {
   @Transactional
   void deleteConfigGroupHostMapping(Long hostId) throws AmbariException {
     // Remove Config group mapping
-    for (Cluster cluster : clusters.values()) {
+    for (Cluster cluster : getClustersByName().values()) {
       for (ConfigGroup configGroup : cluster.getConfigGroups().values()) {
         configGroup.removeHost(hostId);
       }
@@ -697,7 +803,7 @@ public class ClustersImpl implements Clusters {
     // unmapping hosts from a cluster modifies the collections directly; keep
     // a copy of this to ensure that we can pass in the original set of
     // clusters that the host belonged to to the host removal event
-    Set<Cluster> clusters = hostClusterMap.get(hostname);
+    Set<Cluster> clusters = getHostClustersMap().get(hostname);
     if (clusters == null) {
       throw new HostNotFoundException(hostname);
     }
@@ -724,7 +830,7 @@ public class ClustersImpl implements Clusters {
    */
   @Transactional
   void deleteHostEntityRelationships(String hostname) throws AmbariException {
-    if (!hosts.containsKey(hostname)) {
+    if (!getHostsByName().containsKey(hostname)) {
       throw new HostNotFoundException("Could not find host " + hostname);
     }
 
@@ -737,13 +843,13 @@ public class ClustersImpl implements Clusters {
     // Remove from all clusters in the cluster_host_mapping table.
     // This will also remove from kerberos_principal_hosts, hostconfigmapping,
     // and configgrouphostmapping
-    Set<Cluster> clusters = hostClusterMap.get(hostname);
+    Set<Cluster> clusters = getHostClustersMap().get(hostname);
     Set<Long> clusterIds = Sets.newHashSet();
     for (Cluster cluster : clusters) {
       clusterIds.add(cluster.getClusterId());
     }
 
-    Host host = hosts.get(hostname);
+    Host host = getHostsByName().get(hostname);
     unmapHostFromClusters(host, clusters);
     hostDAO.refresh(entity);
 
@@ -772,8 +878,8 @@ public class ClustersImpl implements Clusters {
     topologyHostInfoDAO.removeByHost(entity);
 
     // Remove from dictionaries
-    hosts.remove(hostname);
-    hostsById.remove(entity.getHostId());
+    getHostsByName().remove(hostname);
+    getHostsById().remove(entity.getHostId());
 
     hostDAO.remove(entity);
 
@@ -812,10 +918,10 @@ public class ClustersImpl implements Clusters {
   @Override
   public int getClusterSize(String clusterName) {
     int hostCount = 0;
-
-    Set<Host> hosts = clusterHostMap.get(clusterName);
+    ConcurrentHashMap<String, Set<Host>> clusterHostsMap = 
getClusterHostsMap();
+    Set<Host> hosts = clusterHostsMap.get(clusterName);
     if (null != hosts) {
-      hostCount = clusterHostMap.get(clusterName).size();
+      hostCount = clusterHostsMap.get(clusterName).size();
     }
 
     return hostCount;
@@ -879,7 +985,7 @@ public class ClustersImpl implements Clusters {
   public void invalidate(Cluster cluster) {
     ClusterEntity clusterEntity = clusterDAO.findById(cluster.getClusterId());
     Cluster currentCluster = clusterFactory.create(clusterEntity);
-    clusters.put(clusterEntity.getClusterName(), currentCluster);
-    clustersById.put(currentCluster.getClusterId(), currentCluster);
+    getClustersByName().put(clusterEntity.getClusterName(), currentCluster);
+    getClustersById().put(currentCluster.getClusterId(), currentCluster);
   }
 }
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
index cbba599..de80052 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/SchemaUpgradeHelper.java
@@ -38,6 +38,7 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.ControllerModule;
 import org.apache.ambari.server.ldap.LdapModule;
 import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.utils.EventBusSynchronizer;
 import org.apache.ambari.server.utils.VersionUtils;
 import org.slf4j.Logger;
@@ -403,6 +404,11 @@ public class SchemaUpgradeHelper {
       }
 
       Injector injector = Guice.createInjector(new UpgradeHelperModule(), new 
AuditLoggerModule(), new LdapModule());
+
+      // Startup the JPA infrastructure, but do not indicate it is initialized 
since the underlying
+      // database schema may not be updated to meet the expectations of the 
Entity instances.
+      GuiceJpaInitializer jpaInitializer = 
injector.getInstance(GuiceJpaInitializer.class);
+
       SchemaUpgradeHelper schemaUpgradeHelper = 
injector.getInstance(SchemaUpgradeHelper.class);
 
       //Fail if MySQL database has tables with MyISAM engine
@@ -441,7 +447,9 @@ public class SchemaUpgradeHelper {
 
       schemaUpgradeHelper.executeUpgrade(upgradeCatalogs);
 
-      schemaUpgradeHelper.startPersistenceService();
+      // The DDL is expected to be updated, now send the JPA initialized event 
so Entity
+      // implementations can be created.
+      jpaInitializer.setInitialized();
 
       schemaUpgradeHelper.executePreDMLUpdates(upgradeCatalogs);
 
@@ -457,6 +465,9 @@ public class SchemaUpgradeHelper {
       schemaUpgradeHelper.cleanUpRCATables();
 
       schemaUpgradeHelper.stopPersistenceService();
+
+      // Signal all threads that we are ready to exit...
+      System.exit(0);
     } catch (Throwable e) {
       if (e instanceof AmbariException) {
         LOG.error("Exception occurred during upgrade, failed", e);
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog270.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog270.java
index 02474e8..d59248d 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog270.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog270.java
@@ -83,6 +83,11 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Sets;
 import com.google.common.net.HostAndPort;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
@@ -107,6 +112,10 @@ public class UpgradeCatalog270 extends 
AbstractUpgradeCatalog {
   protected static final String SERVICE_DESIRED_STATE_TABLE = 
"servicedesiredstate";
   protected static final String SECURITY_STATE_COLUMN = "security_state";
 
+  protected static final String AMBARI_SEQUENCES_TABLE = "ambari_sequences";
+  protected static final String AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN = 
"sequence_name";
+  protected static final String AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN = 
"sequence_value";
+
   protected static final String AMBARI_CONFIGURATION_TABLE = 
"ambari_configuration";
   protected static final String AMBARI_CONFIGURATION_CATEGORY_NAME_COLUMN = 
"category_name";
   protected static final String AMBARI_CONFIGURATION_PROPERTY_NAME_COLUMN = 
"property_name";
@@ -178,6 +187,36 @@ public class UpgradeCatalog270 extends 
AbstractUpgradeCatalog {
   protected static final String KERBEROS_PRINCIPAL_HOST_TABLE = 
"kerberos_principal_host";
   protected static final String HOST_ID_COLUMN = "host_id";
 
+  protected static final String REPO_OS_TABLE = "repo_os";
+  protected static final String REPO_OS_ID_COLUMN = "id";
+  protected static final String REPO_OS_REPO_VERSION_ID_COLUMN = 
"repo_version_id";
+  protected static final String REPO_OS_FAMILY_COLUMN = "family";
+  protected static final String REPO_OS_AMBARI_MANAGED_COLUMN = 
"ambari_managed";
+  protected static final String REPO_OS_PRIMARY_KEY = "PK_repo_os_id";
+  protected static final String REPO_OS_FOREIGN_KEY = 
"FK_repo_os_id_repo_version_id";
+
+  protected static final String REPO_DEFINITION_TABLE = "repo_definition";
+  protected static final String REPO_DEFINITION_ID_COLUMN = "id";
+  protected static final String REPO_DEFINITION_REPO_OS_ID_COLUMN = 
"repo_os_id";
+  protected static final String REPO_DEFINITION_REPO_NAME_COLUMN = "repo_name";
+  protected static final String REPO_DEFINITION_REPO_ID_COLUMN = "repo_id";
+  protected static final String REPO_DEFINITION_BASE_URL_COLUMN = "base_url";
+  protected static final String REPO_DEFINITION_DISTRIBUTION_COLUMN = 
"distribution";
+  protected static final String REPO_DEFINITION_COMPONENTS_COLUMN = 
"components";
+  protected static final String REPO_DEFINITION_UNIQUE_REPO_COLUMN = 
"unique_repo";
+  protected static final String REPO_DEFINITION_MIRRORS_COLUMN = "mirrors";
+  protected static final String REPO_DEFINITION_PRIMARY_KEY = 
"PK_repo_definition_id";
+  protected static final String REPO_DEFINITION_FOREIGN_KEY = 
"FK_repo_definition_repo_os_id";
+
+  protected static final String REPO_TAGS_TABLE = "repo_tags";
+  protected static final String REPO_TAGS_REPO_DEFINITION_ID_COLUMN = 
"repo_definition_id";
+  protected static final String REPO_TAGS_TAG_COLUMN = "tag";
+  protected static final String REPO_TAGS_FOREIGN_KEY = 
"FK_repo_tag_definition_id";
+
+  protected static final String REPO_VERSION_TABLE = "repo_version";
+  protected static final String REPO_VERSION_REPO_VERSION_ID_COLUMN = 
"repo_version_id";
+  protected static final String REPO_VERSION_REPOSITORIES_COLUMN = 
"repositories";
+
   protected static final String CLUSTER_ID_COLUMN = "cluster_id";
   public static final String[] 
COMPONENT_NAME_SERVICE_NAME_CLUSTER_ID_KEY_COLUMNS = {COMPONENT_NAME_COLUMN, 
SERVICE_NAME_COLUMN, CLUSTER_ID_COLUMN};
   public static final String[] SERVICE_NAME_CLUSTER_ID_KEY_COLUMNS = 
{SERVICE_NAME_COLUMN, CLUSTER_ID_COLUMN};
@@ -240,6 +279,7 @@ public class UpgradeCatalog270 extends 
AbstractUpgradeCatalog {
     addHostComponentLastStateTable();
     upgradeUserTables();
     upgradeKerberosTables();
+    upgradeRepoTables();
   }
 
   /**
@@ -266,6 +306,200 @@ public class UpgradeCatalog270 extends 
AbstractUpgradeCatalog {
     updateUsersTable();
   }
 
+  protected void upgradeRepoTables() throws SQLException {
+    createRepoOsTable();
+    createRepoDefinitionTable();
+    createRepoTagsTable();
+    migrateRepoData();
+    updateRepoVersionTable();
+  }
+
+  /**
+   * Adds the repo_os table to the Ambari database.
+   * <pre>
+   * CREATE TABLE repo_os (
+   *   id BIGINT NOT NULL,
+   *   repo_version_id BIGINT NOT NULL,
+   *   family VARCHAR(255) NOT NULL DEFAULT '',
+   *   ambari_managed SMALLINT DEFAULT 1,
+   *   CONSTRAINT PK_repo_os_id PRIMARY KEY (id),
+   *   CONSTRAINT FK_repo_os_id_repo_version_id FOREIGN KEY (repo_version_id) 
REFERENCES repo_version (repo_version_id));
+   * </pre>
+   *
+   * @throws SQLException
+   */
+  private void createRepoOsTable() throws SQLException {
+    List<DBAccessor.DBColumnInfo> columns = new ArrayList<>();
+    columns.add(new DBAccessor.DBColumnInfo(REPO_OS_ID_COLUMN, Long.class, 
null, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_OS_REPO_VERSION_ID_COLUMN, 
Long.class, null, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_OS_FAMILY_COLUMN, 
String.class, 255, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_OS_AMBARI_MANAGED_COLUMN, 
Integer.class, null, 1, true));
+
+    dbAccessor.createTable(REPO_OS_TABLE, columns);
+    dbAccessor.addPKConstraint(REPO_OS_TABLE, REPO_OS_PRIMARY_KEY, 
REPO_OS_ID_COLUMN);
+    dbAccessor.addFKConstraint(REPO_OS_TABLE, REPO_OS_FOREIGN_KEY, 
REPO_OS_REPO_VERSION_ID_COLUMN, REPO_VERSION_TABLE, 
REPO_VERSION_REPO_VERSION_ID_COLUMN, false);
+  }
+
+  /**
+   * Adds the repo_definition table to the Ambari database.
+   * <pre>
+   *   CREATE TABLE repo_definition (
+   *     id BIGINT NOT NULL,
+   *     repo_os_id BIGINT,
+   *     repo_name VARCHAR(255) NOT NULL,
+   *     repo_id VARCHAR(255) NOT NULL,
+   *     base_url VARCHAR(2048) NOT NULL,
+   *     distribution VARCHAR(2048),
+   *     components VARCHAR(2048),
+   *     unique_repo SMALLINT DEFAULT 1,
+   *     mirrors VARCHAR(2048),
+   *     CONSTRAINT PK_repo_definition_id PRIMARY KEY (id),
+   *     CONSTRAINT FK_repo_definition_repo_os_id FOREIGN KEY (repo_os_id) 
REFERENCES repo_os (id));
+   * </pre>
+   *
+   * @throws SQLException
+   */
+  private void createRepoDefinitionTable() throws SQLException {
+    List<DBAccessor.DBColumnInfo> columns = new ArrayList<>();
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_ID_COLUMN, 
Long.class, null, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_OS_ID_COLUMN, 
Long.class, null, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_NAME_COLUMN, 
String.class, 255, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_ID_COLUMN, 
String.class, 255, null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_BASE_URL_COLUMN, 
String.class, 2048, null, true));
+    columns.add(new 
DBAccessor.DBColumnInfo(REPO_DEFINITION_DISTRIBUTION_COLUMN, String.class, 
2048, null, true));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_COMPONENTS_COLUMN, 
String.class, 2048, null, true));
+    columns.add(new 
DBAccessor.DBColumnInfo(REPO_DEFINITION_UNIQUE_REPO_COLUMN, Integer.class, 1, 
1, true));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_DEFINITION_MIRRORS_COLUMN, 
String.class, 2048, null, true));
+
+    dbAccessor.createTable(REPO_DEFINITION_TABLE, columns);
+    dbAccessor.addPKConstraint(REPO_DEFINITION_TABLE, 
REPO_DEFINITION_PRIMARY_KEY, REPO_DEFINITION_ID_COLUMN);
+    dbAccessor.addFKConstraint(REPO_DEFINITION_TABLE, 
REPO_DEFINITION_FOREIGN_KEY, REPO_DEFINITION_REPO_OS_ID_COLUMN, REPO_OS_TABLE, 
REPO_OS_ID_COLUMN, false);
+  }
+
+  /**
+   * Adds the repo_tags table to the Ambari database.
+   * <pre>
+   *   CREATE TABLE repo_tags (
+   *     repo_definition_id BIGINT NOT NULL,
+   *     tag VARCHAR(255) NOT NULL,
+   *     CONSTRAINT FK_repo_tag_definition_id FOREIGN KEY (repo_definition_id) 
REFERENCES repo_definition (id));
+   * </pre>
+   *
+   * @throws SQLException
+   */
+  private void createRepoTagsTable() throws SQLException {
+    List<DBAccessor.DBColumnInfo> columns = new ArrayList<>();
+    columns.add(new 
DBAccessor.DBColumnInfo(REPO_TAGS_REPO_DEFINITION_ID_COLUMN, Long.class, null, 
null, false));
+    columns.add(new DBAccessor.DBColumnInfo(REPO_TAGS_TAG_COLUMN, 
String.class, 255, null, false));
+
+    dbAccessor.createTable(REPO_TAGS_TABLE, columns);
+    dbAccessor.addFKConstraint(REPO_TAGS_TABLE, REPO_TAGS_FOREIGN_KEY, 
REPO_TAGS_REPO_DEFINITION_ID_COLUMN, REPO_DEFINITION_TABLE, 
REPO_DEFINITION_ID_COLUMN, false);
+  }
+
+  /**
+   * Perform steps to move data from the old repo_version.repositories 
structure into new tables -
+   * repo_os, repo_definition, repo_tags
+   *
+   * @throws SQLException
+   */
+  private void migrateRepoData() throws SQLException {
+    if(dbAccessor.tableHasColumn(REPO_VERSION_TABLE, 
REPO_VERSION_REPOSITORIES_COLUMN)) {
+      int repoOsId = 0;
+      int repoDefinitionId = 0;
+
+      // Get a map of repo_version.id to repo_version.repositories
+      Map<Long, String> repoVersionData = 
dbAccessor.getKeyToStringColumnMap(REPO_VERSION_TABLE,
+          REPO_VERSION_REPO_VERSION_ID_COLUMN, 
REPO_VERSION_REPOSITORIES_COLUMN, null, null, true);
+
+      if (repoVersionData != null) {
+        // For each entry in the map, parse the repo_version.repositories data 
and created records in the new
+        // repo_os, repo_definition, and repo_tabs tables...
+        for (Map.Entry<Long, String> entry : repoVersionData.entrySet()) {
+          Long repoVersionId = entry.getKey();
+          String repositoriesJson = entry.getValue();
+
+          if (!StringUtils.isEmpty(repositoriesJson)) {
+            JsonArray rootJson = new 
JsonParser().parse(repositoriesJson).getAsJsonArray();
+
+            if (rootJson != null) {
+              for (JsonElement rootElement : rootJson) {
+                // process each OS element
+                JsonObject rootObject = rootElement.getAsJsonObject();
+
+                if (rootObject != null) {
+                  JsonPrimitive osType = 
rootObject.getAsJsonPrimitive("OperatingSystems/os_type");
+                  JsonPrimitive ambariManaged = 
rootObject.getAsJsonPrimitive("OperatingSystems/ambari_managed_repositories");
+                  JsonArray repositories = 
rootObject.getAsJsonArray("repositories");
+                  String isAmbariManaged = ambariManaged.getAsBoolean() ? "1" 
: "0";
+
+                  dbAccessor.insertRowIfMissing(REPO_OS_TABLE,
+                      new String[]{REPO_OS_ID_COLUMN, 
REPO_OS_REPO_VERSION_ID_COLUMN, REPO_OS_AMBARI_MANAGED_COLUMN, 
REPO_OS_FAMILY_COLUMN},
+                      new String[]{String.valueOf(++repoOsId), 
String.valueOf(repoVersionId), isAmbariManaged, String.format("'%s'", 
osType.getAsString())},
+                      false);
+
+                  if (repositories != null) {
+                    for (JsonElement repositoryElement : repositories) {
+                      JsonObject repositoryObject = 
repositoryElement.getAsJsonObject();
+
+                      if (repositoryObject != null) {
+                        JsonPrimitive repoId = 
repositoryObject.getAsJsonPrimitive("Repositories/repo_id");
+                        JsonPrimitive repoName = 
repositoryObject.getAsJsonPrimitive("Repositories/repo_name");
+                        JsonPrimitive baseUrl = 
repositoryObject.getAsJsonPrimitive("Repositories/base_url");
+                        JsonArray tags = 
repositoryObject.getAsJsonArray("Repositories/tags");
+
+                        dbAccessor.insertRowIfMissing(REPO_DEFINITION_TABLE,
+                            new String[]{REPO_DEFINITION_ID_COLUMN, 
REPO_DEFINITION_REPO_OS_ID_COLUMN,
+                                REPO_DEFINITION_REPO_NAME_COLUMN, 
REPO_DEFINITION_REPO_ID_COLUMN, REPO_DEFINITION_BASE_URL_COLUMN},
+                            new String[]{String.valueOf(++repoDefinitionId), 
String.valueOf(repoOsId),
+                                String.format("'%s'", repoName.getAsString()), 
String.format("'%s'", repoId.getAsString()),
+                                String.format("'%s'", baseUrl.getAsString())},
+                            false);
+
+                        if (tags != null) {
+                          for (JsonElement tagsElement : tags) {
+                            JsonPrimitive tag = 
tagsElement.getAsJsonPrimitive();
+
+                            if (tag != null) {
+                              dbAccessor.insertRowIfMissing(REPO_TAGS_TABLE,
+                                  new 
String[]{REPO_TAGS_REPO_DEFINITION_ID_COLUMN, REPO_TAGS_TAG_COLUMN},
+                                  new 
String[]{String.valueOf(repoDefinitionId), String.format("'%s'", 
tag.getAsString())},
+                                  false);
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+
+      // Add the relevant records in the ambari_sequence table
+      // - repo_os_id_seq
+      // - repo_definition_id_seq
+      dbAccessor.insertRowIfMissing(AMBARI_SEQUENCES_TABLE,
+          new String[]{AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN, 
AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN},
+          new String[]{"'repo_os_id_seq'", String.valueOf(++repoOsId)},
+          false);
+      dbAccessor.insertRowIfMissing(AMBARI_SEQUENCES_TABLE,
+          new String[]{AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN, 
AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN},
+          new String[]{"'repo_definition_id_seq'", 
String.valueOf(++repoDefinitionId)},
+          false);
+    }
+  }
+
+  /**
+   * Updates the repo_version table by removing old columns
+   *
+   * @throws SQLException
+   */
+  private void updateRepoVersionTable() throws SQLException {
+    dbAccessor.dropColumn(REPO_VERSION_TABLE, 
REPO_VERSION_REPOSITORIES_COLUMN);
+  }
+
   /**
    * If the <code>users</code> table has not yet been migrated, create the 
<code>user_authentication</code>
    * table and generate relevant records for that table based on data in the 
<code>users</code> table.
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/orm/DBAccessorImplTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/orm/DBAccessorImplTest.java
index 68b0cdf..15c83bb 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/orm/DBAccessorImplTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/orm/DBAccessorImplTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.matchers.JUnitMatchers.containsString;
 
 import java.io.ByteArrayInputStream;
@@ -785,4 +786,73 @@ public class DBAccessorImplTest {
     assertFalse(column1.equals(notEqualsColumn1DefaultValueEmptyString));
     assertFalse(column1.equals(notEqualsColumn1Nullable));
   }
+
+  @Test
+  public void testBuildQuery() throws Exception {
+    String tableName = getFreeTableName();
+    createMyTable(tableName);
+
+    DBAccessorImpl dbAccessor = injector.getInstance(DBAccessorImpl.class);
+
+    assertEquals(String.format("SELECT id FROM %s WHERE name='value1'", 
tableName),
+    dbAccessor.buildQuery(tableName, new String[] {"id"}, new String[] 
{"name"}, new String[] {"value1"}));
+
+    assertEquals(String.format("SELECT id FROM %s WHERE name='value1' AND 
time='100'", tableName),
+    dbAccessor.buildQuery(tableName, new String[] {"id"}, new String[] 
{"name", "time"}, new String[] {"value1", "100"}));
+
+    assertEquals(String.format("SELECT id, name FROM %s WHERE time='100'", 
tableName),
+    dbAccessor.buildQuery(tableName, new String[] {"id", "name"}, new String[] 
{"time"}, new String[] {"100"}));
+
+    assertEquals(String.format("SELECT id, name FROM %s", tableName),
+    dbAccessor.buildQuery(tableName, new String[] {"id", "name"}, null, null));
+
+    try {
+      dbAccessor.buildQuery("invalid_table_name", new String[] {"id", "name"}, 
new String[] {"time"}, new String[] {"100"});
+      fail("Expected IllegalArgumentException due to bad table name");
+    }
+    catch (IllegalArgumentException e) {
+      // This is expected
+    }
+
+    try {
+      dbAccessor.buildQuery(tableName, new String[] {"invalid_column_name"}, 
new String[] {"time"}, new String[] {"100"});
+      fail("Expected IllegalArgumentException due to bad column name");
+    }
+    catch (IllegalArgumentException e) {
+      // This is expected
+    }
+
+    try {
+      dbAccessor.buildQuery(tableName, new String[] {"id"}, new String[] 
{"invalid_column_name"}, new String[] {"100"});
+      fail("Expected IllegalArgumentException due to bad column name");
+    }
+    catch (IllegalArgumentException e) {
+      // This is expected
+    }
+
+    try {
+      dbAccessor.buildQuery(tableName, new String[] {}, new String[] {"name"}, 
new String[] {"100"});
+      fail("Expected IllegalArgumentException due missing select columns");
+    }
+    catch (IllegalArgumentException e) {
+      // This is expected
+    }
+
+    try {
+      dbAccessor.buildQuery(tableName, null, new String[] {"name"}, new 
String[] {"100"});
+      fail("Expected IllegalArgumentException due missing select columns");
+    }
+    catch (IllegalArgumentException e) {
+      // This is expected
+    }
+
+    try {
+      dbAccessor.buildQuery(tableName, new String[] {"id"}, new String[] 
{"name", "time"}, new String[] {"100"});
+      fail("Expected IllegalArgumentException due mismatch condition column 
and value arrays");
+    }
+    catch (IllegalArgumentException e) {
+      // This is expected
+    }
+  }
+
 }
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
index 5f6e24a..7d502be 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
@@ -236,7 +236,6 @@ public class AmbariLdapDataPopulatorTest {
     LdapServerProperties ldapServerProperties = 
createNiceMock(LdapServerProperties.class);
     expect(configurationProvider.get()).andReturn(configuration).anyTimes();
     expect(configuration.ldapEnabled()).andReturn(false);
-    
expect(configuration.getLdapServerProperties()).andReturn(ldapServerProperties);
     replay(ldapTemplate, ldapServerProperties, configurationProvider, 
configuration);
 
     final AmbariLdapDataPopulatorTestInstance populator = new 
AmbariLdapDataPopulatorTestInstance(configurationProvider, users);
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
index b09ac31..3d1385d 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
@@ -28,6 +28,9 @@ import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_CONFIGUR
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_CONFIGURATION_TABLE;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_INFRA_NEW_NAME;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_INFRA_OLD_NAME;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_SEQUENCES_TABLE;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.COMPONENT_DESIRED_STATE_TABLE;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.COMPONENT_NAME_COLUMN;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.COMPONENT_STATE_TABLE;
@@ -52,6 +55,32 @@ import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.PK_KERBEROS_KEY
 import static org.apache.ambari.server.upgrade.UpgradeCatalog270.PK_KKP;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.PK_KKP_MAPPING_SERVICE;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.PRINCIPAL_NAME_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_BASE_URL_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_COMPONENTS_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_DISTRIBUTION_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_FOREIGN_KEY;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_ID_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_MIRRORS_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_PRIMARY_KEY;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_REPO_ID_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_REPO_NAME_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_REPO_OS_ID_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_TABLE;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_UNIQUE_REPO_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_AMBARI_MANAGED_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_FAMILY_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_FOREIGN_KEY;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_ID_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_PRIMARY_KEY;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_REPO_VERSION_ID_COLUMN;
+import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_TABLE;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_FOREIGN_KEY;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_REPO_DEFINITION_ID_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_TABLE;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_TAG_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_VERSION_REPOSITORIES_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_VERSION_REPO_VERSION_ID_COLUMN;
+import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_VERSION_TABLE;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REQUEST_DISPLAY_STATUS_COLUMN;
 import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REQUEST_TABLE;
 import static 
org.apache.ambari.server.upgrade.UpgradeCatalog270.REQUEST_USER_NAME_COLUMN;
@@ -381,6 +410,12 @@ public class UpgradeCatalog270Test {
     Capture<DBAccessor.DBColumnInfo> updateUserTableCaptures = 
newCapture(CaptureType.ALL);
     Capture<DBAccessor.DBColumnInfo> alterUserTableCaptures = 
newCapture(CaptureType.ALL);
 
+    Capture<List<DBAccessor.DBColumnInfo>> addRepoOsTableCapturedColumns = 
newCapture(CaptureType.ALL);
+    Capture<List<DBAccessor.DBColumnInfo>> 
addRepoDefinitionTableCapturedColumns = newCapture(CaptureType.ALL);
+    Capture<List<DBAccessor.DBColumnInfo>> addRepoTagsTableCapturedColumns = 
newCapture(CaptureType.ALL);
+    Capture<String[]> insertAmbariSequencesRowColumns = 
newCapture(CaptureType.ALL);
+    Capture<String[]> insertAmbariSequencesRowValues = 
newCapture(CaptureType.ALL);
+
     // Any return value will work here as long as a SQLException is not thrown.
     expect(dbAccessor.getColumnType(USERS_TABLE, 
USERS_USER_TYPE_COLUMN)).andReturn(0).anyTimes();
 
@@ -388,6 +423,9 @@ public class UpgradeCatalog270Test {
     prepareUpdateGroupMembershipRecords(dbAccessor, 
createMembersTableCaptures);
     prepareUpdateAdminPrivilegeRecords(dbAccessor, 
createAdminPrincipalTableCaptures);
     prepareUpdateUsersTable(dbAccessor, updateUserTableCaptures, 
alterUserTableCaptures);
+    prepareUpdateRepoTables(dbAccessor, addRepoOsTableCapturedColumns, 
addRepoDefinitionTableCapturedColumns, addRepoTagsTableCapturedColumns,
+        insertAmbariSequencesRowColumns, insertAmbariSequencesRowValues);
+
     // upgradeKerberosTables
     Capture<List<DBAccessor.DBColumnInfo>> kerberosKeytabColumnsCapture = 
newCapture();
     dbAccessor.createTable(eq(KERBEROS_KEYTAB_TABLE), 
capture(kerberosKeytabColumnsCapture));
@@ -497,6 +535,8 @@ public class UpgradeCatalog270Test {
     validateUpdateGroupMembershipRecords(createMembersTableCaptures);
     validateUpdateAdminPrivilegeRecords(createAdminPrincipalTableCaptures);
     validateUpdateUsersTable(updateUserTableCaptures, alterUserTableCaptures);
+    validateCreateRepoOsTable(addRepoOsTableCapturedColumns, 
addRepoDefinitionTableCapturedColumns, addRepoTagsTableCapturedColumns,
+        insertAmbariSequencesRowColumns, insertAmbariSequencesRowValues);
 
     verify(dbAccessor);
   }
@@ -678,6 +718,52 @@ public class UpgradeCatalog270Test {
     expectLastCall().once();
   }
 
+  private void prepareUpdateRepoTables(DBAccessor dbAccessor,
+                                       Capture<List<DBAccessor.DBColumnInfo>> 
addRepoOsTableCapturedColumns,
+                                       Capture<List<DBAccessor.DBColumnInfo>> 
addRepoDefinitionTableCapturedColumns,
+                                       Capture<List<DBAccessor.DBColumnInfo>> 
addRepoTagsTableCapturedColumns,
+                                       Capture<String[]> 
insertAmbariSequencesRowColumns,
+                                       Capture<String[]> 
insertAmbariSequencesRowValues)
+      throws SQLException {
+
+    dbAccessor.createTable(eq(REPO_OS_TABLE), 
capture(addRepoOsTableCapturedColumns));
+    expectLastCall().once();
+    dbAccessor.addPKConstraint(REPO_OS_TABLE, REPO_OS_PRIMARY_KEY, 
REPO_OS_ID_COLUMN);
+    expectLastCall().once();
+    dbAccessor.addFKConstraint(REPO_OS_TABLE, REPO_OS_FOREIGN_KEY, 
REPO_OS_REPO_VERSION_ID_COLUMN, REPO_VERSION_TABLE, 
REPO_VERSION_REPO_VERSION_ID_COLUMN, false);
+    expectLastCall().once();
+
+    dbAccessor.createTable(eq(REPO_DEFINITION_TABLE), 
capture(addRepoDefinitionTableCapturedColumns));
+    expectLastCall().once();
+    dbAccessor.addPKConstraint(REPO_DEFINITION_TABLE, 
REPO_DEFINITION_PRIMARY_KEY, REPO_DEFINITION_ID_COLUMN);
+    expectLastCall().once();
+    dbAccessor.addFKConstraint(REPO_DEFINITION_TABLE, 
REPO_DEFINITION_FOREIGN_KEY, REPO_DEFINITION_REPO_OS_ID_COLUMN, REPO_OS_TABLE, 
REPO_OS_ID_COLUMN, false);
+    expectLastCall().once();
+
+    dbAccessor.createTable(eq(REPO_TAGS_TABLE), 
capture(addRepoTagsTableCapturedColumns));
+    expectLastCall().once();
+    dbAccessor.addFKConstraint(REPO_TAGS_TABLE, REPO_TAGS_FOREIGN_KEY, 
REPO_TAGS_REPO_DEFINITION_ID_COLUMN, REPO_DEFINITION_TABLE, 
REPO_DEFINITION_ID_COLUMN, false);
+    expectLastCall().once();
+
+    expect(dbAccessor.tableHasColumn(eq(REPO_VERSION_TABLE), 
eq(REPO_VERSION_REPOSITORIES_COLUMN))).andReturn(true).once();
+
+    expect(dbAccessor.getKeyToStringColumnMap(REPO_VERSION_TABLE, 
REPO_VERSION_REPO_VERSION_ID_COLUMN, REPO_VERSION_REPOSITORIES_COLUMN, null, 
null, true))
+        .andReturn(Collections.emptyMap())
+        .once();
+
+    expect(dbAccessor.insertRowIfMissing(eq(AMBARI_SEQUENCES_TABLE),
+        capture(insertAmbariSequencesRowColumns),
+        capture(insertAmbariSequencesRowValues),
+        eq(false))).andReturn(true).once();
+    expect(dbAccessor.insertRowIfMissing(eq(AMBARI_SEQUENCES_TABLE),
+        capture(insertAmbariSequencesRowColumns),
+        capture(insertAmbariSequencesRowValues),
+        eq(false))).andReturn(true).once();
+
+    dbAccessor.dropColumn(eq(REPO_VERSION_TABLE), 
eq(REPO_VERSION_REPOSITORIES_COLUMN));
+    expectLastCall().once();
+  }
+
   private void validateUpdateUsersTable(Capture<DBAccessor.DBColumnInfo> 
updateUserTableCaptures, Capture<DBAccessor.DBColumnInfo> 
alterUserTableCaptures) {
     Assert.assertTrue(updateUserTableCaptures.hasCaptured());
     validateColumns(updateUserTableCaptures.getValues(),
@@ -698,6 +784,59 @@ public class UpgradeCatalog270Test {
     );
   }
 
+  private void 
validateCreateRepoOsTable(Capture<List<DBAccessor.DBColumnInfo>> 
addRepoOsTableCapturedColumns,
+                                         
Capture<List<DBAccessor.DBColumnInfo>> addRepoDefinitionTableCapturedColumns,
+                                         
Capture<List<DBAccessor.DBColumnInfo>> addRepoTagsTableCapturedColumns, 
Capture<String[]> insertAmbariSequencesRowColumns, Capture<String[]> 
insertAmbariSequencesRowValues) {
+    Assert.assertTrue(addRepoOsTableCapturedColumns.hasCaptured());
+    validateColumns(addRepoOsTableCapturedColumns.getValue(),
+        Arrays.asList(
+            new DBAccessor.DBColumnInfo(REPO_OS_ID_COLUMN, Long.class, null, 
null, false),
+            new DBAccessor.DBColumnInfo(REPO_OS_REPO_VERSION_ID_COLUMN, 
Long.class, null, null, false),
+            new DBAccessor.DBColumnInfo(REPO_OS_FAMILY_COLUMN, String.class, 
255, null, false),
+            new DBAccessor.DBColumnInfo(REPO_OS_AMBARI_MANAGED_COLUMN, 
Integer.class, null, 1, true)
+        )
+    );
+
+    Assert.assertTrue(addRepoDefinitionTableCapturedColumns.hasCaptured());
+    validateColumns(addRepoDefinitionTableCapturedColumns.getValue(),
+        Arrays.asList(
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_ID_COLUMN, Long.class, 
null, null, false),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_OS_ID_COLUMN, 
Long.class, null, null, false),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_NAME_COLUMN, 
String.class, 255, null, false),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_ID_COLUMN, 
String.class, 255, null, false),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_BASE_URL_COLUMN, 
String.class, 2048, null, true),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_DISTRIBUTION_COLUMN, 
String.class, 2048, null, true),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_COMPONENTS_COLUMN, 
String.class, 2048, null, true),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_UNIQUE_REPO_COLUMN, 
Integer.class, 1, 1, true),
+            new DBAccessor.DBColumnInfo(REPO_DEFINITION_MIRRORS_COLUMN, 
String.class, 2048, null, true)
+        )
+    );
+
+    Assert.assertTrue(addRepoTagsTableCapturedColumns.hasCaptured());
+    validateColumns(addRepoTagsTableCapturedColumns.getValue(),
+        Arrays.asList(
+            new DBAccessor.DBColumnInfo(REPO_TAGS_REPO_DEFINITION_ID_COLUMN, 
Long.class, null, null, false),
+            new DBAccessor.DBColumnInfo(REPO_TAGS_TAG_COLUMN, String.class, 
255, null, false)
+        )
+    );
+
+    List<String[]> values;
+
+    Assert.assertTrue(insertAmbariSequencesRowColumns.hasCaptured());
+    values = insertAmbariSequencesRowColumns.getValues();
+    Assert.assertEquals(2, values.size());
+    Assert.assertArrayEquals(new 
String[]{AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN, 
AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN}, values.get(0));
+    Assert.assertArrayEquals(new 
String[]{AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN, 
AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN}, values.get(1));
+
+    Assert.assertTrue(insertAmbariSequencesRowValues.hasCaptured());
+    values = insertAmbariSequencesRowValues.getValues();
+    Assert.assertEquals(2, values.size());
+    Assert.assertArrayEquals(new String[]{"'repo_os_id_seq'", "1"}, 
values.get(0));
+    Assert.assertArrayEquals(new String[]{"'repo_definition_id_seq'", "1"}, 
values.get(1));
+
+
+  }
+
   private void validateColumns(List<DBAccessor.DBColumnInfo> capturedColumns, 
List<DBAccessor.DBColumnInfo> expectedColumns) {
     Assert.assertEquals(expectedColumns.size(), capturedColumns.size());
 
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeTest.java 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeTest.java
index 207e958..f2e1b6a 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeTest.java
@@ -217,8 +217,6 @@ public class UpgradeTest {
       }
      }
 
-    schemaUpgradeHelper.startPersistenceService();
-
     schemaUpgradeHelper.executePreDMLUpdates(upgradeCatalogs);
 
     schemaUpgradeHelper.executeDMLUpdates(upgradeCatalogs, "test");
@@ -226,8 +224,6 @@ public class UpgradeTest {
     schemaUpgradeHelper.executeOnPostUpgrade(upgradeCatalogs);
 
     LOG.info("Upgrade successful.");
-
-    schemaUpgradeHelper.stopPersistenceService();
   }
 
   private String getLastVersion() throws Exception {

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to