浏览代码

Merge pull request #221 from dlysnichenko/AMBARI-22871-trunk

[AMBARI-22871] Move Stack OS and Repository to DB (dlysnichenko)
Lisnichenko Dmitro 7 年之前
父节点
当前提交
ca8934d0e6
共有 44 个文件被更改,包括 1040 次插入682 次删除
  1. 2 2
      ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
  2. 7 7
      ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
  3. 10 10
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
  4. 10 10
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
  5. 5 5
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java
  6. 10 13
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
  7. 10 10
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
  8. 9 8
      ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java
  9. 0 78
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/OperatingSystemEntity.java
  10. 212 0
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepoDefinitionEntity.java
  11. 164 0
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepoOsEntity.java
  12. 0 135
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java
  13. 32 45
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
  14. 18 15
      ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java
  15. 3 4
      ambari-server/src/main/java/org/apache/ambari/server/stack/UpdateActiveRepoVersionOnStartup.java
  16. 54 101
      ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java
  17. 1 1
      ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
  18. 29 1
      ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
  19. 27 1
      ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
  20. 27 1
      ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
  21. 28 1
      ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
  22. 28 1
      ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
  23. 28 1
      ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
  24. 2 0
      ambari-server/src/main/resources/META-INF/persistence.xml
  25. 1 1
      ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java
  26. 7 1
      ambari-server/src/test/java/org/apache/ambari/server/checks/InstallPackagesCheckTest.java
  27. 12 7
      ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
  28. 1 1
      ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
  29. 63 58
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
  30. 11 3
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/CompatibleRepositoryVersionResourceProviderTest.java
  31. 22 18
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProviderTest.java
  32. 48 30
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java
  33. 43 8
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
  34. 1 1
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java
  35. 19 2
      ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
  36. 2 1
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/CrudDAOTest.java
  37. 1 0
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostVersionDAOTest.java
  38. 8 7
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAOTest.java
  39. 15 3
      ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java
  40. 29 28
      ambari-server/src/test/java/org/apache/ambari/server/stack/RepoUtilTest.java
  41. 36 1
      ambari-server/src/test/java/org/apache/ambari/server/stack/UpdateActiveRepoVersionOnStartupTest.java
  42. 3 2
      ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java
  43. 2 2
      ambari-server/src/test/java/org/apache/ambari/server/state/services/RetryUpgradeActionServiceTest.java
  44. 0 58
      ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java

+ 2 - 2
ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java

@@ -36,7 +36,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
 import org.apache.ambari.server.state.Cluster;
@@ -246,7 +246,7 @@ public class ExecutionCommandWrapper {
             commandRepository = repoVersionHelper.getCommandRepository(null, serviceComponent, host);
           } else {
             RepositoryVersionEntity repoVersion = service.getDesiredRepositoryVersion();
-            OperatingSystemEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
+            RepoOsEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
             commandRepository = repoVersionHelper.getCommandRepository(repoVersion, osEntity);
           }
           executionCommand.setRepositoryFile(commandRepository);

+ 7 - 7
ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java

@@ -24,7 +24,7 @@ import java.util.Set;
 
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.annotations.ExperimentalFeature;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.stack.RepoTag;
 import org.apache.commons.lang.builder.ToStringBuilder;
@@ -107,10 +107,10 @@ public class CommandRepository {
    * @param osType        the OS type for the repositories
    * @param repositories  the repository entities that should be processed into a file
    */
-  public void setRepositories(String osType, Collection<RepositoryEntity> repositories) {
+  public void setRepositories(String osType, Collection<RepoDefinitionEntity> repositories) {
     m_repositories = new ArrayList<>();
 
-    for (RepositoryEntity entity : repositories) {
+    for (RepoDefinitionEntity entity : repositories) {
       m_repositories.add(new Repository(osType, entity));
     }
   }
@@ -274,13 +274,13 @@ public class CommandRepository {
       m_tags = info.getTags();
     }
 
-    private Repository(String osType, RepositoryEntity entity) {
+    private Repository(String osType, RepoDefinitionEntity entity) {
       m_baseUrl = entity.getBaseUrl();
-      m_repoId = entity.getRepositoryId();
-      m_repoName = entity.getName();
+      m_repoId = entity.getRepoID();
+      m_repoName = entity.getRepoName();
       m_distribution = entity.getDistribution();
       m_components = entity.getComponents();
-      m_mirrorsList = entity.getMirrorsList();
+      m_mirrorsList = entity.getMirrors();
       m_osType = osType;
       m_tags = entity.getTags();
     }

+ 10 - 10
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java

@@ -124,8 +124,8 @@ import org.apache.ambari.server.orm.dao.WidgetLayoutDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ExtensionLinkEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.SettingEntity;
 import org.apache.ambari.server.orm.entities.WidgetEntity;
@@ -4222,12 +4222,12 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     if (repositoryVersionId != null) {
       final RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByPK(repositoryVersionId);
       if (repositoryVersion != null) {
-        for (OperatingSystemEntity operatingSystem: repositoryVersion.getOperatingSystems()) {
-          if (operatingSystem.getOsType().equals(osType)) {
-            for (RepositoryEntity repository: operatingSystem.getRepositories()) {
+        for (RepoOsEntity operatingSystem : repositoryVersion.getRepoOsEntities()) {
+          if (operatingSystem.getFamily().equals(osType)) {
+            for (RepoDefinitionEntity repository : operatingSystem.getRepoDefinitionEntities()) {
 
-              final RepositoryResponse response = new RepositoryResponse(repository.getBaseUrl(), osType, repository.getRepositoryId(),
-                      repository.getName(), repository.getDistribution(), repository.getComponents(), "", "",
+              final RepositoryResponse response = new RepositoryResponse(repository.getBaseUrl(), osType, repository.getRepoID(),
+                  repository.getRepoName(), repository.getDistribution(), repository.getComponents(), "", "",
                       repository.getTags());
               if (null != versionDefinitionId) {
                 response.setVersionDefinitionId(versionDefinitionId);
@@ -4667,8 +4667,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     if (repositoryVersionId != null) {
       final RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByPK(repositoryVersionId);
       if (repositoryVersion != null) {
-        for (OperatingSystemEntity operatingSystem: repositoryVersion.getOperatingSystems()) {
-          final OperatingSystemResponse response = new OperatingSystemResponse(operatingSystem.getOsType());
+        for (RepoOsEntity operatingSystem : repositoryVersion.getRepoOsEntities()) {
+          final OperatingSystemResponse response = new OperatingSystemResponse(operatingSystem.getFamily());
           if (null != versionDefinitionId) {
             response.setVersionDefinitionId(repositoryVersionId.toString());
           } else {
@@ -4676,7 +4676,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           }
           response.setStackName(repositoryVersion.getStackName());
           response.setStackVersion(repositoryVersion.getStackVersion());
-          response.setAmbariManagedRepos(operatingSystem.isAmbariManagedRepos());
+          response.setAmbariManagedRepos(operatingSystem.isAmbariManaged());
           responses.add(response);
         }
       }

+ 10 - 10
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java

@@ -62,8 +62,8 @@ import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
@@ -546,13 +546,13 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
     final AmbariMetaInfo ami = managementController.getAmbariMetaInfo();
 
     // build the list of OS repos
-    List<OperatingSystemEntity> operatingSystems = repoVersionEnt.getOperatingSystems();
-    Map<String, List<RepositoryEntity>> perOsRepos = new HashMap<>();
-    for (OperatingSystemEntity operatingSystem : operatingSystems) {
-      if (operatingSystem.isAmbariManagedRepos()) {
-        perOsRepos.put(operatingSystem.getOsType(), operatingSystem.getRepositories());
+    List<RepoOsEntity> operatingSystems = repoVersionEnt.getRepoOsEntities();
+    Map<String, List<RepoDefinitionEntity>> perOsRepos = new HashMap<>();
+    for (RepoOsEntity operatingSystem : operatingSystems) {
+      if (operatingSystem.isAmbariManaged()) {
+        perOsRepos.put(operatingSystem.getFamily(), operatingSystem.getRepoDefinitionEntities());
       } else {
-        perOsRepos.put(operatingSystem.getOsType(), Collections.<RepositoryEntity> emptyList());
+        perOsRepos.put(operatingSystem.getFamily(), Collections.<RepoDefinitionEntity>emptyList());
       }
     }
 
@@ -699,9 +699,9 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou
 
     // Determine repositories for host
     String osFamily = host.getOsFamily();
-    OperatingSystemEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
+    RepoOsEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
 
-    if (CollectionUtils.isEmpty(osEntity.getRepositories())) {
+    if (CollectionUtils.isEmpty(osEntity.getRepoDefinitionEntities())) {
       throw new SystemException(String.format("Repositories for os type %s are not defined for version %s of Stack %s.",
             osFamily, repoVersion.getVersion(), stackId));
     }

+ 5 - 5
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProvider.java

@@ -52,7 +52,7 @@ import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Host;
@@ -385,9 +385,9 @@ public class HostStackVersionResourceProvider extends AbstractControllerResource
 
     // Determine repositories for host
     String osFamily = host.getOsFamily();
-    OperatingSystemEntity osEntity = null;
-    for (OperatingSystemEntity operatingSystem : repoVersionEnt.getOperatingSystems()) {
-      if (osFamily.equals(operatingSystem.getOsType())) {
+    RepoOsEntity osEntity = null;
+    for (RepoOsEntity operatingSystem : repoVersionEnt.getRepoOsEntities()) {
+      if (osFamily.equals(operatingSystem.getFamily())) {
         osEntity = operatingSystem;
         break;
       }
@@ -398,7 +398,7 @@ public class HostStackVersionResourceProvider extends AbstractControllerResource
           osFamily));
     }
 
-    if (CollectionUtils.isEmpty(osEntity.getRepositories())) {
+    if (CollectionUtils.isEmpty(osEntity.getRepoDefinitionEntities())) {
       throw new SystemException(String.format("Repositories for os type %s are " +
                       "not defined. Repo version=%s, stackId=%s",
         osFamily, desiredRepoVersion, stackId));

+ 10 - 13
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java

@@ -48,8 +48,8 @@ import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
@@ -337,11 +337,10 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc
             final Object operatingSystems = propertyMap.get(SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID);
             final String operatingSystemsJson = gson.toJson(operatingSystems);
             try {
-              repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
+              entity.addRepoOsEntities(repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson));
             } catch (Exception ex) {
               throw new AmbariException("Json structure for operating systems is incorrect", ex);
             }
-            entity.setOperatingSystems(operatingSystemsJson);
           }
 
           if (StringUtils.isNotBlank(ObjectUtils.toString(propertyMap.get(REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID)))) {
@@ -456,8 +455,8 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc
     Set<String> existingRepoUrls = new HashSet<>();
     List<RepositoryVersionEntity> existingRepoVersions = dao.findByStack(requiredStack);
     for (RepositoryVersionEntity existingRepoVersion : existingRepoVersions) {
-      for (OperatingSystemEntity operatingSystemEntity : existingRepoVersion.getOperatingSystems()) {
-        for (RepositoryEntity repositoryEntity : operatingSystemEntity.getRepositories()) {
+      for (RepoOsEntity operatingSystemEntity : existingRepoVersion.getRepoOsEntities()) {
+        for (RepoDefinitionEntity repositoryEntity : operatingSystemEntity.getRepoDefinitionEntities()) {
           if (repositoryEntity.isUnique() && !existingRepoVersion.getId().equals(repositoryVersion.getId())) { // Allow modifying already defined repo version
             existingRepoUrls.add(repositoryEntity.getBaseUrl());
           }
@@ -473,12 +472,12 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc
 
     final Set<String> osRepositoryVersion = new HashSet<>();
 
-    for (OperatingSystemEntity os: repositoryVersion.getOperatingSystems()) {
-      osRepositoryVersion.add(os.getOsType());
+    for (RepoOsEntity os : repositoryVersion.getRepoOsEntities()) {
+      osRepositoryVersion.add(os.getFamily());
 
-      for (RepositoryEntity repositoryEntity : os.getRepositories()) {
+      for (RepoDefinitionEntity repositoryEntity : os.getRepoDefinitionEntities()) {
         String baseUrl = repositoryEntity.getBaseUrl();
-        if (!skipUrlCheck && os.isAmbariManagedRepos() && existingRepoUrls.contains(baseUrl)) {
+        if (!skipUrlCheck && os.isAmbariManaged() && existingRepoUrls.contains(baseUrl)) {
           throw new AmbariException("Base url " + baseUrl + " is already defined for another repository version. " +
                   "Setting up base urls that contain the same versions of components will cause stack upgrade to fail.");
         }
@@ -523,12 +522,10 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc
     final Object operatingSystems = properties.get(SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID);
     final String operatingSystemsJson = gson.toJson(operatingSystems);
     try {
-      repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
+      entity.addRepoOsEntities(repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson));
     } catch (Exception ex) {
       throw new AmbariException("Json structure for operating systems is incorrect", ex);
     }
-    entity.setOperatingSystems(operatingSystemsJson);
-
     return entity;
   }
 

+ 10 - 10
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java

@@ -49,8 +49,8 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.security.authorization.ResourceType;
@@ -614,7 +614,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
         s_metaInfo.get().getStack(stackId.getStackName(), stackId.getStackVersion()).getRepositoriesByOs();
     repos.addAll(RepoUtil.getServiceRepos(repos, stackReposByOs));
 
-    entity.setOperatingSystems(s_repoVersionHelper.get().serializeOperatingSystems(repos));
+    entity.addRepoOsEntities(s_repoVersionHelper.get().createRepoOsEntities(repos));
 
     entity.setVersion(holder.xml.release.getFullVersion());
     entity.setDisplayName(stackId, holder.xml.release);
@@ -744,14 +744,14 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
 
     ArrayNode subs = factory.arrayNode();
 
-    for (OperatingSystemEntity os : entity.getOperatingSystems()) {
+    for (RepoOsEntity os : entity.getRepoOsEntities()) {
       ObjectNode osBase = factory.objectNode();
 
       ObjectNode osElement = factory.objectNode();
       osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS),
-          os.isAmbariManagedRepos());
+          os.isAmbariManaged());
       osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID),
-          os.getOsType());
+          os.getFamily());
 
       osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID),
           entity.getStackName());
@@ -762,7 +762,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
           osElement);
 
       ArrayNode reposArray = factory.arrayNode();
-      for (RepositoryEntity repo : os.getRepositories()) {
+      for (RepoDefinitionEntity repo : os.getRepoDefinitionEntities()) {
         ObjectNode repoBase = factory.objectNode();
 
         ObjectNode repoElement = factory.objectNode();
@@ -770,11 +770,11 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID),
             repo.getBaseUrl());
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_OS_TYPE_PROPERTY_ID),
-            os.getOsType());
+            os.getFamily());
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID),
-            repo.getRepositoryId());
+            repo.getRepoID());
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID),
-            repo.getName());
+            repo.getRepoName());
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_DISTRIBUTION_PROPERTY_ID),
             repo.getDistribution());
         repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_COMPONENTS_PROPERTY_ID),

+ 9 - 8
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java

@@ -24,6 +24,7 @@ import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.state.RepositoryType;
@@ -159,14 +160,14 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long>
    * @param stackEntity Stack entity.
    * @param version Stack version, e.g., 2.2 or 2.2.0.1-885
    * @param displayName Unique display name
-   * @param operatingSystems JSON structure of repository URLs for each OS
+   * @param repoOsEntities structure of repository URLs for each OS
    * @return Returns the object created if successful, and throws an exception otherwise.
    * @throws AmbariException
    */
   public RepositoryVersionEntity create(StackEntity stackEntity,
-      String version, String displayName,
-      String operatingSystems) throws AmbariException {
-      return create(stackEntity, version, displayName, operatingSystems,
+                                        String version, String displayName,
+                                        List<RepoOsEntity> repoOsEntities) throws AmbariException {
+    return create(stackEntity, version, displayName, repoOsEntities,
           RepositoryType.STANDARD);
   }
 
@@ -176,15 +177,15 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long>
    * @param stackEntity Stack entity.
    * @param version Stack version, e.g., 2.2 or 2.2.0.1-885
    * @param displayName Unique display name
-   * @param operatingSystems JSON structure of repository URLs for each OS
+   * @param repoOsEntities structure of repository URLs for each OS
    * @param type  the repository type
    * @return Returns the object created if successful, and throws an exception otherwise.
    * @throws AmbariException
    */
   @Transactional
   public RepositoryVersionEntity create(StackEntity stackEntity,
-      String version, String displayName,
-      String operatingSystems, RepositoryType type) throws AmbariException {
+                                        String version, String displayName, List<RepoOsEntity> repoOsEntities,
+                                        RepositoryType type) throws AmbariException {
 
     if (stackEntity == null || version == null || version.isEmpty()
         || displayName == null || displayName.isEmpty()) {
@@ -211,7 +212,7 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long>
     }
 
     RepositoryVersionEntity newEntity = new RepositoryVersionEntity(
-        stackEntity, version, displayName, operatingSystems);
+        stackEntity, version, displayName, repoOsEntities);
     newEntity.setType(type);
     this.create(newEntity);
     return newEntity;

+ 0 - 78
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/OperatingSystemEntity.java

@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.orm.entities;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Emulates entity to provide a quick way to change it to real entity in future.
- */
-public class OperatingSystemEntity {
-
-  private String osType;
-  private List<RepositoryEntity> repositories = new ArrayList<>();
-  private boolean ambariManagedRepos = true;
-
-  public String getOsType() {
-    return osType;
-  }
-
-  public void setOsType(String osType) {
-    this.osType = osType;
-  }
-
-  public List<RepositoryEntity> getRepositories() {
-    return repositories;
-  }
-
-  public void setRepositories(List<RepositoryEntity> repositories) {
-    this.repositories = repositories;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    OperatingSystemEntity that = (OperatingSystemEntity) o;
-
-    if (osType != null ? !osType.equals(that.osType) : that.osType != null) return false;
-
-    return true;
-  }
-
-  public void setAmbariManagedRepos(boolean managed) {
-    ambariManagedRepos = managed;
-  }
-
-  /**
-   * @return
-   */
-  public boolean isAmbariManagedRepos() {
-    return ambariManagedRepos;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = osType != null ? osType.hashCode() : 0;
-    return result;
-  }
-
-
-}

+ 212 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepoDefinitionEntity.java

@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.entities;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import org.apache.ambari.server.state.stack.RepoTag;
+
+import com.google.common.base.Objects;
+
+/**
+ * Represents a Repository definition type.
+ */
+@Entity
+@Table(name = "repo_definition")
+@TableGenerator(name = "repo_definition_id_generator",
+    table = "ambari_sequences",
+    pkColumnName = "sequence_name",
+    valueColumnName = "sequence_value",
+    pkColumnValue = "repo_definition_id_seq"
+)
+public class RepoDefinitionEntity {
+  @Id
+  @Column(name = "id", nullable = false)
+  @GeneratedValue(strategy = GenerationType.TABLE, generator = "repo_definition_id_generator")
+  private Long id;
+
+  /**
+   * CollectionTable for RepoTag enum
+   */
+  @Enumerated(value = EnumType.STRING)
+  @ElementCollection(targetClass = RepoTag.class)
+  @CollectionTable(name = "repo_tags", joinColumns = @JoinColumn(name = "repo_definition_id"))
+  @Column(name = "tag")
+  private Set<RepoTag> repoTags = new HashSet<>();
+
+  /**
+   * many-to-one association to {@link RepoOsEntity}
+   */
+  @ManyToOne(fetch = FetchType.EAGER)
+  @JoinColumn(name = "repo_os_id", nullable = false)
+  private RepoOsEntity repoOs;
+
+  @Column(name = "repo_name", nullable = false)
+  private String repoName;
+
+  @Column(name = "repo_id", nullable = false)
+  private String repoID;
+
+  @Column(name = "base_url", nullable = false)
+  private String baseUrl;
+
+  @Column(name = "mirrors")
+  private String mirrors;
+
+  @Column(name = "distribution")
+  private String distribution;
+
+  @Column(name = "components")
+  private String components;
+
+  @Column(name = "unique_repo", nullable = false)
+  private short unique = 0;
+
+
+  public String getDistribution() {
+    return distribution;
+  }
+
+  public void setDistribution(String distribution) {
+    this.distribution = distribution;
+  }
+
+  public RepoOsEntity getRepoOs() {
+    return repoOs;
+  }
+
+  public void setRepoOs(RepoOsEntity repoOs) {
+    this.repoOs = repoOs;
+  }
+
+  public String getRepoName() {
+    return repoName;
+  }
+
+  public void setRepoName(String repoName) {
+    this.repoName = repoName;
+  }
+
+  public String getRepoID() {
+    return repoID;
+  }
+
+  public void setRepoID(String repoID) {
+    this.repoID = repoID;
+  }
+
+  public String getBaseUrl() {
+    return baseUrl;
+  }
+
+  public void setBaseUrl(String baseUrl) {
+    this.baseUrl = baseUrl;
+  }
+
+  public String getMirrors() {
+    return mirrors;
+  }
+
+  public void setMirrors(String mirrors) {
+    this.mirrors = mirrors;
+  }
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public String getComponents() {
+    return components;
+  }
+
+  public void setComponents(String components) {
+    this.components = components;
+  }
+
+  public boolean isUnique() {
+    return unique == 1;
+  }
+
+  public void setUnique(boolean unique) {
+    this.unique = (short) (unique ? 1 : 0);
+  }
+
+  public Set<RepoTag> getTags() {
+    return repoTags;
+  }
+
+  public void setTags(Set<RepoTag> repoTags) {
+    this.repoTags = repoTags;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode() {
+    return java.util.Objects.hash(repoTags, repoName, repoID, baseUrl, mirrors, distribution, components, unique);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(Object object) {
+    if (null == object) {
+      return false;
+    }
+
+    if (this == object) {
+      return true;
+    }
+
+    if (object.getClass() != getClass()) {
+      return false;
+    }
+
+    RepoDefinitionEntity that = (RepoDefinitionEntity) object;
+    return Objects.equal(unique, that.unique)
+        && Objects.equal(repoTags, that.repoTags)
+        && Objects.equal(repoName, that.repoName)
+        && Objects.equal(repoID, that.repoID)
+        && Objects.equal(baseUrl, that.baseUrl)
+        && Objects.equal(mirrors, that.mirrors)
+        && Objects.equal(distribution, that.distribution)
+        && Objects.equal(components, that.components);
+  }
+}

+ 164 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepoOsEntity.java

@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.orm.entities;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.google.common.base.Objects;
+
+/**
+ * Represents a Repository operation system type.
+ */
+@Entity
+@Table(name = "repo_os")
+@TableGenerator(name = "repo_os_id_generator",
+    table = "ambari_sequences",
+    pkColumnName = "sequence_name",
+    valueColumnName = "sequence_value",
+    pkColumnValue = "repo_os_id_seq"
+)
+public class RepoOsEntity {
+  @Id
+  @Column(name = "id", nullable = false)
+  @GeneratedValue(strategy = GenerationType.TABLE, generator = "repo_os_id_generator")
+  private Long id;
+
+  @Column(name = "family")
+  private String family;
+
+  @Column(name = "ambari_managed", nullable = false)
+  private short ambariManaged = 0;
+
+  /**
+   * one-to-many association to {@link RepoDefinitionEntity}
+   */
+  @OneToMany(orphanRemoval = true, fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "repoOs")
+  private List<RepoDefinitionEntity> repoDefinitionEntities = new ArrayList<>();
+
+  /**
+   * many-to-one association to {@link RepositoryVersionEntity}
+   */
+  @ManyToOne(fetch = FetchType.EAGER)
+  @JoinColumn(name = "repo_version_id", nullable = false)
+  private RepositoryVersionEntity repositoryVersionEntity;
+
+  /**
+   * @return repoDefinitionEntities
+   */
+  public List<RepoDefinitionEntity> getRepoDefinitionEntities() {
+    return repoDefinitionEntities;
+  }
+
+  /**
+   * Update one-to-many relation without rebuilding the whole entity
+   *
+   * @param repoDefinitionEntities list of many-to-one entities
+   */
+  public void addRepoDefinitionEntities(List<RepoDefinitionEntity> repoDefinitionEntities) {
+    this.repoDefinitionEntities.addAll(repoDefinitionEntities);
+    for (RepoDefinitionEntity repoDefinitionEntity : repoDefinitionEntities) {
+      repoDefinitionEntity.setRepoOs(this);
+    }
+  }
+
+  /**
+   * Update one-to-many relation without rebuilding the whole entity
+   * @param repoDefinition many-to-one entity
+   */
+  public void addRepoDefinition(RepoDefinitionEntity repoDefinition) {
+    this.repoDefinitionEntities.add(repoDefinition);
+    repoDefinition.setRepoOs(this);
+  }
+
+  public RepositoryVersionEntity getRepositoryVersionEntity() {
+    return repositoryVersionEntity;
+  }
+
+  public void setRepositoryVersionEntity(RepositoryVersionEntity repositoryVersionEntity) {
+    this.repositoryVersionEntity = repositoryVersionEntity;
+  }
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public String getFamily() {
+    return family;
+  }
+
+  public void setFamily(String family) {
+    this.family = family;
+  }
+
+  public boolean isAmbariManaged() {
+    return ambariManaged == 1;
+  }
+
+  public void setAmbariManaged(boolean ambariManaged) {
+    this.ambariManaged = (short) (ambariManaged ? 1 : 0);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode() {
+    return java.util.Objects.hash(family, ambariManaged, repoDefinitionEntities);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(Object object) {
+    if (null == object) {
+      return false;
+    }
+
+    if (this == object) {
+      return true;
+    }
+
+    if (object.getClass() != getClass()) {
+      return false;
+    }
+
+    RepoOsEntity that = (RepoOsEntity) object;
+    return Objects.equal(ambariManaged, that.ambariManaged)
+        && Objects.equal(family, that.family)
+        && Objects.equal(repoDefinitionEntities, that.repoDefinitionEntities);
+  }
+}

+ 0 - 135
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryEntity.java

@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.orm.entities;
-
-import java.util.Collections;
-import java.util.Set;
-
-import org.apache.ambari.server.state.stack.RepoTag;
-
-/**
- * Emulates entity to provide a quick way to change it to real entity in future.
- */
-public class RepositoryEntity {
-
-  private String name;
-  private String distribution;
-  private String components;
-  private String baseUrl;
-  private String repositoryId;
-  private String mirrorsList;
-  private boolean unique;
-
-  private Set<RepoTag> tags;
-
-  public String getName() {
-    return name;
-  }
-
-  public void setName(String name) {
-    this.name = name;
-  }
-
-  public String getDistribution() {
-    return distribution;
-  }
-
-  public void setDistribution(String distribution) {
-    this.distribution = distribution;
-  }
-
-  public String getComponents() {
-    return components;
-  }
-
-  public void setComponents(String components) {
-    this.components = components;
-  }
-
-  public String getBaseUrl() {
-    return baseUrl;
-  }
-
-  public void setBaseUrl(String baseUrl) {
-    this.baseUrl = baseUrl;
-  }
-
-  public String getRepositoryId() {
-    return repositoryId;
-  }
-
-  public void setRepositoryId(String repositoryId) {
-    this.repositoryId = repositoryId;
-  }
-
-  public String getMirrorsList() {
-    return mirrorsList;
-  }
-
-  public void setMirrorsList(String mirrorsList) {
-    this.mirrorsList = mirrorsList;
-  }
-
-  public boolean isUnique() {
-    return unique;
-  }
-
-  public void setUnique(boolean unique) {
-    this.unique = unique;
-  }
-
-  /**
-   * @return the repo tags
-   */
-  public Set<RepoTag> getTags() {
-    return tags == null ? Collections.<RepoTag>emptySet() : tags;
-  }
-
-  /**
-   * @param repoTags the tags to set
-   */
-  public void setTags(Set<RepoTag> repoTags) {
-    tags = repoTags;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    RepositoryEntity that = (RepositoryEntity) o;
-
-    if (name != null ? !name.equals(that.name) : that.name != null) return false;
-    if (distribution != null ? !distribution.equals(that.distribution) : that.distribution != null) return false;
-    if (components != null ? !components.equals(that.components) : that.components != null) return false;
-    if (baseUrl != null ? !baseUrl.equals(that.baseUrl) : that.baseUrl != null) return false;
-    if (repositoryId != null ? !repositoryId.equals(that.repositoryId) : that.repositoryId != null) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = name != null ? name.hashCode() : 0;
-    result = 31 * result + (distribution != null ? distribution.hashCode() : 0);
-    result = 31 * result + (components != null ? components.hashCode() : 0);
-    result = 31 * result + (baseUrl != null ? baseUrl.hashCode() : 0);
-    result = 31 * result + (repositoryId != null ? repositoryId.hashCode() : 0);
-    return result;
-  }
-}

+ 32 - 45
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java

@@ -17,7 +17,7 @@
  */
 package org.apache.ambari.server.orm.entities;
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -26,6 +26,7 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
@@ -52,8 +53,6 @@ import org.apache.ambari.server.state.repository.Release;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
 import com.google.inject.Inject;
@@ -68,8 +67,7 @@ import com.google.inject.Provider;
     table = "ambari_sequences",
     pkColumnName = "sequence_name",
     valueColumnName = "sequence_value",
-    pkColumnValue = "repo_version_id_seq",
-    initialValue = 0
+    pkColumnValue = "repo_version_id_seq"
     )
 @NamedQueries({
     @NamedQuery(
@@ -95,8 +93,6 @@ import com.google.inject.Provider;
         query = "SELECT repositoryVersion FROM RepositoryVersionEntity repositoryVersion WHERE repositoryVersion IN (SELECT DISTINCT sd1.desiredRepositoryVersion FROM ServiceDesiredStateEntity sd1 WHERE sd1.desiredRepositoryVersion IN ?1)") })
 @StaticallyInject
 public class RepositoryVersionEntity {
-  private static final Logger LOG = LoggerFactory.getLogger(RepositoryVersionEntity.class);
-
   @Inject
   private static Provider<RepositoryVersionHelper> repositoryVersionHelperProvider;
 
@@ -109,7 +105,7 @@ public class RepositoryVersionEntity {
    * Unidirectional one-to-one association to {@link StackEntity}
    */
   @OneToOne
-  @JoinColumn(name = "stack_id", unique = false, nullable = false, insertable = true, updatable = true)
+  @JoinColumn(name = "stack_id", nullable = false)
   private StackEntity stack;
 
   @Column(name = "version")
@@ -118,31 +114,33 @@ public class RepositoryVersionEntity {
   @Column(name = "display_name")
   private String displayName;
 
-  @Lob
-  @Column(name = "repositories")
-  private String operatingSystems;
+  /**
+   * one-to-many association to {@link RepoOsEntity}
+   */
+  @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "repositoryVersionEntity", orphanRemoval = true)
+  private List<RepoOsEntity> repoOsEntities = new ArrayList<>();
 
   @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "repositoryVersion")
   private Set<HostVersionEntity> hostVersionEntities;
 
-  @Column(name = "repo_type", nullable = false, insertable = true, updatable = true)
+  @Column(name = "repo_type", nullable = false)
   @Enumerated(value = EnumType.STRING)
   private RepositoryType type = RepositoryType.STANDARD;
 
   @Lob
-  @Column(name="version_xml", insertable = true, updatable = true)
+  @Column(name="version_xml")
   private String versionXml;
 
   @Transient
   private VersionDefinitionXml versionDefinition = null;
 
-  @Column(name="version_url", nullable=true, insertable=true, updatable=true)
+  @Column(name="version_url")
   private String versionUrl;
 
-  @Column(name="version_xsd", insertable = true, updatable = true)
+  @Column(name="version_xsd")
   private String versionXsd;
 
-  @Column(name = "hidden", nullable = false, insertable = true, updatable = true)
+  @Column(name = "hidden", nullable = false)
   private short isHidden = 0;
 
   /**
@@ -173,11 +171,14 @@ public class RepositoryVersionEntity {
   }
 
   public RepositoryVersionEntity(StackEntity stack, String version,
-      String displayName, String operatingSystems) {
+                                 String displayName, List<RepoOsEntity> repoOsEntities) {
     this.stack = stack;
     this.version = version;
     this.displayName = displayName;
-    this.operatingSystems = operatingSystems;
+    this.repoOsEntities = repoOsEntities;
+    for (RepoOsEntity repoOsEntity : repoOsEntities) {
+      repoOsEntity.setRepositoryVersionEntity(this);
+    }
   }
 
   @PreUpdate
@@ -265,31 +266,6 @@ public class RepositoryVersionEntity {
   }
 
 
-  public String getOperatingSystemsJson() {
-    return operatingSystems;
-  }
-
-  public void setOperatingSystems(String repositories) {
-    operatingSystems = repositories;
-  }
-
-  /**
-   * Getter which hides json nature of operating systems and returns them as entities.
-   *
-   * @return empty list if stored json is invalid
-   */
-  public List<OperatingSystemEntity> getOperatingSystems() {
-    if (StringUtils.isNotBlank(operatingSystems)) {
-      try {
-        return repositoryVersionHelperProvider.get().parseOperatingSystems(operatingSystems);
-      } catch (Exception ex) {
-        String msg = String.format("Failed to parse repository from OS/Repo information in the database: %s. Required fields: repo_name, repo_id, base_url", operatingSystems);
-        LOG.error(msg, ex);
-      }
-    }
-    return Collections.emptyList();
-  }
-
   public String getStackName() {
     return getStackId().getStackName();
   }
@@ -385,7 +361,7 @@ public class RepositoryVersionEntity {
    */
   @Override
   public int hashCode() {
-    return java.util.Objects.hash(stack, version, displayName, operatingSystems);
+    return java.util.Objects.hash(stack, version, displayName, repoOsEntities);
   }
 
   /**
@@ -408,7 +384,7 @@ public class RepositoryVersionEntity {
     RepositoryVersionEntity that = (RepositoryVersionEntity) object;
     return Objects.equal(stack, that.stack) && Objects.equal(version, that.version)
         && Objects.equal(displayName, that.displayName)
-        && Objects.equal(operatingSystems, that.operatingSystems);
+        && Objects.equal(repoOsEntities, that.repoOsEntities);
   }
 
   /**
@@ -529,4 +505,15 @@ public class RepositoryVersionEntity {
   public void setResolved(boolean resolved) {
     this.resolved = resolved ? (short) 1 : (short) 0;
   }
+
+  public List<RepoOsEntity> getRepoOsEntities() {
+    return repoOsEntities;
+  }
+
+  public void addRepoOsEntities(List<RepoOsEntity> repoOsEntities) {
+    this.repoOsEntities = repoOsEntities;
+    for (RepoOsEntity repoOsEntity : repoOsEntities) {
+      repoOsEntity.setRepositoryVersionEntity(this);
+    }
+  }
 }

+ 18 - 15
ambari-server/src/main/java/org/apache/ambari/server/stack/RepoUtil.java

@@ -28,8 +28,8 @@ import javax.annotation.Nullable;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.RepositoryResponse;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.commons.collections.CollectionUtils;
@@ -66,8 +66,11 @@ public class RepoUtil {
    */
   final static String REPOSITORY_FILE_NAME = "repoinfo.xml";
 
-  private static final Function<RepositoryEntity, String> REPO_ENTITY_TO_NAME = new Function<RepositoryEntity, String>() {
-    @Override  public String apply(@Nullable RepositoryEntity input) { return input.getName(); }
+  private static final Function<RepoDefinitionEntity, String> REPO_ENTITY_TO_NAME = new Function<RepoDefinitionEntity, String>() {
+    @Override
+    public String apply(@Nullable RepoDefinitionEntity input) {
+      return input.getRepoName();
+    }
   };
 
 
@@ -117,16 +120,16 @@ public class RepoUtil {
    * @param stackReposByOs - Stack repositories loaded from the disk (including service repositories), grouped by os.
    * @return {@code true} if there were added repositories
    */
-  public static boolean addServiceReposToOperatingSystemEntities(List<OperatingSystemEntity> operatingSystems,
-      ListMultimap<String, RepositoryInfo> stackReposByOs) {
+  public static boolean addServiceReposToOperatingSystemEntities(List<RepoOsEntity> operatingSystems,
+                                                                 ListMultimap<String, RepositoryInfo> stackReposByOs) {
     Set<String> addedRepos = new HashSet<>();
-    for (OperatingSystemEntity os : operatingSystems) {
-      List<RepositoryInfo> serviceReposForOs = stackReposByOs.get(os.getOsType());
-      ImmutableSet<String> repoNames = ImmutableSet.copyOf(Lists.transform(os.getRepositories(), REPO_ENTITY_TO_NAME));
+    for (RepoOsEntity os : operatingSystems) {
+      List<RepositoryInfo> serviceReposForOs = stackReposByOs.get(os.getFamily());
+      ImmutableSet<String> repoNames = ImmutableSet.copyOf(Lists.transform(os.getRepoDefinitionEntities(), REPO_ENTITY_TO_NAME));
       for (RepositoryInfo repoInfo : serviceReposForOs)
         if (!repoNames.contains(repoInfo.getRepoName())) {
-          os.getRepositories().add(toRepositoryEntity(repoInfo));
-          addedRepos.add(String.format("%s (%s)", repoInfo.getRepoId(), os.getOsType()));
+          os.addRepoDefinition(toRepositoryEntity(repoInfo));
+          addedRepos.add(String.format("%s (%s)", repoInfo.getRepoId(), os.getFamily()));
         }
     }
     LOG.info("Added {} service repos: {}", addedRepos.size(),Iterables.toString(addedRepos));
@@ -184,11 +187,11 @@ public class RepoUtil {
     return responses;
   }
 
-  private static RepositoryEntity toRepositoryEntity(RepositoryInfo repoInfo) {
-    RepositoryEntity re = new RepositoryEntity();
+  private static RepoDefinitionEntity toRepositoryEntity(RepositoryInfo repoInfo) {
+    RepoDefinitionEntity re = new RepoDefinitionEntity();
     re.setBaseUrl(repoInfo.getBaseUrl());
-    re.setName(repoInfo.getRepoName());
-    re.setRepositoryId(repoInfo.getRepoId());
+    re.setRepoName(repoInfo.getRepoName());
+    re.setRepoID(repoInfo.getRepoId());
     re.setDistribution(repoInfo.getDistribution());
     re.setComponents(repoInfo.getComponents());
     re.setTags(repoInfo.getTags());

+ 3 - 4
ambari-server/src/main/java/org/apache/ambari/server/stack/UpdateActiveRepoVersionOnStartup.java

@@ -26,7 +26,7 @@ import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.StackId;
@@ -101,11 +101,10 @@ public class UpdateActiveRepoVersionOnStartup {
   private boolean updateRepoVersion(StackInfo stackInfo, RepositoryVersionEntity repoVersion) throws Exception {
     ListMultimap<String, RepositoryInfo> serviceReposByOs = stackInfo.getRepositoriesByOs();
 
-    // Update repos in the JSON representation
-    List<OperatingSystemEntity> operatingSystems = repoVersion.getOperatingSystems();
+    List<RepoOsEntity> operatingSystems = repoVersion.getRepoOsEntities();
     boolean changed = RepoUtil.addServiceReposToOperatingSystemEntities(operatingSystems, serviceReposByOs);
     if (changed) {
-      repoVersion.setOperatingSystems(repositoryVersionHelper.serializeOperatingSystemEntities(operatingSystems));
+      repoVersion.addRepoOsEntities(operatingSystems);
     }
     return changed;
   }

+ 54 - 101
ambari-server/src/main/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelper.java

@@ -39,8 +39,8 @@ import org.apache.ambari.server.controller.internal.OperatingSystemResourceProvi
 import org.apache.ambari.server.controller.internal.RepositoryResourceProvider;
 import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
 import org.apache.ambari.server.controller.spi.SystemException;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -160,27 +160,27 @@ public class RepositoryVersionHelper {
    * @return list of operating system entities
    * @throws Exception if any kind of json parsing error happened
    */
-  public List<OperatingSystemEntity> parseOperatingSystems(String repositoriesJson) throws Exception {
-    final List<OperatingSystemEntity> operatingSystems = new ArrayList<>();
+  public List<RepoOsEntity> parseOperatingSystems(String repositoriesJson) throws Exception {
+    final List<RepoOsEntity> operatingSystems = new ArrayList<>();
     final JsonArray rootJson = new JsonParser().parse(repositoriesJson).getAsJsonArray();
     for (JsonElement operatingSystemJson: rootJson) {
       JsonObject osObj = operatingSystemJson.getAsJsonObject();
 
-      final OperatingSystemEntity operatingSystemEntity = new OperatingSystemEntity();
+      final RepoOsEntity operatingSystemEntity = new RepoOsEntity();
 
-      operatingSystemEntity.setOsType(osObj.get(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID).getAsString());
+      operatingSystemEntity.setFamily(osObj.get(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID).getAsString());
 
       if (osObj.has(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS)) {
-        operatingSystemEntity.setAmbariManagedRepos(osObj.get(
+        operatingSystemEntity.setAmbariManaged(osObj.get(
             OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS).getAsBoolean());
       }
 
       for (JsonElement repositoryElement: osObj.get(RepositoryVersionResourceProvider.SUBRESOURCE_REPOSITORIES_PROPERTY_ID).getAsJsonArray()) {
-        final RepositoryEntity repositoryEntity = new RepositoryEntity();
+        final RepoDefinitionEntity repositoryEntity = new RepoDefinitionEntity();
         final JsonObject repositoryJson = repositoryElement.getAsJsonObject();
         repositoryEntity.setBaseUrl(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID).getAsString());
-        repositoryEntity.setName(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID).getAsString());
-        repositoryEntity.setRepositoryId(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID).getAsString());
+        repositoryEntity.setRepoName(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID).getAsString());
+        repositoryEntity.setRepoID(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID).getAsString());
         if (repositoryJson.get(RepositoryResourceProvider.REPOSITORY_DISTRIBUTION_PROPERTY_ID) != null) {
           repositoryEntity.setDistribution(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_DISTRIBUTION_PROPERTY_ID).getAsString());
         }
@@ -188,7 +188,7 @@ public class RepositoryVersionHelper {
           repositoryEntity.setComponents(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_COMPONENTS_PROPERTY_ID).getAsString());
         }
         if (repositoryJson.get(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID) != null) {
-          repositoryEntity.setMirrorsList(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID).getAsString());
+          repositoryEntity.setMirrors(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID).getAsString());
         }
         if (repositoryJson.getAsJsonObject().get(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID) != null) {
           repositoryEntity.setUnique(repositoryJson.getAsJsonObject().get(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID).getAsBoolean());
@@ -204,88 +204,43 @@ public class RepositoryVersionHelper {
           repositoryEntity.setTags(tags);
         }
 
-        operatingSystemEntity.getRepositories().add(repositoryEntity);
+        operatingSystemEntity.addRepoDefinition(repositoryEntity);
       }
       operatingSystems.add(operatingSystemEntity);
     }
     return operatingSystems;
   }
 
-  /**
-   * Serializes repository info to json for storing to DB.
-   * Produces json like:
-   * <pre>
-   * [
-   *    {
-   *       "repositories":[
-   *          {
-   *             "Repositories/base_url":"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0",
-   *             "Repositories/repo_name":"HDP-UTILS",
-   *             "Repositories/repo_id":"HDP-UTILS-1.1.0.20"
-   *          },
-   *          {
-   *             "Repositories/base_url":"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0",
-   *             "Repositories/repo_name":"HDP",
-   *             "Repositories/repo_id":"HDP-2.2"
-   *          }
-   *       ],
-   *       "OperatingSystems/os_type":"redhat6"
-   *    }
-   * ]
-   * </pre>
-   *
-   * @param repositories list of repository infos
-   * @return serialized list of operating systems
-   */
-  public String serializeOperatingSystems(List<RepositoryInfo> repositories) {
-    final JsonArray rootJson = new JsonArray();
+  public List<RepoOsEntity> createRepoOsEntities(List<RepositoryInfo> repositories) {
+
+    List<RepoOsEntity> repoOsEntities = new ArrayList<>();
     final Multimap<String, RepositoryInfo> operatingSystems = ArrayListMultimap.create();
-    for (RepositoryInfo repository: repositories) {
+    for (RepositoryInfo repository : repositories) {
       operatingSystems.put(repository.getOsType(), repository);
     }
     for (Entry<String, Collection<RepositoryInfo>> operatingSystem : operatingSystems.asMap().entrySet()) {
-      final JsonObject operatingSystemJson = new JsonObject();
-      final JsonArray repositoriesJson = new JsonArray();
+      RepoOsEntity operatingSystemEntity = new RepoOsEntity();
+      List<RepoDefinitionEntity> repositoriesList = new ArrayList<>();
       for (RepositoryInfo repository : operatingSystem.getValue()) {
-        final JsonObject repositoryJson = new JsonObject();
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID, repository.getBaseUrl());
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID, repository.getRepoName());
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID, repository.getRepoId());
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_DISTRIBUTION_PROPERTY_ID, repository.getDistribution());
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_COMPONENTS_PROPERTY_ID, repository.getComponents());
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID, repository.getMirrorsList());
-        repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID, repository.isUnique());
-
-        // add the tags even if there are none
-        JsonArray tags = gson.toJsonTree(repository.getTags()).getAsJsonArray();
-        repositoryJson.add(RepositoryResourceProvider.REPOSITORY_TAGS_PROPERTY_ID, tags);
-
-        repositoriesJson.add(repositoryJson);
-        operatingSystemJson.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS, repository.isAmbariManagedRepositories());
-      }
-      operatingSystemJson.add(RepositoryVersionResourceProvider.SUBRESOURCE_REPOSITORIES_PROPERTY_ID, repositoriesJson);
-      operatingSystemJson.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID, operatingSystem.getKey());
-      rootJson.add(operatingSystemJson);
-    }
-    return gson.toJson(rootJson);
-  }
-
-  public String serializeOperatingSystemEntities(List<OperatingSystemEntity> operatingSystems) {
-    List<RepositoryInfo> repositoryInfos = new ArrayList<>();
-    for (OperatingSystemEntity os: operatingSystems) {
-      for (RepositoryEntity repositoryEntity: os.getRepositories()) {
-        RepositoryInfo repositoryInfo = new RepositoryInfo();
-        repositoryInfo.setRepoId(repositoryEntity.getRepositoryId());
-        repositoryInfo.setRepoName(repositoryEntity.getName());
-        repositoryInfo.setDistribution(repositoryEntity.getDistribution());
-        repositoryInfo.setComponents(repositoryEntity.getComponents());
-        repositoryInfo.setBaseUrl(repositoryEntity.getBaseUrl());
-        repositoryInfo.setOsType(os.getOsType());
-        repositoryInfo.setAmbariManagedRepositories(os.isAmbariManagedRepos());
-        repositoryInfos.add(repositoryInfo);
+        RepoDefinitionEntity repositoryDefinition = new RepoDefinitionEntity();
+        repositoryDefinition.setBaseUrl(repository.getBaseUrl());
+        repositoryDefinition.setRepoName(repository.getRepoName());
+        repositoryDefinition.setRepoID(repository.getRepoId());
+        repositoryDefinition.setDistribution(repository.getDistribution());
+        repositoryDefinition.setComponents(repository.getComponents());
+        repositoryDefinition.setMirrors(repository.getMirrorsList());
+        repositoryDefinition.setUnique(repository.isUnique());
+
+        repositoryDefinition.setTags(repository.getTags());
+
+        repositoriesList.add(repositoryDefinition);
+        operatingSystemEntity.setAmbariManaged(repository.isAmbariManagedRepositories());
       }
+      operatingSystemEntity.addRepoDefinitionEntities(repositoriesList);
+      operatingSystemEntity.setFamily(operatingSystem.getKey());
+      repoOsEntities.add(operatingSystemEntity);
     }
-    return serializeOperatingSystems(repositoryInfos);
+    return repoOsEntities;
   }
 
   /**
@@ -385,14 +340,14 @@ public class RepositoryVersionHelper {
    * @param host target {@link Host} for providing repositories list
    * @param repoVersion {@link RepositoryVersionEntity} version definition with all available repositories
    *
-   * @return {@link OperatingSystemEntity} with available repositories for host
+   * @return {@link RepoOsEntity} with available repositories for host
    * @throws SystemException if no repository available for target {@link Host}
    */
-  public OperatingSystemEntity getOSEntityForHost(Host host, RepositoryVersionEntity repoVersion) throws SystemException {
+  public RepoOsEntity getOSEntityForHost(Host host, RepositoryVersionEntity repoVersion) throws SystemException {
     String osFamily = host.getOsFamily();
-    OperatingSystemEntity osEntity = null;
-    for (OperatingSystemEntity operatingSystem : repoVersion.getOperatingSystems()) {
-      if (osFamily.equals(operatingSystem.getOsType())) {
+    RepoOsEntity osEntity = null;
+    for (RepoOsEntity operatingSystem : repoVersion.getRepoOsEntities()) {
+      if (osFamily.equals(operatingSystem.getFamily())) {
         osEntity = operatingSystem;
         break;
       }
@@ -411,7 +366,7 @@ public class RepositoryVersionHelper {
    * @param osEntity      the OS family
    */
   public CommandRepository getCommandRepository(final RepositoryVersionEntity repoVersion,
-                                                final OperatingSystemEntity osEntity) throws SystemException {
+                                                final RepoOsEntity osEntity) throws SystemException {
 
     final CommandRepository commandRepo = new CommandRepository();
     final boolean sysPreppedHost = configuration.get().areHostsSysPrepped().equalsIgnoreCase("true");
@@ -420,7 +375,7 @@ public class RepositoryVersionHelper {
       throw new SystemException("Repository version entity is not provided");
     }
 
-    commandRepo.setRepositories(osEntity.getOsType(), osEntity.getRepositories());
+    commandRepo.setRepositories(osEntity.getFamily(), osEntity.getRepoDefinitionEntities());
     commandRepo.setRepositoryVersion(repoVersion.getVersion());
     commandRepo.setRepositoryVersionId(repoVersion.getId());
     commandRepo.setResolved(repoVersion.isResolved());
@@ -428,7 +383,7 @@ public class RepositoryVersionHelper {
     commandRepo.getFeature().setPreInstalled(configuration.get().areHostsSysPrepped());
     commandRepo.getFeature().setIsScoped(!sysPreppedHost);
 
-    if (!osEntity.isAmbariManagedRepos()) {
+    if (!osEntity.isAmbariManaged()) {
       commandRepo.setNonManaged();
     } else {
       if (repoVersion.isLegacy()){
@@ -464,7 +419,7 @@ public class RepositoryVersionHelper {
     throws SystemException {
 
     RepositoryVersionEntity repoVersion = getRepositoryVersionEntity(cluster, component);
-    OperatingSystemEntity osEntity = getOSEntityForHost(host, repoVersion);
+    RepoOsEntity osEntity = getOSEntityForHost(host, repoVersion);
 
     return getCommandRepository(repoVersion, osEntity);
   }
@@ -505,15 +460,13 @@ public class RepositoryVersionHelper {
     JsonArray repositories = new JsonArray();
 
     String hostOsFamily = cluster.getHost(hostName).getOsFamily();
-    for (OperatingSystemEntity operatingSystemEntity : repositoryVersion.getOperatingSystems()) {
-      // ostype in OperatingSystemEntity it's os family. That should be fixed
-      // in OperatingSystemEntity.
-      if (operatingSystemEntity.getOsType().equals(hostOsFamily)) {
-        for (RepositoryEntity repositoryEntity : operatingSystemEntity.getRepositories()) {
+    for (RepoOsEntity operatingSystemEntity : repositoryVersion.getRepoOsEntities()) {
+      if (operatingSystemEntity.getFamily().equals(hostOsFamily)) {
+        for (RepoDefinitionEntity repositoryEntity : operatingSystemEntity.getRepoDefinitionEntities()) {
           JsonObject repositoryInfo = new JsonObject();
           repositoryInfo.addProperty("base_url", repositoryEntity.getBaseUrl());
-          repositoryInfo.addProperty("repo_name", repositoryEntity.getName());
-          repositoryInfo.addProperty("repo_id", repositoryEntity.getRepositoryId());
+          repositoryInfo.addProperty("repo_name", repositoryEntity.getRepoName());
+          repositoryInfo.addProperty("repo_id", repositoryEntity.getRepoID());
 
           repositories.add(repositoryInfo);
         }
@@ -558,10 +511,10 @@ public class RepositoryVersionHelper {
         continue;
       }
 
-      for (OperatingSystemEntity ose : rve.getOperatingSystems()) {
-        if (ose.getOsType().equals(osType) && ose.isAmbariManagedRepos()) {
-          for (RepositoryEntity re : ose.getRepositories()) {
-            if (re.getName().equals(repoName) &&
+      for (RepoOsEntity ose : rve.getRepoOsEntities()) {
+        if (ose.getFamily().equals(osType) && ose.isAmbariManaged()) {
+          for (RepoDefinitionEntity re : ose.getRepoDefinitionEntities()) {
+            if (re.getRepoName().equals(repoName) &&
               !re.getBaseUrl().equals(baseUrl)) {
               obj.addProperty("baseUrl", re.getBaseUrl());
             }
@@ -630,7 +583,7 @@ public class RepositoryVersionHelper {
    * @param osEntity      the OS family
    */
   public void addCommandRepositoryToContext(ActionExecutionContext context,
-                                            OperatingSystemEntity osEntity) throws SystemException {
+                                            RepoOsEntity osEntity) throws SystemException {
 
     final RepositoryVersionEntity repoVersion = context.getRepositoryVersion();
     final CommandRepository commandRepo = getCommandRepository(repoVersion, osEntity);

+ 1 - 1
ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java

@@ -1441,7 +1441,7 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
         stackEntity,
         version,
         stackId.getStackName() + "-" + version,
-        repositoryVersionHelper.serializeOperatingSystems(stackInfo.getRepositories()));
+        repositoryVersionHelper.createRepoOsEntities(stackInfo.getRepositories()));
   }
 
   /**

+ 29 - 1
ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql

@@ -158,7 +158,6 @@ CREATE TABLE repo_version (
   stack_id BIGINT NOT NULL,
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
-  repositories VARCHAR(3000) NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   hidden SMALLINT NOT NULL DEFAULT 0,
   resolved SMALLINT NOT NULL DEFAULT 0,
@@ -172,6 +171,31 @@ CREATE TABLE repo_version (
   CONSTRAINT UQ_repo_version_display_name UNIQUE (display_name),
   CONSTRAINT UQ_repo_version_stack_id UNIQUE (stack_id, version));
 
+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));
+
+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));
+
+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));
 
 CREATE TABLE servicecomponentdesiredstate (
   id BIGINT NOT NULL,
@@ -1143,6 +1167,10 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value)
   union all
   select 'repo_version_id_seq', 0 FROM SYSIBM.SYSDUMMY1
   union all
+  select 'repo_os_id_seq', 0 FROM SYSIBM.SYSDUMMY1
+  union all
+  select 'repo_definition_id_seq', 0 FROM SYSIBM.SYSDUMMY1
+  union all
   select 'host_version_id_seq', 0 FROM SYSIBM.SYSDUMMY1
   union all
   select 'service_config_id_seq', 1 FROM SYSIBM.SYSDUMMY1

+ 27 - 1
ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql

@@ -178,7 +178,6 @@ CREATE TABLE repo_version (
   stack_id BIGINT NOT NULL,
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
-  repositories MEDIUMTEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   hidden SMALLINT NOT NULL DEFAULT 0,
   resolved TINYINT(1) NOT NULL DEFAULT 0,
@@ -192,6 +191,31 @@ CREATE TABLE repo_version (
   CONSTRAINT UQ_repo_version_display_name UNIQUE (display_name),
   CONSTRAINT UQ_repo_version_stack_id UNIQUE (stack_id, version));
 
+CREATE TABLE repo_os (
+  id BIGINT NOT NULL,
+  repo_version_id BIGINT NOT NULL,
+  family VARCHAR(255) NOT NULL DEFAULT '',
+  ambari_managed TINYINT(1) 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));
+
+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 MEDIUMTEXT NOT NULL,
+  distribution MEDIUMTEXT,
+  components MEDIUMTEXT,
+  unique_repo TINYINT(1) DEFAULT 1,
+  mirrors MEDIUMTEXT,
+  CONSTRAINT PK_repo_definition_id PRIMARY KEY (id),
+  CONSTRAINT FK_repo_definition_repo_os_id FOREIGN KEY (repo_os_id) REFERENCES repo_os (id));
+
+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));
 
 CREATE TABLE servicecomponentdesiredstate (
   id BIGINT NOT NULL,
@@ -1134,6 +1158,8 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) VALUES
   ('alert_notice_id_seq', 0),
   ('alert_current_id_seq', 0),
   ('repo_version_id_seq', 0),
+  ('repo_os_id_seq', 0),
+  ('repo_definition_id_seq', 0),
   ('upgrade_id_seq', 0),
   ('upgrade_group_id_seq', 0),
   ('upgrade_item_id_seq', 0),

+ 27 - 1
ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql

@@ -159,7 +159,6 @@ CREATE TABLE repo_version (
   stack_id NUMBER(19) NOT NULL,
   version VARCHAR2(255) NOT NULL,
   display_name VARCHAR2(128) NOT NULL,
-  repositories CLOB NOT NULL,
   repo_type VARCHAR2(255) DEFAULT 'STANDARD' NOT NULL,
   hidden NUMBER(1) DEFAULT 0 NOT NULL,
   resolved NUMBER(1) DEFAULT 0 NOT NULL,
@@ -173,6 +172,31 @@ CREATE TABLE repo_version (
   CONSTRAINT UQ_repo_version_display_name UNIQUE (display_name),
   CONSTRAINT UQ_repo_version_stack_id UNIQUE (stack_id, version));
 
+CREATE TABLE repo_os (
+  id NUMBER(19) NOT NULL,
+  repo_version_id NUMBER(19) NOT NULL,
+  family VARCHAR(255) DEFAULT '' NOT NULL,
+  ambari_managed NUMBER(1) 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));
+
+CREATE TABLE repo_definition (
+  id NUMBER(19) NOT NULL,
+  repo_os_id NUMBER(19),
+  repo_name VARCHAR(255) NOT NULL,
+  repo_id VARCHAR(255) NOT NULL,
+  base_url CLOB NOT NULL,
+  distribution CLOB,
+  components CLOB,
+  unique_repo NUMBER(1) DEFAULT 1,
+  mirrors CLOB,
+  CONSTRAINT PK_repo_definition_id PRIMARY KEY (id),
+  CONSTRAINT FK_repo_definition_repo_os_id FOREIGN KEY (repo_os_id) REFERENCES repo_os (id));
+
+CREATE TABLE repo_tags (
+  repo_definition_id NUMBER(19) NOT NULL,
+  tag VARCHAR(255) NOT NULL,
+  CONSTRAINT FK_repo_tag_definition_id FOREIGN KEY (repo_definition_id) REFERENCES repo_definition (id));
 
 CREATE TABLE servicecomponentdesiredstate (
   id NUMBER(19) NOT NULL,
@@ -1113,6 +1137,8 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('alert_histo
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('alert_notice_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('alert_current_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('repo_version_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('repo_os_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('repo_definition_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_group_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_item_id_seq', 0);

+ 28 - 1
ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql

@@ -160,7 +160,6 @@ CREATE TABLE repo_version (
   stack_id BIGINT NOT NULL,
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
-  repositories TEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   hidden SMALLINT NOT NULL DEFAULT 0,
   version_url VARCHAR(1024),
@@ -174,6 +173,32 @@ CREATE TABLE repo_version (
   CONSTRAINT UQ_repo_version_display_name UNIQUE (display_name),
   CONSTRAINT UQ_repo_version_stack_id UNIQUE (stack_id, version));
 
+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));
+
+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));
+
+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));
+
 CREATE TABLE servicecomponentdesiredstate (
   id BIGINT NOT NULL,
   component_name VARCHAR(255) NOT NULL,
@@ -1139,6 +1164,8 @@ INSERT INTO ambari_sequences (sequence_name, sequence_value) VALUES
   ('remote_cluster_id_seq', 0),
   ('remote_cluster_service_id_seq', 0),
   ('servicecomponent_version_id_seq', 0),
+  ('repo_os_id_seq', 0),
+  ('repo_definition_id_seq', 0),
   ('hostcomponentdesiredstate_id_seq', 0);
 
 INSERT INTO adminresourcetype (resource_type_id, resource_type_name) VALUES

+ 28 - 1
ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql

@@ -157,7 +157,6 @@ CREATE TABLE repo_version (
   stack_id NUMERIC(19) NOT NULL,
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
-  repositories TEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   hidden SMALLINT NOT NULL DEFAULT 0,
   resolved BIT NOT NULL DEFAULT 0,
@@ -171,6 +170,32 @@ CREATE TABLE repo_version (
   CONSTRAINT UQ_repo_version_display_name UNIQUE (display_name),
   CONSTRAINT UQ_repo_version_stack_id UNIQUE (stack_id, version));
 
+CREATE TABLE repo_os (
+  id NUMERIC(19) NOT NULL,
+  repo_version_id NUMERIC(19) 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));
+
+CREATE TABLE repo_definition (
+  id NUMERIC(19) NOT NULL,
+  repo_os_id NUMERIC(19),
+  repo_name VARCHAR(255) NOT NULL,
+  repo_id VARCHAR(255) NOT NULL,
+  base_url TEXT NOT NULL,
+  distribution TEXT,
+  components TEXT,
+  unique_repo SMALLINT DEFAULT 1,
+  mirrors TEXT,
+  CONSTRAINT PK_repo_definition_id PRIMARY KEY (id),
+  CONSTRAINT FK_repo_definition_repo_os_id FOREIGN KEY (repo_os_id) REFERENCES repo_os (id));
+
+CREATE TABLE repo_tags (
+  repo_definition_id NUMERIC(19) NOT NULL,
+  tag VARCHAR(255) NOT NULL,
+  CONSTRAINT FK_repo_tag_definition_id FOREIGN KEY (repo_definition_id) REFERENCES repo_definition (id));
+
 CREATE TABLE servicecomponentdesiredstate (
   id NUMERIC(19) NOT NULL,
   component_name VARCHAR(255) NOT NULL,
@@ -1111,6 +1136,8 @@ INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('alert_histo
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('alert_notice_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('alert_current_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('repo_version_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('repo_os_id_seq', 0);
+INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('repo_definition_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_group_id_seq', 0);
 INSERT INTO ambari_sequences(sequence_name, sequence_value) values ('upgrade_item_id_seq', 0);

+ 28 - 1
ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql

@@ -172,7 +172,6 @@ CREATE TABLE repo_version (
   stack_id BIGINT NOT NULL,
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
-  repositories VARCHAR(MAX) NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
   hidden SMALLINT NOT NULL DEFAULT 0,
   resolved BIT NOT NULL DEFAULT 0,
@@ -186,6 +185,32 @@ CREATE TABLE repo_version (
   CONSTRAINT UQ_repo_version_display_name UNIQUE (display_name),
   CONSTRAINT UQ_repo_version_stack_id UNIQUE (stack_id, version));
 
+CREATE TABLE repo_os (
+  id BIGINT NOT NULL,
+  repo_version_id BIGINT NOT NULL,
+  family VARCHAR(255) NOT NULL DEFAULT '',
+  ambari_managed BIT 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));
+
+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(MAX) NOT NULL,
+  distribution VARCHAR(MAX),
+  components VARCHAR(MAX),
+  unique_repo BIT DEFAULT 1,
+  mirrors VARCHAR(MAX),
+  CONSTRAINT PK_repo_definition_id PRIMARY KEY (id),
+  CONSTRAINT FK_repo_definition_repo_os_id FOREIGN KEY (repo_os_id) REFERENCES repo_os (id));
+
+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));
+
 CREATE TABLE servicecomponentdesiredstate (
   id BIGINT NOT NULL,
   component_name VARCHAR(255) NOT NULL,
@@ -1136,6 +1161,8 @@ BEGIN TRANSACTION
     ('alert_current_id_seq', 0),
     ('config_id_seq', 11),
     ('repo_version_id_seq', 0),
+    ('repo_os_id_seq', 0),
+    ('repo_definition_id_seq', 0),
     ('host_version_id_seq', 0),
     ('service_config_id_seq', 1),
     ('upgrade_id_seq', 0),

+ 2 - 0
ambari-server/src/main/resources/META-INF/persistence.xml

@@ -57,6 +57,8 @@
     <class>org.apache.ambari.server.orm.entities.PrincipalTypeEntity</class>
     <class>org.apache.ambari.server.orm.entities.PrivilegeEntity</class>
     <class>org.apache.ambari.server.orm.entities.RepositoryVersionEntity</class>
+    <class>org.apache.ambari.server.orm.entities.RepoOsEntity</class>
+    <class>org.apache.ambari.server.orm.entities.RepoDefinitionEntity</class>
     <class>org.apache.ambari.server.orm.entities.RequestEntity</class>
     <class>org.apache.ambari.server.orm.entities.RequestOperationLevelEntity</class>
     <class>org.apache.ambari.server.orm.entities.RequestResourceFilterEntity</class>

+ 1 - 1
ambari-server/src/test/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapperTest.java

@@ -365,7 +365,7 @@ public class ExecutionCommandWrapperTest {
     Service service = cluster.getService("HDFS");
     service.setDesiredRepositoryVersion(repositoryVersion);
 
-    repositoryVersion.setOperatingSystems("[]");
+    repositoryVersion.addRepoOsEntities(new ArrayList<>());
 
     ormTestHelper.repositoryVersionDAO.merge(repositoryVersion);
 

+ 7 - 1
ambari-server/src/test/java/org/apache/ambari/server/checks/InstallPackagesCheckTest.java

@@ -27,6 +27,7 @@ import org.apache.ambari.server.controller.PrereqCheckRequest;
 import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.models.HostComponentSummary;
@@ -128,7 +129,12 @@ public class InstallPackagesCheckTest {
     StackEntity stack = new StackEntity();
     stack.setStackName(stackId.getStackName());
     stack.setStackVersion(stackId.getStackVersion());
-    RepositoryVersionEntity rve = new RepositoryVersionEntity(stack, repositoryVersion, repositoryVersion, "rhel6");
+    List<RepoOsEntity> osEntities = new ArrayList<>();
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("rhel6");
+    repoOsEntity.setAmbariManaged(true);
+    osEntities.add(repoOsEntity);
+    RepositoryVersionEntity rve = new RepositoryVersionEntity(stack, repositoryVersion, repositoryVersion, osEntities);
     Mockito.when(repositoryVersionDAO.findByStackNameAndVersion(Mockito.anyString(), Mockito.anyString())).thenReturn(rve);
     final Cluster cluster = Mockito.mock(Cluster.class);
     Mockito.when(cluster.getClusterName()).thenReturn(clusterName);

+ 12 - 7
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java

@@ -52,6 +52,8 @@ import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.ServiceComponentDesiredStateDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity;
@@ -66,7 +68,6 @@ import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostState;
 import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.PropertyInfo;
-import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.SecurityType;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
@@ -630,12 +631,16 @@ public class AmbariCustomCommandExecutionHelperTest {
     Assert.assertEquals(2, commandRepo.getRepositories().size());
 
 
-    RepositoryInfo ri = new RepositoryInfo();
-    ri.setBaseUrl("http://foo");
-    ri.setRepoName("HDP");
-    ri.setRepoId("new-id");
-    ri.setOsType("redhat6");
-    String operatingSystems = repoVersionHelper.serializeOperatingSystems(Collections.singletonList(ri));
+    List<RepoOsEntity> operatingSystems = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("new-id");
+    repoDefinitionEntity1.setBaseUrl("http://foo");
+    repoDefinitionEntity1.setRepoName("HDP");
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    operatingSystems.add(repoOsEntity);
 
     StackEntity stackEntity = stackDAO.find(cluster.getDesiredStackVersion().getStackName(),
         cluster.getDesiredStackVersion().getStackVersion());

+ 1 - 1
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java

@@ -7066,7 +7066,7 @@ public class AmbariManagementControllerTest {
     StackEntity stackEntity = stackDAO.find(STACK_NAME, STACK_VERSION);
     assertNotNull(stackEntity);
 
-    RepositoryVersionEntity versionEntity = dao.create(stackEntity, "0.2.2", "HDP-0.2", ClusterStackVersionResourceProviderTest.OS_JSON);
+    RepositoryVersionEntity versionEntity = dao.create(stackEntity, "0.2.2", "HDP-0.2", ClusterStackVersionResourceProviderTest.REPO_OS_ENTITIES);
 
     OperatingSystemRequest request = new OperatingSystemRequest(STACK_NAME, STACK_VERSION, null);
     Set<OperatingSystemResponse> responses = controller.getOperatingSystems(Collections.singleton(request));

+ 63 - 58
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java

@@ -78,6 +78,8 @@ import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
+ import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+ import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
@@ -120,9 +122,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -151,23 +150,43 @@ public class ClusterStackVersionResourceProviderTest {
   private ActionManager actionManager;
   private AmbariManagementController managementController;
 
-  public static final String OS_JSON = "[\n" +
-          "   {\n" +
-          "      \"repositories\":[\n" +
-          "         {\n" +
-          "            \"Repositories/base_url\":\"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0\",\n" +
-          "            \"Repositories/repo_name\":\"HDP-UTILS\",\n" +
-          "            \"Repositories/repo_id\":\"HDP-UTILS-1.1.0.20\"\n" +
-          "         },\n" +
-          "         {\n" +
-          "            \"Repositories/base_url\":\"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0\",\n" +
-          "            \"Repositories/repo_name\":\"HDP\",\n" +
-          "            \"Repositories/repo_id\":\"HDP-2.2\"\n" +
-          "         }\n" +
-          "      ],\n" +
-          "      \"OperatingSystems/os_type\":\"redhat6\"\n" +
-          "   }\n" +
-          "]";
+   public static final List<RepoOsEntity> REPO_OS_ENTITIES = new ArrayList<>();
+
+   static {
+     RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+     repoDefinitionEntity1.setRepoID("HDP-UTILS-1.1.0.20");
+     repoDefinitionEntity1.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0");
+     repoDefinitionEntity1.setRepoName("HDP-UTILS");
+     RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+     repoDefinitionEntity2.setRepoID("HDP-2.2");
+     repoDefinitionEntity2.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0");
+     repoDefinitionEntity2.setRepoName("HDP");
+     RepoOsEntity repoOsEntity = new RepoOsEntity();
+     repoOsEntity.setFamily("redhat6");
+     repoOsEntity.setAmbariManaged(true);
+     repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+     repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+     REPO_OS_ENTITIES.add(repoOsEntity);
+   }
+
+   public static final List<RepoOsEntity> REPO_OS_NOT_MANAGED = new ArrayList<>();
+
+   static {
+     RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+     repoDefinitionEntity1.setRepoID("HDP-UTILS-1.1.0.20");
+     repoDefinitionEntity1.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0");
+     repoDefinitionEntity1.setRepoName("HDP-UTILS");
+     RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+     repoDefinitionEntity2.setRepoID("HDP-2.2");
+     repoDefinitionEntity2.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0");
+     repoDefinitionEntity2.setRepoName("HDP");
+     RepoOsEntity repoOsEntity = new RepoOsEntity();
+     repoOsEntity.setFamily("redhat6");
+     repoOsEntity.setAmbariManaged(false);
+     repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+     repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+     REPO_OS_NOT_MANAGED.add(repoOsEntity);
+   }
 
   @Before
   public void setup() throws Exception {
@@ -227,7 +246,7 @@ public class ClusterStackVersionResourceProviderTest {
 
     RepositoryVersionEntity repoVersion = new RepositoryVersionEntity();
     repoVersion.setId(1l);
-    repoVersion.setOperatingSystems(OS_JSON);
+    repoVersion.addRepoOsEntities(REPO_OS_ENTITIES);
     repoVersion.setStack(stackEntity);
 
     final String hostWithoutVersionableComponents = "host2";
@@ -398,7 +417,7 @@ public class ClusterStackVersionResourceProviderTest {
 
     RepositoryVersionEntity repoVersion = new RepositoryVersionEntity();
     repoVersion.setId(1l);
-    repoVersion.setOperatingSystems(OS_JSON);
+    repoVersion.addRepoOsEntities(REPO_OS_ENTITIES);
     repoVersion.setVersionXml(IOUtils.toString(new FileInputStream(f)));
     repoVersion.setVersionXsd("version_definition.xsd");
     repoVersion.setType(RepositoryType.PATCH);
@@ -613,7 +632,7 @@ public class ClusterStackVersionResourceProviderTest {
 
     RepositoryVersionEntity repoVersion = new RepositoryVersionEntity();
     repoVersion.setId(1l);
-    repoVersion.setOperatingSystems(OS_JSON);
+     repoVersion.addRepoOsEntities(REPO_OS_ENTITIES);
     repoVersion.setVersionXml(IOUtils.toString(new FileInputStream(f)));
     repoVersion.setVersionXsd("version_definition.xsd");
     repoVersion.setType(RepositoryType.STANDARD);
@@ -831,12 +850,6 @@ public class ClusterStackVersionResourceProviderTest {
    }
 
    private void testCreateResourcesWithNonManagedOS(Authentication authentication) throws Exception {
-    JsonArray json = new JsonParser().parse(OS_JSON).getAsJsonArray();
-
-    JsonObject jsonObj = json.get(0).getAsJsonObject();
-    jsonObj.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS, false);
-
-    String os_json = json.toString();
 
     Cluster cluster = createNiceMock(Cluster.class);
     StackId stackId = new StackId("HDP", "2.0.1");
@@ -849,7 +862,7 @@ public class ClusterStackVersionResourceProviderTest {
 
     RepositoryVersionEntity repoVersion = new RepositoryVersionEntity();
     repoVersion.setId(1l);
-    repoVersion.setOperatingSystems(os_json);
+     repoVersion.addRepoOsEntities(REPO_OS_NOT_MANAGED);
     repoVersion.setVersionXml(IOUtils.toString(new FileInputStream(f)));
     repoVersion.setVersionXsd("version_definition.xsd");
     repoVersion.setType(RepositoryType.STANDARD);
@@ -1076,7 +1089,7 @@ public class ClusterStackVersionResourceProviderTest {
     RepositoryVersionEntity repoVersion = new RepositoryVersionEntity();
     repoVersion.setStack(stack);
     repoVersion.setId(1l);
-    repoVersion.setOperatingSystems(OS_JSON);
+     repoVersion.addRepoOsEntities(REPO_OS_ENTITIES);
     repoVersion.setVersionXml(xml);
     repoVersion.setVersionXsd("version_definition.xsd");
     repoVersion.setType(RepositoryType.STANDARD);
@@ -1285,7 +1298,7 @@ public class ClusterStackVersionResourceProviderTest {
 
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setId(1l);
-    repoVersionEntity.setOperatingSystems(OS_JSON);
+    repoVersionEntity.addRepoOsEntities(REPO_OS_ENTITIES);
     repoVersionEntity.setVersionXml(IOUtils.toString(new FileInputStream(f)));
     repoVersionEntity.setVersionXsd("version_definition.xsd");
     repoVersionEntity.setType(RepositoryType.STANDARD);
@@ -1449,24 +1462,22 @@ public class ClusterStackVersionResourceProviderTest {
     expect(repoVersion.getStackName()).andReturn("HDP").anyTimes();
 
 
-    String os_json = "[\n" +
-        "   {\n" +
-        "      \"repositories\":[\n" +
-        "         {\n" +
-        "            \"Repositories/base_url\":\"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos-ppc7/2.x/updates/2.2.0.0\",\n" +
-        "            \"Repositories/repo_name\":\"HDP-UTILS\",\n" +
-        "            \"Repositories/repo_id\":\"HDP-UTILS-1.1.0.20\"\n" +
-        "         },\n" +
-        "         {\n" +
-        "            \"Repositories/base_url\":\"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos-ppc7/2.x/updates/2.2.0.0\",\n" +
-        "            \"Repositories/repo_name\":\"HDP\",\n" +
-        "            \"Repositories/repo_id\":\"HDP-2.2\"\n" +
-        "         }\n" +
-        "      ],\n" +
-        "      \"OperatingSystems/os_type\":\"redhat-ppc7\"\n" +
-        "   }\n" +
-        "]";
-    expect(repoVersion.getOperatingSystems()).andReturn(rvh.parseOperatingSystems(os_json)).anyTimes();
+    List<RepoOsEntity> oss = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("HDP-UTILS-1.1.0.20");
+    repoDefinitionEntity1.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos-ppc7/2.x/updates/2.2.0.0");
+    repoDefinitionEntity1.setRepoName("HDP-UTILS");
+    RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+    repoDefinitionEntity2.setRepoID("HDP-2.2");
+    repoDefinitionEntity2.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos-ppc7/2.x/updates/2.2.0.0");
+    repoDefinitionEntity2.setRepoName("HDP");
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat-ppc7");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+    oss.add(repoOsEntity);
+    expect(repoVersion.getRepoOsEntities()).andReturn(oss).anyTimes();
     expect(repoVersion.getType()).andReturn(RepositoryType.STANDARD).anyTimes();
 
     Map<String, Host> hostsForCluster = new HashMap<>();
@@ -1883,12 +1894,6 @@ public class ClusterStackVersionResourceProviderTest {
 
    @Test
    public void testCreateResourcesPatch() throws Exception {
-     JsonArray json = new JsonParser().parse(OS_JSON).getAsJsonArray();
-
-     JsonObject jsonObj = json.get(0).getAsJsonObject();
-     jsonObj.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS, false);
-
-     String os_json = json.toString();
 
      Cluster cluster = createNiceMock(Cluster.class);
      StackId stackId = new StackId("HDP", "2.0.1");
@@ -1899,7 +1904,7 @@ public class ClusterStackVersionResourceProviderTest {
 
      RepositoryVersionEntity fromRepo = new RepositoryVersionEntity();
      fromRepo.setId(0L);
-     fromRepo.setOperatingSystems(os_json);
+     fromRepo.addRepoOsEntities(REPO_OS_NOT_MANAGED);
      fromRepo.setVersionXsd("version_definition.xsd");
      fromRepo.setType(RepositoryType.STANDARD);
      fromRepo.setStack(fromStack);
@@ -1963,7 +1968,7 @@ public class ClusterStackVersionResourceProviderTest {
 
      RepositoryVersionEntity repoVersion = new RepositoryVersionEntity();
      repoVersion.setId(1l);
-     repoVersion.setOperatingSystems(os_json);
+     repoVersion.addRepoOsEntities(REPO_OS_NOT_MANAGED);
      repoVersion.setVersionXml(xmlString);
      repoVersion.setVersionXsd("version_definition.xsd");
      repoVersion.setType(RepositoryType.PATCH);

+ 11 - 3
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/CompatibleRepositoryVersionResourceProviderTest.java

@@ -50,6 +50,7 @@ import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
@@ -76,7 +77,14 @@ public class CompatibleRepositoryVersionResourceProviderTest {
 
   private static Injector injector;
 
-  private static String jsonStringRedhat6 = "[{\"OperatingSystems\":{\"os_type\":\"redhat6\"},\"repositories\":[]}]";
+  private static final List<RepoOsEntity> osRedhat6 = new ArrayList<>();
+
+  {
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    osRedhat6.add(repoOsEntity);
+  }
   private static StackId stackId11 = new StackId("HDP", "1.1");
   private static StackId stackId22 = new StackId("HDP", "2.2");
 
@@ -90,7 +98,7 @@ public class CompatibleRepositoryVersionResourceProviderTest {
 
     RepositoryVersionEntity entity1 = new RepositoryVersionEntity();
     entity1.setDisplayName("name1");
-    entity1.setOperatingSystems(jsonStringRedhat6);
+    entity1.addRepoOsEntities(osRedhat6);
     entity1.setStack(hdp11Stack);
     entity1.setVersion("1.1.1.1");
     entity1.setId(1L);
@@ -101,7 +109,7 @@ public class CompatibleRepositoryVersionResourceProviderTest {
 
     RepositoryVersionEntity entity2 = new ExtendedRepositoryVersionEntity();
     entity2.setDisplayName("name2");
-    entity2.setOperatingSystems(jsonStringRedhat6);
+    entity2.addRepoOsEntities(osRedhat6);
     entity2.setStack(hdp22Stack);
     entity2.setVersion("2.2.2.2");
     entity2.setId(2L);

+ 22 - 18
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostStackVersionResourceProviderTest.java

@@ -32,6 +32,7 @@ import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -62,6 +63,8 @@ import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.state.Cluster;
@@ -110,23 +113,24 @@ public class HostStackVersionResourceProviderTest {
   private RepositoryVersionEntity repoVersion;
   private Resource.Type type = Resource.Type.HostStackVersion;
 
-  private String operatingSystemsJson = "[\n" +
-          "   {\n" +
-          "      \"repositories\":[\n" +
-          "         {\n" +
-          "            \"Repositories/base_url\":\"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0\",\n" +
-          "            \"Repositories/repo_name\":\"HDP-UTILS\",\n" +
-          "            \"Repositories/repo_id\":\"HDP-UTILS-1.1.0.20\"\n" +
-          "         },\n" +
-          "         {\n" +
-          "            \"Repositories/base_url\":\"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0\",\n" +
-          "            \"Repositories/repo_name\":\"HDP\",\n" +
-          "            \"Repositories/repo_id\":\"HDP-2.2\"\n" +
-          "         }\n" +
-          "      ],\n" +
-          "      \"OperatingSystems/os_type\":\"redhat6\"\n" +
-          "   }\n" +
-          "]";
+  private List<RepoOsEntity> operatingSystemsEn = new ArrayList<>();
+
+  {
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("HDP-UTILS-1.1.0.20");
+    repoDefinitionEntity1.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0");
+    repoDefinitionEntity1.setRepoName("HDP-UTILS");
+    RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+    repoDefinitionEntity2.setRepoID("HDP-2.2");
+    repoDefinitionEntity2.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0");
+    repoDefinitionEntity2.setRepoName("HDP");
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+    operatingSystemsEn.add(repoOsEntity);
+  }
 
   @Before
   public void setup() throws Exception {
@@ -148,7 +152,7 @@ public class HostStackVersionResourceProviderTest {
     hostVersionEntityMock = createNiceMock(HostVersionEntity.class);
     actionManager = createNiceMock(ActionManager.class);
     repoVersion = new RepositoryVersionEntity();
-    repoVersion.setOperatingSystems(operatingSystemsJson);
+    repoVersion.addRepoOsEntities(operatingSystemsEn);
 
     StackEntity stack = new StackEntity();
     stack.setStackName("HDP");

+ 48 - 30
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java

@@ -19,6 +19,7 @@
 package org.apache.ambari.server.controller.internal;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -41,8 +42,8 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
@@ -76,8 +77,16 @@ public class RepositoryVersionResourceProviderTest {
 
   private static Injector injector;
 
-  private static String jsonStringRedhat6 = "[{\"OperatingSystems\":{\"os_type\":\"redhat6\"},\"repositories\":[]}]";
-  private static String jsonStringRedhat7 = "[{\"OperatingSystems\":{\"os_type\":\"redhat7\"},\"repositories\":[]}]";
+  public static final List<RepoOsEntity> osRedhat6 = new ArrayList<>();
+
+  static {
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    osRedhat6.add(repoOsEntity);
+  }
+
+  public static final List<RepoOsEntity> osRedhat7 = new ArrayList<>();
 
   @Before
   public void before() throws Exception {
@@ -250,7 +259,7 @@ public class RepositoryVersionResourceProviderTest {
     final RepositoryVersionDAO repositoryVersionDAO = injector.getInstance(RepositoryVersionDAO.class);
     final RepositoryVersionEntity entity = new RepositoryVersionEntity();
     entity.setDisplayName("name");
-    entity.setOperatingSystems(jsonStringRedhat6);
+    entity.addRepoOsEntities(osRedhat6);
     entity.setStack(stackEntity);
     entity.setVersion("1.1.1.1");
 
@@ -276,7 +285,21 @@ public class RepositoryVersionResourceProviderTest {
     entity.setDisplayName("name");
     entity.setStack(stackEntity);
     entity.setVersion("1.1");
-    entity.setOperatingSystems("[{\"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\",\"Repositories/unique\":\"true\"}]}]");
+
+
+    List<RepoOsEntity> osEntities = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("1");
+    repoDefinitionEntity1.setBaseUrl("http://example.com/repo1");
+    repoDefinitionEntity1.setRepoName("1");
+    repoDefinitionEntity1.setUnique(true);
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    osEntities.add(repoOsEntity);
+
+    entity.addRepoOsEntities(osEntities);
 
     final RepositoryVersionDAO repositoryVersionDAO = injector.getInstance(RepositoryVersionDAO.class);
     AmbariMetaInfo info = injector.getInstance(AmbariMetaInfo.class);
@@ -293,14 +316,8 @@ public class RepositoryVersionResourceProviderTest {
     RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity);
 
     // test invalid usecases
-    entity.setOperatingSystems(jsonStringRedhat7);
-    try {
-      RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity);
-      Assert.fail("Should throw exception");
-    } catch (Exception ex) {
-    }
 
-    entity.setOperatingSystems("");
+    entity.addRepoOsEntities(new ArrayList<>());
     try {
       RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity);
       Assert.fail("Should throw exception");
@@ -320,7 +337,7 @@ public class RepositoryVersionResourceProviderTest {
     entity.setDisplayName("name");
     entity.setStack(stackEntity);
     entity.setVersion("1.1");
-    entity.setOperatingSystems("[{\"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\",\"Repositories/unique\":\"true\"}]}]");
+    entity.addRepoOsEntities(osEntities);
     repositoryVersionDAO.create(entity);
 
     final RepositoryVersionEntity entity2 = new RepositoryVersionEntity();
@@ -328,7 +345,7 @@ public class RepositoryVersionResourceProviderTest {
     entity2.setDisplayName("name2");
     entity2.setStack(stackEntity);
     entity2.setVersion("1.2");
-    entity2.setOperatingSystems("[{\"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\",\"Repositories/unique\":\"true\"}]}]");
+    entity2.addRepoOsEntities(osEntities);
 
     try {
       RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity2);
@@ -341,7 +358,7 @@ public class RepositoryVersionResourceProviderTest {
     entity3.setDisplayName("name2");
     entity3.setStack(stackEntity);
     entity3.setVersion("1.1");
-    entity3.setOperatingSystems("[{\"OperatingSystems/ambari_managed_repositories\": true, \"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\",\"Repositories/unique\":\"true\"}]}]");
+    entity3.addRepoOsEntities(osEntities);
 
     try {
       RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity3);
@@ -350,7 +367,8 @@ public class RepositoryVersionResourceProviderTest {
       // expected
     }
 
-    entity3.setOperatingSystems("[{\"OperatingSystems/ambari_managed_repositories\": false, \"OperatingSystems/os_type\":\"redhat6\",\"repositories\":[{\"Repositories/repo_id\":\"1\",\"Repositories/repo_name\":\"1\",\"Repositories/base_url\":\"http://example.com/repo1\",\"Repositories/unique\":\"true\"}]}]");
+    entity3.addRepoOsEntities(osEntities);
+    repoOsEntity.setAmbariManaged(false);
     RepositoryVersionResourceProvider.validateRepositoryVersion(repositoryVersionDAO, info, entity3);
 
   }
@@ -446,12 +464,12 @@ public class RepositoryVersionResourceProviderTest {
     Gson gson = new Gson();
     String operatingSystemsJson = gson.toJson(operatingSystems);
     RepositoryVersionHelper repositoryVersionHelper = new RepositoryVersionHelper();
-    List<OperatingSystemEntity> operatingSystemEntities = repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
-    for (OperatingSystemEntity operatingSystemEntity : operatingSystemEntities) {
-      String osType = operatingSystemEntity.getOsType();
-      List<RepositoryEntity> repositories = operatingSystemEntity.getRepositories();
-      for (RepositoryEntity repository : repositories) {
-        RepositoryInfo repo = ambariMetaInfo.getRepository(stackName, stackVersion, osType, repository.getRepositoryId());
+    List<RepoOsEntity> operatingSystemEntities = repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
+    for (RepoOsEntity operatingSystemEntity : operatingSystemEntities) {
+      String osType = operatingSystemEntity.getFamily();
+      List<RepoDefinitionEntity> repositories = operatingSystemEntity.getRepoDefinitionEntities();
+      for (RepoDefinitionEntity repository : repositories) {
+        RepositoryInfo repo = ambariMetaInfo.getRepository(stackName, stackVersion, osType, repository.getRepoID());
         if (repo != null) {
           String baseUrlActual = repo.getBaseUrl();
           String baseUrlExpected = repository.getBaseUrl();
@@ -515,13 +533,13 @@ public class RepositoryVersionResourceProviderTest {
     Gson gson = new Gson();
     String operatingSystemsJson = gson.toJson(operatingSystems);
     RepositoryVersionHelper repositoryVersionHelper = new RepositoryVersionHelper();
-    List<OperatingSystemEntity> operatingSystemEntities = repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
-    for (OperatingSystemEntity operatingSystemEntity : operatingSystemEntities) {
-      Assert.assertFalse(operatingSystemEntity.isAmbariManagedRepos());
-      String osType = operatingSystemEntity.getOsType();
-      List<RepositoryEntity> repositories = operatingSystemEntity.getRepositories();
-      for (RepositoryEntity repository : repositories) {
-        RepositoryInfo repo = ambariMetaInfo.getRepository(stackName, stackVersion, osType, repository.getRepositoryId());
+    List<RepoOsEntity> operatingSystemEntities = repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
+    for (RepoOsEntity operatingSystemEntity : operatingSystemEntities) {
+      Assert.assertFalse(operatingSystemEntity.isAmbariManaged());
+      String osType = operatingSystemEntity.getFamily();
+      List<RepoDefinitionEntity> repositories = operatingSystemEntity.getRepoDefinitionEntities();
+      for (RepoDefinitionEntity repository : repositories) {
+        RepositoryInfo repo = ambariMetaInfo.getRepository(stackName, stackVersion, osType, repository.getRepoID());
         if (repo != null) {
           String baseUrlActual = repo.getBaseUrl();
           String baseUrlExpected = repository.getBaseUrl();

+ 43 - 8
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java

@@ -77,6 +77,8 @@ import org.apache.ambari.server.orm.dao.StageDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.ExecutionCommandEntity;
 import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
@@ -214,25 +216,23 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
     StackEntity stackEntity220 = stackDAO.find("HDP", "2.2.0");
     StackId stack211 = new StackId(stackEntity211);
 
-    String operatingSystems = "[{\"OperatingSystems/ambari_managed_repositories\":\"true\",\"repositories\":[{\"Repositories/repo_id\":\"HDP\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP\"},{\"Repositories/repo_id\":\"HDP-UTILS\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP-UTILS\"}],\"OperatingSystems/os_type\":\"redhat6\"}]";
-
     repoVersionEntity2110 = new RepositoryVersionEntity();
     repoVersionEntity2110.setDisplayName("My New Version 1");
-    repoVersionEntity2110.setOperatingSystems(operatingSystems);
+    repoVersionEntity2110.addRepoOsEntities(createTestOperatingSystems());
     repoVersionEntity2110.setStack(stackEntity211);
     repoVersionEntity2110.setVersion("2.1.1.0");
     repoVersionDao.create(repoVersionEntity2110);
 
     repoVersionEntity2111 = new RepositoryVersionEntity();
     repoVersionEntity2111.setDisplayName("My New Version 2 for minor upgrade");
-    repoVersionEntity2111.setOperatingSystems(operatingSystems);
+    repoVersionEntity2111.addRepoOsEntities(createTestOperatingSystems());
     repoVersionEntity2111.setStack(stackEntity211);
     repoVersionEntity2111.setVersion("2.1.1.1");
     repoVersionDao.create(repoVersionEntity2111);
 
     repoVersionEntity2112 = new RepositoryVersionEntity();
     repoVersionEntity2112.setDisplayName("My New Version 3 for patch upgrade");
-    repoVersionEntity2112.setOperatingSystems(operatingSystems);
+    repoVersionEntity2112.addRepoOsEntities(createTestOperatingSystems());
     repoVersionEntity2112.setStack(stackEntity211);
     repoVersionEntity2112.setVersion("2.1.1.2");
     repoVersionEntity2112.setType(RepositoryType.PATCH);
@@ -241,7 +241,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
 
     repoVersionEntity2200 = new RepositoryVersionEntity();
     repoVersionEntity2200.setDisplayName("My New Version 4 for major upgrade");
-    repoVersionEntity2200.setOperatingSystems(operatingSystems);
+    repoVersionEntity2200.addRepoOsEntities(createTestOperatingSystems());
     repoVersionEntity2200.setStack(stackEntity220);
     repoVersionEntity2200.setVersion("2.2.0.0");
     repoVersionDao.create(repoVersionEntity2200);
@@ -281,6 +281,25 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
     EasyMock.replay(injector.getInstance(AuditLogger.class));
   }
 
+  private List<RepoOsEntity> createTestOperatingSystems() {
+    List<RepoOsEntity> operatingSystems = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("HDP-UTILS");
+    repoDefinitionEntity1.setBaseUrl("");
+    repoDefinitionEntity1.setRepoName("HDP-UTILS");
+    RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+    repoDefinitionEntity2.setRepoID("HDP");
+    repoDefinitionEntity2.setBaseUrl("");
+    repoDefinitionEntity2.setRepoName("HDP");
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+    operatingSystems.add(repoOsEntity);
+    return operatingSystems;
+  }
+
   @After
   public void after() throws AmbariException, SQLException {
     H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
@@ -998,7 +1017,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
 
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("My New Version 3");
-    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.addRepoOsEntities(new ArrayList<>());
     repoVersionEntity.setStack(stackEntity);
     repoVersionEntity.setVersion("2.2.2.3");
     repoVersionDao.create(repoVersionEntity);
@@ -1931,7 +1950,23 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
     StackEntity stackEntity = stackDAO.find("HDP", "2.1.1");
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("My New Version 3");
-    repoVersionEntity.setOperatingSystems("[{\"OperatingSystems/ambari_managed_repositories\":\"true\",\"repositories\":[{\"Repositories/repo_id\":\"HDP\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP\"},{\"Repositories/repo_id\":\"HDP-UTILS\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP-UTILS\"}],\"OperatingSystems/os_type\":\"redhat6\"}]");
+    List<RepoOsEntity> operatingSystems = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("HDP-UTILS");
+    repoDefinitionEntity1.setBaseUrl("");
+    repoDefinitionEntity1.setRepoName("HDP-UTILS");
+    RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+    repoDefinitionEntity2.setRepoID("HDP");
+    repoDefinitionEntity2.setBaseUrl("");
+    repoDefinitionEntity2.setRepoName("HDP");
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+    operatingSystems.add(repoOsEntity);
+
+    repoVersionEntity.addRepoOsEntities(operatingSystems);
     repoVersionEntity.setStack(stackEntity);
     repoVersionEntity.setVersion("2.2.2.3");
     repoVersionDao.create(repoVersionEntity);

+ 1 - 1
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeSummaryResourceProviderTest.java

@@ -149,7 +149,7 @@ public class UpgradeSummaryResourceProviderTest {
 
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("For Stack Version 2.2.0");
-    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.addRepoOsEntities(new ArrayList<>());
     repoVersionEntity.setStack(stackEntity);
     repoVersionEntity.setVersion("2.2.0.0");
     repoVersionDAO.create(repoVersionEntity);

+ 19 - 2
ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java

@@ -67,6 +67,8 @@ import org.apache.ambari.server.orm.entities.HostStateEntity;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
@@ -633,7 +635,7 @@ public class OrmTestHelper {
     if (repositoryVersion == null) {
       try {
         repositoryVersion = repositoryVersionDAO.create(stackEntity, version,
-            String.valueOf(System.currentTimeMillis()) + uniqueCounter.incrementAndGet(), "");
+            String.valueOf(System.currentTimeMillis()) + uniqueCounter.incrementAndGet(), new ArrayList<>());
       } catch (Exception ex) {
         LOG.error("Caught exception", ex);
         ex.printStackTrace();
@@ -667,7 +669,22 @@ public class OrmTestHelper {
 
     if (repositoryVersion == null) {
       try {
-        String operatingSystems = "[{\"OperatingSystems/ambari_managed_repositories\":\"true\",\"repositories\":[{\"Repositories/repo_id\":\"HDP\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP\"},{\"Repositories/repo_id\":\"HDP-UTILS\",\"Repositories/base_url\":\"\",\"Repositories/repo_name\":\"HDP-UTILS\"}],\"OperatingSystems/os_type\":\"redhat6\"}]";
+        List<RepoOsEntity> operatingSystems = new ArrayList<>();
+        RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+        repoDefinitionEntity1.setRepoID("HDP");
+        repoDefinitionEntity1.setBaseUrl("");
+        repoDefinitionEntity1.setRepoName("HDP");
+        RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+        repoDefinitionEntity2.setRepoID("HDP-UTILS");
+        repoDefinitionEntity2.setBaseUrl("");
+        repoDefinitionEntity2.setRepoName("HDP-UTILS");
+        RepoOsEntity repoOsEntity = new RepoOsEntity();
+        repoOsEntity.setFamily("redhat6");
+        repoOsEntity.setAmbariManaged(true);
+        repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+        repoOsEntity.addRepoDefinition(repoDefinitionEntity2);
+        operatingSystems.add(repoOsEntity);
+
 
         repositoryVersion = repositoryVersionDAO.create(stackEntity, version,
             String.valueOf(System.currentTimeMillis()) + uniqueCounter.incrementAndGet(), operatingSystems);

+ 2 - 1
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/CrudDAOTest.java

@@ -19,6 +19,7 @@
 package org.apache.ambari.server.orm.dao;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.H2DatabaseCleaner;
@@ -72,7 +73,7 @@ public class CrudDAOTest {
 
     final RepositoryVersionEntity entity = new RepositoryVersionEntity();
     entity.setDisplayName("display name" + uniqueCounter);
-    entity.setOperatingSystems("repositories");
+    entity.addRepoOsEntities(new ArrayList<>());
     entity.setStack(stackEntity);
     entity.setVersion("version" + uniqueCounter);
     repositoryVersionDAO.create(entity);

+ 1 - 0
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/HostVersionDAOTest.java

@@ -298,6 +298,7 @@ public class HostVersionDAOTest {
         helper.getOrCreateRepositoryVersion(HDP_22_STACK, repoVersion_2200), RepositoryVersionState.INSTALLED);
     hostVersionEntity3.setId(3L);
 
+    hostVersionEntity1.equals(hostVersionDAO.findByClusterStackVersionAndHost("test_cluster1", HDP_22_STACK, repoVersion_2200, "test_host1"));
     Assert.assertEquals(hostVersionEntity1, hostVersionDAO.findByClusterStackVersionAndHost("test_cluster1", HDP_22_STACK, repoVersion_2200, "test_host1"));
     Assert.assertEquals(hostVersionEntity2, hostVersionDAO.findByClusterStackVersionAndHost("test_cluster1", HDP_22_STACK, repoVersion_2200, "test_host2"));
     Assert.assertEquals(hostVersionEntity3, hostVersionDAO.findByClusterStackVersionAndHost("test_cluster1", HDP_22_STACK, repoVersion_2200, "test_host3"));

+ 8 - 7
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAOTest.java

@@ -19,6 +19,7 @@
 package org.apache.ambari.server.orm.dao;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.UUID;
 
 import org.apache.ambari.server.AmbariException;
@@ -72,7 +73,7 @@ public class RepositoryVersionDAOTest {
 
     final RepositoryVersionEntity entity = new RepositoryVersionEntity();
     entity.setDisplayName("display name");
-    entity.setOperatingSystems("repositories");
+    entity.addRepoOsEntities(new ArrayList<>());
     entity.setStack(stackEntity);
     entity.setVersion("version");
     repositoryVersionDAO.create(entity);
@@ -93,13 +94,13 @@ public class RepositoryVersionDAOTest {
     // Assert the version must be unique
     RepositoryVersionEntity dupVersion = new RepositoryVersionEntity();
     dupVersion.setDisplayName("display name " + uuid);
-    dupVersion.setOperatingSystems("repositories");
+    dupVersion.addRepoOsEntities(new ArrayList<>());
     dupVersion.setStack(stackEntity);
     dupVersion.setVersion(first.getVersion());
 
     boolean exceptionThrown = false;
     try {
-      repositoryVersionDAO.create(stackEntity, dupVersion.getVersion(), dupVersion.getDisplayName(), dupVersion.getOperatingSystemsJson());
+      repositoryVersionDAO.create(stackEntity, dupVersion.getVersion(), dupVersion.getDisplayName(), dupVersion.getRepoOsEntities());
     } catch (AmbariException e) {
       exceptionThrown = true;
       Assert.assertTrue(e.getMessage().contains("already exists"));
@@ -112,7 +113,7 @@ public class RepositoryVersionDAOTest {
     // The version must belong to the stack
     dupVersion.setVersion("2.3-1234");
     try {
-      repositoryVersionDAO.create(stackEntity, dupVersion.getVersion(), dupVersion.getDisplayName(), dupVersion.getOperatingSystemsJson());
+      repositoryVersionDAO.create(stackEntity, dupVersion.getVersion(), dupVersion.getDisplayName(), dupVersion.getRepoOsEntities());
     } catch (AmbariException e) {
       exceptionThrown = true;
       Assert.assertTrue(e.getMessage().contains("needs to belong to stack"));
@@ -123,7 +124,7 @@ public class RepositoryVersionDAOTest {
     // Success
     dupVersion.setVersion(stackEntity.getStackVersion() + "-1234");
     try {
-      repositoryVersionDAO.create(stackEntity, dupVersion.getVersion(), dupVersion.getDisplayName(), dupVersion.getOperatingSystemsJson());
+      repositoryVersionDAO.create(stackEntity, dupVersion.getVersion(), dupVersion.getDisplayName(), dupVersion.getRepoOsEntities());
     } catch (AmbariException e) {
       Assert.fail("Did not expect a failure creating the Repository Version");
     }
@@ -175,7 +176,7 @@ public class RepositoryVersionDAOTest {
 
     final RepositoryVersionEntity hdp206RepoEntity = new RepositoryVersionEntity();
     hdp206RepoEntity.setDisplayName("HDP-2.0.6.0-1234");
-    hdp206RepoEntity.setOperatingSystems("repositories");
+    hdp206RepoEntity.addRepoOsEntities(new ArrayList<>());
     hdp206RepoEntity.setStack(hdp206StackEntity);
     hdp206RepoEntity.setVersion("HDP-2.0.6.0-1234");
     repositoryVersionDAO.create(hdp206RepoEntity);
@@ -190,7 +191,7 @@ public class RepositoryVersionDAOTest {
 
     final RepositoryVersionEntity other10RepoEntity = new RepositoryVersionEntity();
     other10RepoEntity.setDisplayName("OTHER-1.0.1.0-1234");
-    other10RepoEntity.setOperatingSystems("repositories");
+    other10RepoEntity.addRepoOsEntities(new ArrayList<>());
     other10RepoEntity.setStack(other10StackEntity);
     other10RepoEntity.setVersion("OTHER-1.0.1.0-1234");
     repositoryVersionDAO.create(other10RepoEntity);

+ 15 - 3
ambari-server/src/test/java/org/apache/ambari/server/serveraction/upgrades/ComponentVersionCheckActionTest.java

@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -46,6 +47,8 @@ import org.apache.ambari.server.orm.dao.RequestDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
 import org.apache.ambari.server.orm.entities.HostVersionEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RequestEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
@@ -167,9 +170,18 @@ public class ComponentVersionCheckActionTest {
     m_helper.getOrCreateRepositoryVersion(sourceStack, sourceRepo);
 
     // Create the new repo version
-    String urlInfo = "[{'repositories':["
-        + "{'Repositories/base_url':'http://foo1','Repositories/repo_name':'HDP','Repositories/repo_id':'" + targetStack.getStackId() + "'}"
-        + "], 'OperatingSystems/os_type':'redhat6'}]";
+
+    List<RepoOsEntity> urlInfo = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID(targetStack.getStackId());
+    repoDefinitionEntity1.setBaseUrl("http://foo1");
+    repoDefinitionEntity1.setRepoName("HDP");
+    RepoOsEntity repoOsEntity = new RepoOsEntity();
+    repoOsEntity.setFamily("redhat6");
+    repoOsEntity.setAmbariManaged(true);
+    repoOsEntity.addRepoDefinition(repoDefinitionEntity1);
+    urlInfo.add(repoOsEntity);
+
 
     RepositoryVersionEntity toRepositoryVersion = repoVersionDAO.create(stackEntityTarget,
         targetRepo, String.valueOf(System.currentTimeMillis()), urlInfo);

+ 29 - 28
ambari-server/src/test/java/org/apache/ambari/server/stack/RepoUtilTest.java

@@ -22,8 +22,8 @@ import java.util.List;
 import java.util.Objects;
 
 import org.apache.ambari.server.controller.RepositoryResponse;
-import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
-import org.apache.ambari.server.orm.entities.RepositoryEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.junit.Assert;
 import org.junit.Test;
@@ -42,10 +42,10 @@ public class RepoUtilTest {
 
 
   @Test public void testAddServiceReposToOperatingSystemEntities_SimpleCase() {
-    List<OperatingSystemEntity> operatingSystems = new ArrayList<>();
+    List<RepoOsEntity> operatingSystems = new ArrayList<>();
     for (String os: OPERATING_SYSTEMS) {
-      RepositoryEntity repo1 = repoEntity("HDP", "HDP-2.3", "http://hdp.org/2.3");
-      RepositoryEntity repo2 = repoEntity("HDP-UTILS", "HDP-UTILS-1.1.0", "http://hdp.org/utils/1.1.0");
+      RepoDefinitionEntity repo1 = repoEntity("HDP", "HDP-2.3", "http://hdp.org/2.3");
+      RepoDefinitionEntity repo2 = repoEntity("HDP-UTILS", "HDP-UTILS-1.1.0", "http://hdp.org/utils/1.1.0");
       operatingSystems.add(osEntity(os, repo1, repo2));
     }
     ListMultimap<String, RepositoryInfo> serviceRepos = serviceRepos(ImmutableList.of("redhat5", "redhat6", "sles11"),
@@ -54,21 +54,21 @@ public class RepoUtilTest {
     RepoUtil.addServiceReposToOperatingSystemEntities(operatingSystems, serviceRepos);
 
     // Verify results. Service repos should be added only to redhat6 and sles11
-    for (OperatingSystemEntity os: operatingSystems) {
-      Assert.assertNotSame("Redhat5 should not be added as new operating system.", "redhat5", os.getOsType());
-      Optional<RepositoryEntity> msft_r = findRepoEntityById(os.getRepositories(), "MSFT_R-8.1");
+    for (RepoOsEntity os : operatingSystems) {
+      Assert.assertNotSame("Redhat5 should not be added as new operating system.", "redhat5", os.getFamily());
+      Optional<RepoDefinitionEntity> msft_r = findRepoEntityById(os.getRepoDefinitionEntities(), "MSFT_R-8.1");
       Assert.assertTrue(
-          String.format("Only redhat6 and sles11 should contain the service repo. os: %s, repo: %s", os.getOsType(), msft_r),
-          findRepoEntityById(os.getRepositories(), "MSFT_R-8.1").isPresent() ==  ImmutableList.of("redhat6", "sles11").contains(os.getOsType())) ;
+          String.format("Only redhat6 and sles11 should contain the service repo. os: %s, repo: %s", os.getFamily(), msft_r),
+          findRepoEntityById(os.getRepoDefinitionEntities(), "MSFT_R-8.1").isPresent() == ImmutableList.of("redhat6", "sles11").contains(os.getFamily()));
     }
   }
 
   @Test public void testAddServiceReposToOperatingSystemEntities_RepoAlreadExists() {
-    List<OperatingSystemEntity> operatingSystems = new ArrayList<>();
+    List<RepoOsEntity> operatingSystems = new ArrayList<>();
     for (String os: OPERATING_SYSTEMS) {
-      RepositoryEntity repo1 = repoEntity("HDP", "HDP-2.3", "http://hdp.org/2.3");
-      RepositoryEntity repo2 = repoEntity("HDP-UTILS", "HDP-UTILS-1.1.0", "http://hdp.org/utils/1.1.0");
-      RepositoryEntity repo3 = repoEntity("MSFT_R", "MSFT_R-8.1", "http://msft.r.ORIGINAL");
+      RepoDefinitionEntity repo1 = repoEntity("HDP", "HDP-2.3", "http://hdp.org/2.3");
+      RepoDefinitionEntity repo2 = repoEntity("HDP-UTILS", "HDP-UTILS-1.1.0", "http://hdp.org/utils/1.1.0");
+      RepoDefinitionEntity repo3 = repoEntity("MSFT_R", "MSFT_R-8.1", "http://msft.r.ORIGINAL");
       operatingSystems.add(osEntity(os, repo1, repo2, repo3));
     }
     ListMultimap<String, RepositoryInfo> serviceRepos = serviceRepos(ImmutableList.of("redhat6"),
@@ -77,9 +77,9 @@ public class RepoUtilTest {
     RepoUtil.addServiceReposToOperatingSystemEntities(operatingSystems, serviceRepos);
 
     // Verify results. Service repo should not be added second time.
-    for (OperatingSystemEntity os: operatingSystems) {
-      Optional<RepositoryEntity> msft_r_orig = findRepoEntityById(os.getRepositories(), "MSFT_R-8.1");
-      Optional<RepositoryEntity> msft_r_new = findRepoEntityById(os.getRepositories(), "MSFT_R-8.2");
+    for (RepoOsEntity os : operatingSystems) {
+      Optional<RepoDefinitionEntity> msft_r_orig = findRepoEntityById(os.getRepoDefinitionEntities(), "MSFT_R-8.1");
+      Optional<RepoDefinitionEntity> msft_r_new = findRepoEntityById(os.getRepoDefinitionEntities(), "MSFT_R-8.2");
       Assert.assertTrue("Original repo is missing", msft_r_orig.isPresent());
       Assert.assertTrue("Service repo with duplicate name should not have been added", !msft_r_new.isPresent());
     }
@@ -116,26 +116,27 @@ public class RepoUtilTest {
     }
   }
 
-  private static Optional<RepositoryEntity> findRepoEntityById(Iterable<RepositoryEntity> repos, String repoId) {
-    for (RepositoryEntity repo: repos) if (Objects.equals(repo.getRepositoryId(), repoId)) {
+  private static Optional<RepoDefinitionEntity> findRepoEntityById(Iterable<RepoDefinitionEntity> repos, String repoId) {
+    for (RepoDefinitionEntity repo : repos)
+      if (Objects.equals(repo.getRepoID(), repoId)) {
       return Optional.of(repo);
     }
     return Optional.absent();
   }
 
-  private static OperatingSystemEntity osEntity(String os, RepositoryEntity... repoEntities) {
-    OperatingSystemEntity entity = new OperatingSystemEntity();
-    entity.setOsType(os);
-    for (RepositoryEntity repo: repoEntities) {
-      entity.getRepositories().add(repo);
+  private static RepoOsEntity osEntity(String os, RepoDefinitionEntity... repoEntities) {
+    RepoOsEntity entity = new RepoOsEntity();
+    entity.setFamily(os);
+    for (RepoDefinitionEntity repo : repoEntities) {
+      entity.addRepoDefinition(repo);
     }
     return entity;
   }
 
-  private static RepositoryEntity repoEntity(String name, String repoId, String baseUrl) {
-    RepositoryEntity repo = new RepositoryEntity();
-    repo.setName(name);
-    repo.setRepositoryId(repoId);
+  private static RepoDefinitionEntity repoEntity(String name, String repoId, String baseUrl) {
+    RepoDefinitionEntity repo = new RepoDefinitionEntity();
+    repo.setRepoName(name);
+    repo.setRepoID(repoId);
     repo.setBaseUrl(baseUrl);
     return repo;
   }

+ 36 - 1
ambari-server/src/test/java/org/apache/ambari/server/stack/UpdateActiveRepoVersionOnStartupTest.java

@@ -25,7 +25,9 @@ import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
@@ -33,6 +35,8 @@ import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
+import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
+import org.apache.ambari.server.orm.entities.RepoOsEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
@@ -108,7 +112,38 @@ public class UpdateActiveRepoVersionOnStartupTest {
 
     RepositoryVersionEntity desiredRepositoryVersion = new RepositoryVersionEntity();
     desiredRepositoryVersion.setStack(stackEntity);
-    desiredRepositoryVersion.setOperatingSystems(resourceAsString("org/apache/ambari/server/stack/UpdateActiveRepoVersionOnStartupTest_initialRepos.json"));
+
+    List<RepoOsEntity> operatingSystems = new ArrayList<>();
+    RepoDefinitionEntity repoDefinitionEntity1 = new RepoDefinitionEntity();
+    repoDefinitionEntity1.setRepoID("HDP-UTILS-1.1.0.20");
+    repoDefinitionEntity1.setBaseUrl("http://192.168.99.100/repos/HDP-UTILS-1.1.0.20/");
+    repoDefinitionEntity1.setRepoName("HDP-UTILS");
+    RepoDefinitionEntity repoDefinitionEntity2 = new RepoDefinitionEntity();
+    repoDefinitionEntity2.setRepoID("HDP-2.4");
+    repoDefinitionEntity2.setBaseUrl("http://192.168.99.100/repos/HDP-2.4.0.0/");
+    repoDefinitionEntity2.setRepoName("HDP");
+    RepoOsEntity repoOsEntity1 = new RepoOsEntity();
+    repoOsEntity1.setFamily("redhat6");
+    repoOsEntity1.setAmbariManaged(true);
+    repoOsEntity1.addRepoDefinition(repoDefinitionEntity1);
+    repoOsEntity1.addRepoDefinition(repoDefinitionEntity2);
+    operatingSystems.add(repoOsEntity1);
+    RepoDefinitionEntity repoDefinitionEntity3 = new RepoDefinitionEntity();
+    repoDefinitionEntity3.setRepoID("HDP-UTILS-1.1.0.20");
+    repoDefinitionEntity3.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos7");
+    repoDefinitionEntity3.setRepoName("HDP-UTILS");
+    RepoDefinitionEntity repoDefinitionEntity4 = new RepoDefinitionEntity();
+    repoDefinitionEntity4.setRepoID("HDP-2.4");
+    repoDefinitionEntity4.setBaseUrl("http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos7/2.x/BUILDS/2.4.3.0-207");
+    repoDefinitionEntity4.setRepoName("HDP");
+    RepoOsEntity repoOsEntity2 = new RepoOsEntity();
+    repoOsEntity2.setFamily("redhat7");
+    repoOsEntity2.setAmbariManaged(true);
+    repoOsEntity2.addRepoDefinition(repoDefinitionEntity3);
+    repoOsEntity2.addRepoDefinition(repoDefinitionEntity4);
+    operatingSystems.add(repoOsEntity2);
+
+    desiredRepositoryVersion.addRepoOsEntities(operatingSystems);
 
     ServiceDesiredStateEntity serviceDesiredStateEntity = new ServiceDesiredStateEntity();
     serviceDesiredStateEntity.setDesiredRepositoryVersion(desiredRepositoryVersion);

+ 3 - 2
ambari-server/src/test/java/org/apache/ambari/server/state/ServiceComponentTest.java

@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -435,7 +436,7 @@ public class ServiceComponentTest {
     StackEntity stackEntity = stackDAO.find("HDP", "2.2.0");
 
     RepositoryVersionEntity rve = new RepositoryVersionEntity(stackEntity, "HDP-2.2.0",
-        "2.2.0.1-1111", "[]");
+        "2.2.0.1-1111", new ArrayList<>());
 
     RepositoryVersionDAO repositoryDAO = injector.getInstance(RepositoryVersionDAO.class);
     repositoryDAO.create(rve);
@@ -490,7 +491,7 @@ public class ServiceComponentTest {
     StackEntity stackEntity = stackDAO.find("HDP", "2.2.0");
 
     RepositoryVersionEntity rve = new RepositoryVersionEntity(stackEntity, "HDP-2.2.0",
-        "2.2.0.1-1111", "[]");
+        "2.2.0.1-1111", new ArrayList<>());
 
     RepositoryVersionDAO repositoryDAO = injector.getInstance(RepositoryVersionDAO.class);
     repositoryDAO.create(rve);

+ 2 - 2
ambari-server/src/test/java/org/apache/ambari/server/state/services/RetryUpgradeActionServiceTest.java

@@ -238,7 +238,7 @@ public class RetryUpgradeActionServiceTest {
 
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("Initial Version");
-    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.addRepoOsEntities(new ArrayList<>());
     repoVersionEntity.setStack(stackEntity220);
     repoVersionEntity.setVersion("2.2.0.0");
     repoVersionDAO.create(repoVersionEntity);
@@ -253,7 +253,7 @@ public class RetryUpgradeActionServiceTest {
   private void prepareUpgrade() throws AmbariException {
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("Version to Upgrade To");
-    repoVersionEntity.setOperatingSystems("");
+    repoVersionEntity.addRepoOsEntities(new ArrayList<>());
     repoVersionEntity.setStack(stackEntity220);
     repoVersionEntity.setVersion("2.2.0.1");
     repoVersionDAO.create(repoVersionEntity);

+ 0 - 58
ambari-server/src/test/java/org/apache/ambari/server/state/stack/upgrade/RepositoryVersionHelperTest.java

@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.state.stack.upgrade;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.ambari.server.state.RepositoryInfo;
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.google.gson.Gson;
-
-/**
- * Tests the {@link RepositoryVersionHelper} class
- */
-public class RepositoryVersionHelperTest {
-
-  private RepositoryVersionHelper helper;
-
-  @Test
-  public void testSerializeOperatingSystems() throws Exception {
-    Gson gson = new Gson();
-    Field field = RepositoryVersionHelper.class.getDeclaredField("gson");
-    field.setAccessible(true);
-
-    RepositoryVersionHelper helper = new RepositoryVersionHelper();
-    field.set(helper, gson);
-
-    final List<RepositoryInfo> repositories = new ArrayList<>();
-    final RepositoryInfo repository = new RepositoryInfo();
-    repository.setBaseUrl("baseurl");
-    repository.setOsType("os");
-    repository.setRepoId("repoId");
-    repository.setUnique(true);
-    repository.setAmbariManagedRepositories(true);
-    repositories.add(repository);
-
-    final String serialized = helper.serializeOperatingSystems(repositories);
-    Assert.assertEquals("[{\"OperatingSystems/ambari_managed_repositories\":true,\"repositories\":[{\"Repositories/base_url\":\"baseurl\",\"Repositories/repo_id\":\"repoId\",\"Repositories/unique\":true,\"Repositories/tags\":[]}],\"OperatingSystems/os_type\":\"os\"}]", serialized);
-  }
-}