ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nc...@apache.org
Subject ambari git commit: AMBARI-15652. Provide an in-memory representation of available VDF (ncole)
Date Fri, 01 Apr 2016 19:30:38 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk 12d19c9f8 -> 69c636eb2


AMBARI-15652. Provide an in-memory representation of available VDF (ncole)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/69c636eb
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/69c636eb
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/69c636eb

Branch: refs/heads/trunk
Commit: 69c636eb20427de5f203c97021077b659bd41081
Parents: 12d19c9
Author: Nate Cole <ncole@hortonworks.com>
Authored: Fri Apr 1 08:51:25 2016 -0400
Committer: Nate Cole <ncole@hortonworks.com>
Committed: Fri Apr 1 14:47:20 2016 -0400

----------------------------------------------------------------------
 .../VersionDefinitionResourceDefinition.java    |  53 +------
 .../server/api/services/AmbariMetaInfo.java     |  88 ++++++++----
 .../api/services/VersionDefinitionService.java  |  24 +++-
 .../AmbariManagementControllerImpl.java         |  73 +++++++++-
 .../controller/OperatingSystemRequest.java      |  14 ++
 .../controller/OperatingSystemResponse.java     |  15 ++
 .../server/controller/RepositoryResponse.java   |  14 ++
 .../OperatingSystemResourceProvider.java        |  43 +++---
 .../internal/RepositoryResourceProvider.java    |  14 +-
 .../VersionDefinitionResourceProvider.java      | 138 ++++++++++++++++---
 .../apache/ambari/server/state/StackInfo.java   |  86 +++++++-----
 .../state/repository/VersionDefinitionXml.java  |  96 ++++++++++++-
 .../server/state/stack/LatestRepoCallable.java  |  74 ++++++++--
 .../src/main/resources/version_definition.xsd   |   2 +-
 .../AmbariManagementControllerTest.java         |  25 ++++
 ...ClusterStackVersionResourceProviderTest.java |   2 +-
 .../VersionDefinitionResourceProviderTest.java  |  76 +++++++++-
 .../state/repository/VersionDefinitionTest.java |  40 ++++++
 .../resources/stacks/HDP/2.2.0/repos/hdp.json   |   5 +
 .../HDP/2.2.0/repos/version-2.2.0.4-123.xml     |  49 +++++++
 contrib/version-builder/version_builder.py      |   4 +-
 21 files changed, 765 insertions(+), 170 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java
index 67d9439..ba4491e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java
@@ -17,27 +17,16 @@
  */
 package org.apache.ambari.server.api.resources;
 
-import java.util.List;
+import java.util.Collections;
+import java.util.Set;
 
-import org.apache.ambari.server.api.services.Request;
-import org.apache.ambari.server.api.util.TreeNode;
-import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
-import org.apache.ambari.server.controller.internal.VersionDefinitionResourceProvider;
 import org.apache.ambari.server.controller.spi.Resource;
-
-import com.google.common.collect.Lists;
+import org.apache.ambari.server.controller.spi.Resource.Type;
 
 /**
  * The Resource Definition used for Version Definition files.
  */
 public class VersionDefinitionResourceDefinition extends BaseResourceDefinition {
-  private static final String STACKS_NAME = new StackResourceDefinition().getPluralName();
-  private static final String STACK_VERSIONS_NAME = new StackVersionResourceDefinition().getPluralName();
-  private static final String REPO_VERSIONS_NAME = new RepositoryVersionResourceDefinition().getPluralName();
-
-  private static final String HREF_TEMPLATE =
-      STACKS_NAME + "/%s/" + STACK_VERSIONS_NAME + "/%s/" + REPO_VERSIONS_NAME;
-
 
   public VersionDefinitionResourceDefinition() {
     super(Resource.Type.VersionDefinition);
@@ -54,40 +43,8 @@ public class VersionDefinitionResourceDefinition extends BaseResourceDefinition
   }
 
   @Override
-  public List<PostProcessor> getPostProcessors() {
-    List<PostProcessor> list = Lists.newArrayList();
-
-    list.add(new HrefPostProcessor());
-
-    return list;
-  }
-
-
-  class HrefPostProcessor extends BaseHrefPostProcessor {
-    @Override
-    public void process(Request request, TreeNode<Resource> resultNode, String href) {
-      super.process(request, resultNode, href);
-
-      Object stackNameObj = resultNode.getObject().getPropertyValue(
-          VersionDefinitionResourceProvider.VERSION_DEF_STACK_NAME);
-      Object stackVersionObj = resultNode.getObject().getPropertyValue(
-          VersionDefinitionResourceProvider.VERSION_DEF_STACK_VERSION);
-
-      if (resultNode.getObject().getType() == Resource.Type.VersionDefinition &&
-          null != stackNameObj && null != stackVersionObj &&
-          null != resultNode.getProperty("href")) {
-
-        String oldHref = resultNode.getProperty("href").toString();
-
-        String newPath = String.format(HREF_TEMPLATE, stackNameObj, stackVersionObj);
-
-        String newHref = oldHref.replace(getPluralName(), newPath);
-        newHref = newHref.replace(VersionDefinitionResourceProvider.VERSION_DEF,
-            RepositoryVersionResourceProvider.REPOSITORY_VERSION);
-
-        resultNode.setProperty("href", newHref);
-      }
-    }
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    return Collections.singleton(new SubResourceDefinition(Type.OperatingSystem));
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index 0f09d94..c243552 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -18,10 +18,27 @@
 
 package org.apache.ambari.server.api.services;
 
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
+import static org.apache.ambari.server.controller.spi.Resource.InternalType.Component;
+import static org.apache.ambari.server.controller.utilities.PropertyHelper.AGGREGATE_FUNCTION_IDENTIFIERS;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+
+import javax.xml.bind.JAXBException;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ParentObjectNotFoundException;
 import org.apache.ambari.server.StackAccessException;
@@ -58,33 +75,19 @@ import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
+import org.apache.ambari.server.state.repository.VersionDefinitionXml;
+import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.Metric;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.OsFamily;
-import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.xml.bind.JAXBException;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.Set;
-
-import static org.apache.ambari.server.controller.spi.Resource.InternalType.Component;
-import static org.apache.ambari.server.controller.utilities.PropertyHelper.AGGREGATE_FUNCTION_IDENTIFIERS;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 
 /**
@@ -152,6 +155,8 @@ public class AmbariMetaInfo {
   private File commonServicesRoot;
   private File serverVersionFile;
   private File customActionRoot;
+  private Map<String, VersionDefinitionXml> versionDefinitions = null;
+
 
   @Inject
   private MetainfoDAO metaInfoDAO;
@@ -1344,4 +1349,39 @@ public class AmbariMetaInfo {
   public Map<String, String> getAmbariServerProperties() {
     return conf.getAmbariProperties();
   }
+
+  /**
+   * Ensures that the map of version definition files is populated
+   */
+  private void ensureVersionDefinitions() {
+    if (null == versionDefinitions) {
+      versionDefinitions = new HashMap<>();
+    }
+    for (StackInfo stack : getStacks()) {
+      for (VersionDefinitionXml definition : stack.getVersionDefinitions()) {
+        versionDefinitions.put(String.format("%s-%s-%s", stack.getName(),
+            stack.getVersion(), definition.release.version), definition);
+      }
+    }
+  }
+
+  /**
+   * @param versionDefinitionId the version definition id
+   * @return the definition, or {@code null} if not found
+   */
+  public VersionDefinitionXml getVersionDefinition(String versionDefinitionId) {
+    ensureVersionDefinitions();
+
+    return versionDefinitions.get(versionDefinitionId);
+  }
+
+  /**
+   * @return the version definitions found for stacks
+   */
+  public Map<String, VersionDefinitionXml> getVersionDefinitions() {
+    ensureVersionDefinitions();
+
+    return versionDefinitions;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
index e637850..6410bd8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/VersionDefinitionService.java
@@ -19,6 +19,8 @@
 package org.apache.ambari.server.api.services;
 
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -54,12 +56,27 @@ public class VersionDefinitionService extends BaseService {
   @Path("{versionId}")
   @Produces(MediaType.TEXT_PLAIN)
   public Response getService(@Context HttpHeaders headers, @Context UriInfo ui,
-      @PathParam("versionId") Long versionId) {
+      @PathParam("versionId") String versionId) {
 
     return handleRequest(headers, null, ui, Request.Type.GET,
       createResource(versionId));
   }
 
+  /**
+   * Handles ANY /{versionNumber}/operating_systems requests.
+   *
+   * @param versionNumber the repository version id, whether it be from the DB or available.
+   * @return operating systems service
+   */
+  @Path("{versionNumber}/operating_systems")
+  public OperatingSystemService getOperatingSystemsHandler(@PathParam("versionNumber") String versionNumber) {
+    final Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.VersionDefinition, versionNumber);
+    return new OperatingSystemService(mapIds);
+  }
+
+
+
   @POST
   @Produces(MediaType.TEXT_PLAIN)
   public Response createVersion(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
@@ -92,10 +109,9 @@ public class VersionDefinitionService extends BaseService {
         createResource(null));
   }
 
-  protected ResourceInstance createResource(Long versionId) {
+  protected ResourceInstance createResource(String versionId) {
     return createResource(Resource.Type.VersionDefinition,
-        Collections.singletonMap(Resource.Type.VersionDefinition,
-            null == versionId ? null : versionId.toString()));
+        Collections.singletonMap(Resource.Type.VersionDefinition, versionId));
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index d1f8232..a0b98f7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -160,6 +160,7 @@ import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
+import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.WidgetLayout;
 import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
@@ -3762,6 +3763,16 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     String osType = request.getOsType();
     String repoId = request.getRepoId();
     Long repositoryVersionId = request.getRepositoryVersionId();
+    String versionDefinitionId = request.getVersionDefinitionId();
+
+    // !!! when asking for Repository responses for a versionDefinition, it is either for
+    // an established repo version (a Long) OR from the in-memory generated ones (a String)
+    if (null == repositoryVersionId && null != versionDefinitionId) {
+
+      if (NumberUtils.isDigits(versionDefinitionId)) {
+        repositoryVersionId = Long.valueOf(versionDefinitionId);
+      }
+    }
 
     Set<RepositoryResponse> responses = new HashSet<RepositoryResponse>();
 
@@ -3772,7 +3783,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           if (operatingSystem.getOsType().equals(osType)) {
             for (RepositoryEntity repository: operatingSystem.getRepositories()) {
               final RepositoryResponse response = new RepositoryResponse(repository.getBaseUrl(), osType, repository.getRepositoryId(), repository.getName(), "", "", "");
-              response.setRepositoryVersionId(repositoryVersionId);
+              if (null != versionDefinitionId) {
+                response.setVersionDefinitionId(versionDefinitionId);
+              } else {
+                response.setRepositoryVersionId(repositoryVersionId);
+              }
               response.setStackName(repositoryVersion.getStackName());
               response.setStackVersion(repositoryVersion.getStackVersion());
               responses.add(response);
@@ -3781,6 +3796,29 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           }
         }
       }
+    } else if (null != versionDefinitionId) {
+      VersionDefinitionXml xml = ambariMetaInfo.getVersionDefinition(versionDefinitionId);
+
+      if (null == xml) {
+        throw new AmbariException(String.format("Version identified by %s does not exist",
+            versionDefinitionId));
+      }
+      StackId stackId = new StackId(xml.release.stackId);
+
+      for (RepositoryXml.Os os : xml.repositoryInfo.getOses()) {
+        for (RepositoryXml.Repo repo : os.getRepos()) {
+          RepositoryResponse resp = new RepositoryResponse(repo.getBaseUrl(), os.getFamily(),
+              repo.getRepoId(), repo.getRepoName(), repo.getMirrorsList(),
+              repo.getBaseUrl(), repo.getLatestUri());
+
+          resp.setVersionDefinitionId(versionDefinitionId);
+          resp.setStackName(stackId.getStackName());
+          resp.setStackVersion(stackId.getStackVersion());
+
+          responses.add(resp);
+        }
+      }
+
     } else {
       if (repoId == null) {
         List<RepositoryInfo> repositories = ambariMetaInfo.getRepositories(stackName, stackVersion, osType);
@@ -4188,18 +4226,49 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     String stackVersion = request.getStackVersion();
     String osType = request.getOsType();
     Long repositoryVersionId = request.getRepositoryVersionId();
+    String versionDefinitionId = request.getVersionDefinitionId();
+
+    // !!! when asking for OperatingSystem responses for a versionDefinition, it is either for
+    // an established repo version (a Long) OR from the in-memory generated ones (a String)
+    if (null == repositoryVersionId && null != versionDefinitionId) {
+      if (NumberUtils.isDigits(versionDefinitionId)) {
+        repositoryVersionId = Long.valueOf(versionDefinitionId);
+      }
+    }
 
     if (repositoryVersionId != null) {
       final RepositoryVersionEntity repositoryVersion = repositoryVersionDAO.findByPK(repositoryVersionId);
       if (repositoryVersion != null) {
         for (OperatingSystemEntity operatingSystem: repositoryVersion.getOperatingSystems()) {
           final OperatingSystemResponse response = new OperatingSystemResponse(operatingSystem.getOsType());
-          response.setRepositoryVersionId(repositoryVersionId);
+          if (null != versionDefinitionId) {
+            response.setVersionDefinitionId(repositoryVersionId.toString());
+          } else {
+            response.setRepositoryVersionId(repositoryVersionId);
+          }
           response.setStackName(repositoryVersion.getStackName());
           response.setStackVersion(repositoryVersion.getStackVersion());
           responses.add(response);
         }
       }
+    } else if (null != versionDefinitionId) {
+      VersionDefinitionXml xml = ambariMetaInfo.getVersionDefinition(versionDefinitionId);
+
+      if (null == xml) {
+        throw new AmbariException(String.format("Version identified by %s does not exist",
+            versionDefinitionId));
+      }
+      StackId stackId = new StackId(xml.release.stackId);
+
+      for (RepositoryXml.Os os : xml.repositoryInfo.getOses()) {
+        OperatingSystemResponse resp = new OperatingSystemResponse(os.getFamily());
+        resp.setVersionDefinitionId(versionDefinitionId);
+        resp.setStackName(stackId.getStackName());
+        resp.setStackVersion(stackId.getStackVersion());
+
+        responses.add(resp);
+      }
+
     } else {
       if (osType != null) {
         OperatingSystemInfo operatingSystem = ambariMetaInfo.getOperatingSystem(stackName, stackVersion, osType);

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemRequest.java
index 16136db..35a6a8c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemRequest.java
@@ -22,6 +22,7 @@ public class OperatingSystemRequest extends StackVersionRequest {
 
   private String osType;
   private Long repositoryVersionId;
+  private String versionDefinitionId;
 
   public OperatingSystemRequest(String stackName, String stackVersion, String osType) {
     super(stackName, stackVersion);
@@ -44,4 +45,17 @@ public class OperatingSystemRequest extends StackVersionRequest {
     this.repositoryVersionId = repositoryVersionId;
   }
 
+  /**
+   * @param id the version definition id string
+   */
+  public void setVersionDefinitionId(String id) {
+    versionDefinitionId = id;
+  }
+  /**
+   * @return the version definition id string
+   */
+  public String getVersionDefinitionId() {
+    return versionDefinitionId;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemResponse.java
index cc9bb70..06b4148 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/OperatingSystemResponse.java
@@ -24,6 +24,7 @@ public class OperatingSystemResponse {
   private String stackVersion;
   private String osType;
   private Long repositoryVersionId;
+  private String versionDefinitionId;
 
   public OperatingSystemResponse(String osType) {
     setOsType(osType);
@@ -60,4 +61,18 @@ public class OperatingSystemResponse {
   public void setRepositoryVersionId(Long repositoryVersionId) {
     this.repositoryVersionId = repositoryVersionId;
   }
+
+  /**
+   * @param id the version definition id
+   */
+  public void setVersionDefinitionId(String id) {
+    versionDefinitionId = id;
+  }
+
+  /**
+   * @return the version definition id
+   */
+  public String getVersionDefinitionId() {
+    return versionDefinitionId;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
index 63f6b60..6221826 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryResponse.java
@@ -30,6 +30,7 @@ public class RepositoryResponse {
   private String defaultBaseUrl;
   private String latestBaseUrl;
   private Long repositoryVersionId;
+  private String versionDefinitionId;
 
   public RepositoryResponse(String baseUrl, String osType, String repoId,
       String repoName, String mirrorsList, String defaultBaseUrl, String latestBaseUrl) {
@@ -128,4 +129,17 @@ public class RepositoryResponse {
     this.repositoryVersionId = repositoryVersionId;
   }
 
+  /**
+   * @param id the version definition id
+   */
+  public void setVersionDefinitionId(String id) {
+    versionDefinitionId = id;
+  }
+
+  /**
+   * @return the version definition id
+   */
+  public String getVersionDefinitionId() {
+    return versionDefinitionId;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/OperatingSystemResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/OperatingSystemResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/OperatingSystemResourceProvider.java
index b982583..fd4a91f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/OperatingSystemResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/OperatingSystemResourceProvider.java
@@ -38,33 +38,28 @@ import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
+import com.google.common.collect.Sets;
+
 public class OperatingSystemResourceProvider extends ReadOnlyResourceProvider {
 
   public static final String OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID            = PropertyHelper.getPropertyId("OperatingSystems", "stack_name");
   public static final String OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID         = PropertyHelper.getPropertyId("OperatingSystems", "stack_version");
   public static final String OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID               = PropertyHelper.getPropertyId("OperatingSystems", "os_type");
   public static final String OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("OperatingSystems", "repository_version_id");
+  public static final String OPERATING_SYSTEM_VERSION_DEFINITION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("OperatingSystems", "version_definition_id");
 
-  @SuppressWarnings("serial")
-  private static Set<String> pkPropertyIds = new HashSet<String>() {
-    {
-      add(OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
-      add(OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID);
-      add(OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID);
-    }
-  };
+  private static Set<String> pkPropertyIds = Sets.newHashSet(
+      OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID,
+      OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID,
+      OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID);
 
-  @SuppressWarnings("serial")
-  public static Set<String> propertyIds = new HashSet<String>() {
-    {
-      add(OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
-      add(OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID);
-      add(OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID);
-      add(OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID);
-    }
-  };
+  public static Set<String> propertyIds = Sets.newHashSet(
+      OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID,
+      OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID,
+      OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID,
+      OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID,
+      OPERATING_SYSTEM_VERSION_DEFINITION_ID_PROPERTY_ID);
 
-  @SuppressWarnings("serial")
   public static Map<Type, String> keyPropertyIds = new HashMap<Type, String>() {
     {
       put(Resource.Type.OperatingSystem, OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
@@ -72,6 +67,7 @@ public class OperatingSystemResourceProvider extends ReadOnlyResourceProvider {
       put(Resource.Type.StackVersion, OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID);
       put(Resource.Type.RepositoryVersion, OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID);
       put(Resource.Type.CompatibleRepositoryVersion, OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID);
+      put(Resource.Type.VersionDefinition, OPERATING_SYSTEM_VERSION_DEFINITION_ID_PROPERTY_ID);
     }
   };
 
@@ -122,6 +118,11 @@ public class OperatingSystemResourceProvider extends ReadOnlyResourceProvider {
             response.getRepositoryVersionId(), requestedIds);
       }
 
+      if (response.getVersionDefinitionId() != null) {
+        setResourceProperty(resource, OPERATING_SYSTEM_VERSION_DEFINITION_ID_PROPERTY_ID,
+            response.getVersionDefinitionId(), requestedIds);
+      }
+
       resources.add(resource);
     }
 
@@ -133,9 +134,15 @@ public class OperatingSystemResourceProvider extends ReadOnlyResourceProvider {
         (String) properties.get(OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID),
         (String) properties.get(OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID),
         (String) properties.get(OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID));
+
     if (properties.containsKey(OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID)) {
       request.setRepositoryVersionId(Long.parseLong(properties.get(OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID).toString()));
     }
+
+    if (properties.containsKey(OPERATING_SYSTEM_VERSION_DEFINITION_ID_PROPERTY_ID)) {
+      request.setVersionDefinitionId(properties.get(OPERATING_SYSTEM_VERSION_DEFINITION_ID_PROPERTY_ID).toString());
+    }
+
     return request;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
index a37364f..1622a4d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
@@ -57,6 +57,7 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
   public static final String REPOSITORY_VERIFY_BASE_URL_PROPERTY_ID       = PropertyHelper.getPropertyId("Repositories", "verify_base_url");
   public static final String REPOSITORY_LATEST_BASE_URL_PROPERTY_ID       = PropertyHelper.getPropertyId("Repositories", "latest_base_url");
   public static final String REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("Repositories", "repository_version_id");
+  public static final String REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("Repositories", "version_definition_id");
 
   @SuppressWarnings("serial")
   private static Set<String> pkPropertyIds = new HashSet<String>() {
@@ -82,6 +83,7 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
       add(REPOSITORY_VERIFY_BASE_URL_PROPERTY_ID);
       add(REPOSITORY_LATEST_BASE_URL_PROPERTY_ID);
       add(REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID);
+      add(REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID);
     }
   };
 
@@ -94,6 +96,7 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
       put(Resource.Type.OperatingSystem, REPOSITORY_OS_TYPE_PROPERTY_ID);
       put(Resource.Type.Repository, REPOSITORY_REPO_ID_PROPERTY_ID);
       put(Resource.Type.RepositoryVersion, REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID);
+      put(Resource.Type.VersionDefinition, REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID);
     }
   };
 
@@ -163,10 +166,15 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
         setResourceProperty(resource, REPOSITORY_MIRRORS_LIST_PROPERTY_ID, response.getMirrorsList(), requestedIds);
         setResourceProperty(resource, REPOSITORY_DEFAULT_BASE_URL_PROPERTY_ID, response.getDefaultBaseUrl(), requestedIds);
         setResourceProperty(resource, REPOSITORY_LATEST_BASE_URL_PROPERTY_ID, response.getLatestBaseUrl(), requestedIds);
-        if (response.getRepositoryVersionId() != null) {
+        if (null != response.getRepositoryVersionId()) {
           setResourceProperty(resource, REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID, response.getRepositoryVersionId(), requestedIds);
         }
 
+        if (null != response.getVersionDefinitionId()) {
+          setResourceProperty(resource, REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID,
+              response.getVersionDefinitionId(), requestedIds);
+        }
+
         resources.add(resource);
     }
 
@@ -217,6 +225,10 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
       request.setRepositoryVersionId(Long.parseLong(properties.get(REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID).toString()));
     }
 
+    if (properties.containsKey(REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID)) {
+      request.setVersionDefinitionId(properties.get(REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID).toString());
+    }
+
     if (properties.containsKey(REPOSITORY_BASE_URL_PROPERTY_ID)) {
       request.setBaseUrl((String) properties.get(REPOSITORY_BASE_URL_PROPERTY_ID));
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
index 3ab5169..963265b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java
@@ -27,10 +27,12 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.StaticallyInject;
+import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
 import org.apache.ambari.server.configuration.Configuration;
@@ -58,6 +60,7 @@ import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
 
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
@@ -78,14 +81,19 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
   protected static final String VERSION_DEF_ID                       = "VersionDefinition/id";
   protected static final String VERSION_DEF_TYPE_PROPERTY_ID         = "VersionDefinition/type";
   protected static final String VERSION_DEF_DEFINITION_URL           = "VersionDefinition/version_url";
-
+  protected static final String VERSION_DEF_AVAILABLE_DEFINITION     = "VersionDefinition/available";
   protected static final String VERSION_DEF_DEFINITION_BASE64        = PropertyHelper.getPropertyId(VERSION_DEF, VERSION_DEF_BASE64_PROPERTY);
+
   protected static final String VERSION_DEF_FULL_VERSION             = "VersionDefinition/repository_version";
   protected static final String VERSION_DEF_RELEASE_VERSION          = "VersionDefinition/release/version";
   protected static final String VERSION_DEF_RELEASE_BUILD            = "VersionDefinition/release/build";
   protected static final String VERSION_DEF_RELEASE_NOTES            = "VersionDefinition/release/notes";
   protected static final String VERSION_DEF_RELEASE_COMPATIBLE_WITH  = "VersionDefinition/release/compatible_with";
   protected static final String VERSION_DEF_AVAILABLE_SERVICES       = "VersionDefinition/services";
+  protected static final String VERSION_DEF_STACK_SERVICES           = "VersionDefinition/stack_services";
+  protected static final String SHOW_AVAILABLE                       = "VersionDefinition/show_available";
+
+  public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID  = new OperatingSystemResourceDefinition().getPluralName();
 
   @Inject
   private static RepositoryVersionDAO s_repoVersionDAO;
@@ -109,7 +117,8 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
       VERSION_DEF_ID,
       VERSION_DEF_STACK_NAME,
       VERSION_DEF_STACK_VERSION,
-      VERSION_DEF_FULL_VERSION);
+      VERSION_DEF_FULL_VERSION
+      );
 
   /**
    * The property ids for an version definition resource.
@@ -119,12 +128,17 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
       VERSION_DEF_TYPE_PROPERTY_ID,
       VERSION_DEF_DEFINITION_URL,
       VERSION_DEF_DEFINITION_BASE64,
+      VERSION_DEF_STACK_NAME,
+      VERSION_DEF_STACK_VERSION,
       VERSION_DEF_FULL_VERSION,
       VERSION_DEF_RELEASE_NOTES,
       VERSION_DEF_RELEASE_COMPATIBLE_WITH,
       VERSION_DEF_RELEASE_VERSION,
       VERSION_DEF_RELEASE_BUILD,
-      VERSION_DEF_AVAILABLE_SERVICES);
+      VERSION_DEF_AVAILABLE_SERVICES,
+      VERSION_DEF_STACK_SERVICES,
+      SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID,
+      SHOW_AVAILABLE);
 
   /**
    * The key property ids for an version definition resource.
@@ -161,8 +175,11 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
 
     final Map<String, Object> properties = requestProperties.iterator().next();
 
-    if (!properties.containsKey(VERSION_DEF_DEFINITION_URL) && !properties.containsKey(VERSION_DEF_DEFINITION_BASE64)) {
-      throw new IllegalArgumentException(String.format("%s is required or upload the file directly", VERSION_DEF_DEFINITION_URL));
+    if (!properties.containsKey(VERSION_DEF_DEFINITION_URL) &&
+        !properties.containsKey(VERSION_DEF_DEFINITION_BASE64) &&
+        !properties.containsKey(VERSION_DEF_AVAILABLE_DEFINITION)) {
+      throw new IllegalArgumentException(String.format("Creation method is not known.  %s or %s is required or upload the file directly",
+          VERSION_DEF_DEFINITION_URL, VERSION_DEF_AVAILABLE_DEFINITION));
     }
 
     if (properties.containsKey(VERSION_DEF_DEFINITION_URL) && properties.containsKey(VERSION_DEF_DEFINITION_BASE64)) {
@@ -176,14 +193,32 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
 
         String definitionUrl = (String) properties.get(VERSION_DEF_DEFINITION_URL);
         String definitionBase64 = (String) properties.get(VERSION_DEF_DEFINITION_BASE64);
+        String definitionName = (String) properties.get(VERSION_DEF_AVAILABLE_DEFINITION);
 
         XmlHolder holder = null;
         if (null != definitionUrl) {
           holder = loadXml(definitionUrl);
-        } else {
+        } else if (null != definitionBase64) {
           holder = loadXml(Base64.decodeBase64(definitionBase64));
+        } else if (null != definitionName) {
+          VersionDefinitionXml xml = s_metaInfo.get().getVersionDefinition(definitionName);
+          if (null == xml) {
+            throw new AmbariException(String.format("Version %s not found", definitionName));
+          }
+
+          holder = new XmlHolder();
+          holder.xml = xml;
+          try {
+            holder.xmlString = xml.toXml();
+          } catch (Exception e) {
+            throw new AmbariException(String.format("The available repository %s does not serialize", definitionName));
+          }
+
+        } else {
+          throw new AmbariException("Cannot determine creation method");
         }
 
+
         RepositoryVersionEntity entity = toRepositoryVersionEntity(holder);
 
         RepositoryVersionResourceProvider.validateRepositoryVersion(s_repoVersionDAO,
@@ -213,23 +248,52 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     Set<Resource> results = new HashSet<Resource>();
     Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
 
-    if (null == predicate){
+    Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
+
+    if (propertyMaps.isEmpty()) {
       List<RepositoryVersionEntity> versions = s_repoVersionDAO.findAllDefinitions();
 
       for (RepositoryVersionEntity entity : versions) {
         results.add(toResource(entity, requestPropertyIds));
       }
-
     } else {
-      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
-        String id = (String) propertyMap.get(VERSION_DEF_ID);
-        if (null == id) {
-          continue;
-        }
+      for (Map<String, Object> propertyMap : propertyMaps) {
+
+        if (propertyMap.containsKey(SHOW_AVAILABLE) &&
+            Boolean.parseBoolean(propertyMap.get(SHOW_AVAILABLE).toString())) {
+
+          for (Entry<String, VersionDefinitionXml> entry : s_metaInfo.get().getVersionDefinitions().entrySet()) {
+            results.add(toResource(entry.getKey(), entry.getValue(), requestPropertyIds));
+          }
+
+        } else {
+          String id = (String) propertyMap.get(VERSION_DEF_ID);
+
+          if (null != id) {
+            if (NumberUtils.isDigits(id)) {
+
+              RepositoryVersionEntity entity = s_repoVersionDAO.findByPK(Long.parseLong(id));
+              if (null != entity) {
+                results.add(toResource(entity, requestPropertyIds));
+              }
+            } else {
+              VersionDefinitionXml xml = s_metaInfo.get().getVersionDefinition(id);
+
+              if (null == xml) {
+                throw new NoSuchResourceException(String.format("Could not find version %s",
+                    id));
+              }
+              results.add(toResource(id, xml, requestPropertyIds));
+
+            }
+          } else {
+            List<RepositoryVersionEntity> versions = s_repoVersionDAO.findAllDefinitions();
+
+            for (RepositoryVersionEntity entity : versions) {
+              results.add(toResource(entity, requestPropertyIds));
+            }
+          }
 
-        RepositoryVersionEntity entity = s_repoVersionDAO.findByPK(Long.parseLong(id));
-        if (null != entity) {
-          results.add(toResource(entity, requestPropertyIds));
         }
       }
     }
@@ -408,6 +472,38 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     return entity;
   }
 
+  private Resource toResource(String id, VersionDefinitionXml xml, Set<String> requestedIds) throws SystemException {
+
+    Resource resource = new ResourceImpl(Resource.Type.VersionDefinition);
+    resource.setProperty(VERSION_DEF_ID, id);
+    resource.setProperty(SHOW_AVAILABLE, Boolean.TRUE);
+    StackId stackId = new StackId(xml.release.stackId);
+
+    // !!! these are needed for href
+    resource.setProperty(VERSION_DEF_STACK_NAME, stackId.getStackName());
+    resource.setProperty(VERSION_DEF_STACK_VERSION, stackId.getStackVersion());
+
+    StackInfo stack = null;
+    try {
+      stack = s_metaInfo.get().getStack(stackId.getStackName(), stackId.getStackVersion());
+    } catch (AmbariException e) {
+      throw new SystemException(String.format("Could not load stack %s", stackId));
+    }
+
+    setResourceProperty(resource, VERSION_DEF_TYPE_PROPERTY_ID, xml.release.repositoryType, requestedIds);
+    setResourceProperty(resource, VERSION_DEF_FULL_VERSION, xml.release.version, requestedIds);
+    setResourceProperty(resource, VERSION_DEF_RELEASE_BUILD, xml.release.build, requestedIds);
+    setResourceProperty(resource, VERSION_DEF_RELEASE_COMPATIBLE_WITH, xml.release.compatibleWith, requestedIds);
+    setResourceProperty(resource, VERSION_DEF_RELEASE_NOTES, xml.release.releaseNotes, requestedIds);
+    setResourceProperty(resource, VERSION_DEF_RELEASE_VERSION, xml.release.version, requestedIds);
+
+    setResourceProperty(resource, VERSION_DEF_AVAILABLE_SERVICES, xml.getAvailableServices(stack), requestedIds);
+    setResourceProperty(resource, VERSION_DEF_STACK_SERVICES, xml.getStackServices(stack), requestedIds);
+
+    return resource;
+
+  }
+
   /**
    * Convert the given {@link RepositoryVersionEntity} to a {@link Resource}.
    *
@@ -421,7 +517,6 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
       throws SystemException {
 
     Resource resource = new ResourceImpl(Resource.Type.VersionDefinition);
-
     resource.setProperty(VERSION_DEF_ID, entity.getId());
 
     VersionDefinitionXml xml = null;
@@ -446,17 +541,20 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     setResourceProperty(resource, VERSION_DEF_RELEASE_NOTES, xml.release.releaseNotes, requestedIds);
     setResourceProperty(resource, VERSION_DEF_RELEASE_VERSION, xml.release.version, requestedIds);
 
-      // !!! future do something with the manifest
+    StackInfo stack = null;
 
-    if (isPropertyRequested(VERSION_DEF_AVAILABLE_SERVICES, requestedIds)) {
-      StackInfo stack = null;
+    if (isPropertyRequested(VERSION_DEF_AVAILABLE_SERVICES, requestedIds) ||
+        isPropertyRequested(VERSION_DEF_STACK_SERVICES, requestedIds)) {
       try {
         stack = s_metaInfo.get().getStack(stackId.getStackName(), stackId.getStackVersion());
       } catch (AmbariException e) {
         throw new SystemException(String.format("Could not load stack %s", stackId));
       }
+    }
 
+    if (null != stack) {
       setResourceProperty(resource, VERSION_DEF_AVAILABLE_SERVICES, xml.getAvailableServices(stack), requestedIds);
+      setResourceProperty(resource, VERSION_DEF_STACK_SERVICES, xml.getStackServices(stack), requestedIds);
     }
 
     return resource;

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
index 0d87b68..ad4c8b4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
@@ -27,33 +27,18 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.ambari.server.controller.StackVersionResponse;
 import org.apache.ambari.server.stack.Validable;
-import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
+import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.stack.ConfigUpgradePack;
+import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
 import org.apache.ambari.server.state.stack.UpgradePack;
 
 public class StackInfo implements Comparable<StackInfo>, Validable{
   private String minJdk;
   private String maxJdk;
-
-  public String getMinJdk() {
-    return minJdk;
-  }
-
-  public void setMinJdk(String minJdk) {
-    this.minJdk = minJdk;
-  }
-
-  public String getMaxJdk() {
-    return maxJdk;
-  }
-
-  public void setMaxJdk(String maxJdk) {
-    this.maxJdk = maxJdk;
-  }
-
   private String name;
   private String version;
   private String minUpgradeVersion;
@@ -73,9 +58,37 @@ public class StackInfo implements Comparable<StackInfo>, Validable{
   private boolean valid = true;
   private Map<String, Map<PropertyInfo.PropertyType, Set<String>>> propertiesTypesCache =
       Collections.synchronizedMap(new HashMap<String, Map<PropertyInfo.PropertyType, Set<String>>>());
+  /**
+   * Meaning: stores subpath from stack root to exact hooks folder for stack. These hooks are
+   * applied to all commands for services in current stack.
+   */
+  private String stackHooksFolder;
+
+  private String upgradesFolder = null;
+
+  private volatile Map<String, PropertyInfo> requiredProperties;
+
+  private Map<String, VersionDefinitionXml> versionDefinitions = new ConcurrentHashMap<>();
+
+
+  public String getMinJdk() {
+    return minJdk;
+  }
+
+  public void setMinJdk(String minJdk) {
+    this.minJdk = minJdk;
+  }
+
+  public String getMaxJdk() {
+    return maxJdk;
+  }
+
+  public void setMaxJdk(String maxJdk) {
+    this.maxJdk = maxJdk;
+  }
 
   /**
-   * 
+   *
    * @return valid xml flag
    */
   @Override
@@ -84,16 +97,16 @@ public class StackInfo implements Comparable<StackInfo>, Validable{
   }
 
   /**
-   * 
+   *
    * @param valid set validity flag
    */
   @Override
   public void setValid(boolean valid) {
     this.valid = valid;
-  }    
+  }
 
   private Set<String> errorSet = new HashSet<String>();
-  
+
   @Override
   public void setErrors(String error) {
     errorSet.add(error);
@@ -102,22 +115,12 @@ public class StackInfo implements Comparable<StackInfo>, Validable{
   @Override
   public Collection getErrors() {
     return errorSet;
-  }   
-  
+  }
+
   @Override
   public void setErrors(Collection error) {
     this.errorSet.addAll(error);
   }
-  
-  /**
-   * Meaning: stores subpath from stack root to exact hooks folder for stack. These hooks are
-   * applied to all commands for services in current stack.
-   */
-  private String stackHooksFolder;
-
-  private String upgradesFolder = null;
-
-  private volatile Map<String, PropertyInfo> requiredProperties;
 
   public String getName() {
     return name;
@@ -460,4 +463,19 @@ public class StackInfo implements Comparable<StackInfo>, Validable{
     return propertiesTypesCache.get(configType);
   }
 
+  /**
+   * @param key the version that the xml represents
+   * @param xml the version definition object
+   */
+  public void addVersionDefinition(String key, VersionDefinitionXml xml) {
+    versionDefinitions.put(key, xml);
+  }
+
+  /**
+   * @return the list of available definitions on this stack
+   */
+  public Collection<VersionDefinitionXml> getVersionDefinitions() {
+    return versionDefinitions.values();
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
index 50bc30f..4488f58 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.state.repository;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.io.StringWriter;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,6 +33,7 @@ import java.util.TreeSet;
 
 import javax.xml.XMLConstants;
 import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -46,7 +48,9 @@ import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 
 import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.repository.AvailableVersion.Component;
 import org.apache.ambari.server.state.stack.RepositoryXml;
@@ -214,6 +218,36 @@ public class VersionDefinitionXml {
     return set;
   }
 
+  /**
+   * Returns the XML representation of this instance.
+   */
+  public String toXml() throws Exception {
+
+    JAXBContext ctx = JAXBContext.newInstance(VersionDefinitionXml.class);
+    Marshaller marshaller = ctx.createMarshaller();
+    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+    InputStream xsdStream = VersionDefinitionXml.class.getClassLoader().getResourceAsStream(xsdLocation);
+
+    if (null == xsdStream) {
+      throw new Exception(String.format("Could not load XSD identified by '%s'", xsdLocation));
+    }
+
+    try {
+      Schema schema = factory.newSchema(new StreamSource(xsdStream));
+      marshaller.setSchema(schema);
+      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+      marshaller.setProperty("jaxb.noNamespaceSchemaLocation", xsdLocation);
+
+      StringWriter w = new StringWriter();
+      marshaller.marshal(this, w);
+
+      return w.toString();
+    } finally {
+      IOUtils.closeQuietly(xsdStream);
+    }
+  }
+
 
 
   /**
@@ -258,8 +292,10 @@ public class VersionDefinitionXml {
     JAXBContext ctx = JAXBContext.newInstance(VersionDefinitionXml.class);
     Unmarshaller unmarshaller = ctx.createUnmarshaller();
 
+    InputStream xsdStream = null;
+
     if (null != xsdName) {
-      InputStream xsdStream = VersionDefinitionXml.class.getClassLoader().getResourceAsStream(xsdName);
+      xsdStream = VersionDefinitionXml.class.getClassLoader().getResourceAsStream(xsdName);
 
       if (null == xsdStream) {
         throw new Exception(String.format("Could not load XSD identified by '%s'", xsdName));
@@ -270,13 +306,63 @@ public class VersionDefinitionXml {
       unmarshaller.setSchema(schema);
     }
 
-    VersionDefinitionXml xml = (VersionDefinitionXml) unmarshaller.unmarshal(xmlReader);
-    xml.xsdLocation = xsdName;
-
-    return xml;
+    try {
+      VersionDefinitionXml xml = (VersionDefinitionXml) unmarshaller.unmarshal(xmlReader);
+      xml.xsdLocation = xsdName;
+      return xml;
+    } finally {
+      IOUtils.closeQuietly(xsdStream);
+    }
   }
 
+  /**
+   * Used to facilitate merging when multiple version definitions are provided.  Ambari
+   * represents them as a unified entity.  Since there is no knowledge of which one is
+   * "correct" - the first one is used for the release meta-info.
+   */
+  public static class Merger {
+    private VersionDefinitionXml m_xml = new VersionDefinitionXml();
+    private boolean m_seeded = false;
 
+    public Merger() {
+      m_xml.release = new Release();
+      m_xml.repositoryInfo = new RepositoryXml();
+    }
 
+    /**
+     * Adds definition to this one.
+     * @param version the version the definition represents
+     * @param xml the definition object
+     */
+    public void add(String version, VersionDefinitionXml xml) {
+      if (!m_seeded) {
+        m_xml.xsdLocation = xml.xsdLocation;
+
+        StackId stackId = new StackId(xml.release.stackId);
+
+        m_xml.release.build = null; // could be combining builds, so this is invalid
+        m_xml.release.compatibleWith = xml.release.compatibleWith;
+        m_xml.release.display = stackId.getStackName() + "-" + xml.release.version;
+        m_xml.release.packageVersion = null; // could be combining, so this is invalid
+        m_xml.release.repositoryType = RepositoryType.STANDARD; // assumption since merging only done for new installs
+        m_xml.release.releaseNotes = xml.release.releaseNotes;
+        m_xml.release.stackId = xml.release.stackId;
+        m_xml.release.version = version;
+        m_xml.manifestServices.addAll(xml.manifestServices);
+
+        m_seeded = true;
+      }
+
+      m_xml.repositoryInfo.getOses().addAll(xml.repositoryInfo.getOses());
+    }
+
+    /**
+     * @return the merged definition file
+     */
+    public VersionDefinitionXml merge() {
+      return m_seeded ? m_xml : null;
+    }
+
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/java/org/apache/ambari/server/state/stack/LatestRepoCallable.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/LatestRepoCallable.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/LatestRepoCallable.java
index 0ad24fe..fc2bab1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/LatestRepoCallable.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/LatestRepoCallable.java
@@ -21,13 +21,17 @@ import java.io.File;
 import java.io.FileReader;
 import java.io.InputStreamReader;
 import java.lang.reflect.Type;
+import java.net.URI;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
 import org.apache.ambari.server.controller.internal.URLStreamProvider;
 import org.apache.ambari.server.state.RepositoryInfo;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,8 +75,8 @@ public class LatestRepoCallable implements Callable<Void> {
             LOOKUP_CONNECTION_TIMEOUT, LOOKUP_READ_TIMEOUT,
             null, null, null);
 
-        LOG.info("Loading latest URL info for stack " + stack.getName() + "-" +
-                stack.getVersion() + " from " + sourceUri);
+        LOG.info("Loading latest URL info for stack {}-{} from {}", stack.getName(),
+                stack.getVersion(), sourceUri);
         latestUrlMap = gson.fromJson(new InputStreamReader(
             streamProvider.readFrom(sourceUri)), type);
       } else {
@@ -84,23 +88,24 @@ public class LatestRepoCallable implements Callable<Void> {
         }
 
         if (jsonFile.exists()) {
-          LOG.info("Loading latest URL info for stack " + stack.getName() + "-" +
-                  stack.getVersion() + " from " + jsonFile);
+          LOG.info("Loading latest URL info for stack{}-{} from {}", stack.getName(),
+                  stack.getVersion(), jsonFile);
           latestUrlMap = gson.fromJson(new FileReader(jsonFile), type);
         }
       }
     } catch (Exception e) {
-      LOG.info("Could not load the URI for stack " + stack.getName() + "-" +
-              stack.getVersion() + " from " + sourceUri + " (" + e.getMessage() + ")" +
-              ". Using default repository values.");
+      LOG.info("Could not load the URI for stack {}-{} from {}, ({}).  Using default repository values",
+          stack.getName(), stack.getVersion(), sourceUri, e.getMessage());
       throw e;
     }
 
-
+    // !!! process latest overrides
     if (null != latestUrlMap) {
       for (RepositoryInfo ri : stack.getRepositories()) {
         if (latestUrlMap.containsKey(ri.getRepoId())) {
+
           Map<String, Object> valueMap = latestUrlMap.get(ri.getRepoId());
+
           if (valueMap.containsKey("latest")) {
 
             @SuppressWarnings("unchecked")
@@ -112,7 +117,7 @@ public class LatestRepoCallable implements Callable<Void> {
               // Agents do the reverse action (take the base url, and append <name>.repo)
 
               String repo_file_format;
-              
+
               if(os_family.isUbuntuFamily(ri.getOsType())) {
                 repo_file_format = "list";
               } else {
@@ -141,6 +146,57 @@ public class LatestRepoCallable implements Callable<Void> {
       }
     }
 
+    StackId stackId = new StackId(stack);
+    if (!latestUrlMap.containsKey(stackId.toString())) {
+      return null;
+    }
+
+    Map<String, Object> map = latestUrlMap.get(stackId.toString());
+    if (null == map || !map.containsKey("manifests")) {
+      return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    Map<String, Object> versionMap = (Map<String, Object>) map.get("manifests");
+
+    // EACH VDF is for ONLY ONE repository.  We must provide a merged view.
+    // there is no good way around this, so we have to make some concessions
+
+    // !!! each key is a version number, and the value is a map containing
+    // os_family -> VDF link
+    VersionDefinitionXml.Merger merger = new VersionDefinitionXml.Merger();
+
+    for (Entry<String, Object> entry : versionMap.entrySet()) {
+      String version = entry.getKey();
+
+      @SuppressWarnings("unchecked")
+      Map<String, String> osMap = (Map<String, String>) entry.getValue();
+
+      for (Entry<String, String> versionEntry : osMap.entrySet()) {
+        String uriString = versionEntry.getValue();
+
+        if ('.' == uriString.charAt(0)) {
+          uriString = new File(stackRepoFolder, uriString).toURI().toString();
+        }
+
+        try {
+          URI uri = new URI(uriString);
+
+          VersionDefinitionXml xml = VersionDefinitionXml.load(uri.toURL());
+
+          merger.add(version, xml);
+        } catch (Exception e) {
+          LOG.warn("Could not load version definition for {} identified by {}. {}",
+              stackId, uriString, e.getMessage(), e);
+        }
+      }
+
+      VersionDefinitionXml xml = merger.merge();
+      if (null != xml) {
+        stack.addVersionDefinition(version, xml);
+      }
+    }
+
     return null;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/main/resources/version_definition.xsd
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/version_definition.xsd b/ambari-server/src/main/resources/version_definition.xsd
index 3c0399f..d437906 100644
--- a/ambari-server/src/main/resources/version_definition.xsd
+++ b/ambari-server/src/main/resources/version_definition.xsd
@@ -30,7 +30,7 @@
      <xs:element name="type" type="repo-type" />
      <xs:element name="stack-id" type="xs:string" />
      <xs:element name="version" type="xs:string" />
-     <xs:element name="build" type="xs:string" />
+     <xs:element name="build" type="xs:string" minOccurs="0" maxOccurs="1"/>
      <xs:element name="compatible-with" type="xs:string" minOccurs="0"/>
      <xs:element name="release-notes" type="xs:string" maxOccurs="1" />
      <xs:element name="display" type="xs:string" minOccurs="0" />

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index d729d2a..1612233 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -74,6 +74,7 @@ import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.audit.AuditLoggerModule;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.internal.ClusterStackVersionResourceProviderTest;
 import org.apache.ambari.server.controller.internal.ComponentResourceProviderTest;
 import org.apache.ambari.server.controller.internal.HostComponentResourceProviderTest;
 import org.apache.ambari.server.controller.internal.HostResourceProviderTest;
@@ -94,12 +95,15 @@ import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.ExecutionCommandDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
+import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.dao.TopologyHostInfoDAO;
 import org.apache.ambari.server.orm.dao.WidgetDAO;
 import org.apache.ambari.server.orm.dao.WidgetLayoutDAO;
 import org.apache.ambari.server.orm.entities.ExecutionCommandEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
+import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.WidgetEntity;
 import org.apache.ambari.server.orm.entities.WidgetLayoutEntity;
 import org.apache.ambari.server.orm.entities.WidgetLayoutUserWidgetEntity;
@@ -7342,6 +7346,27 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
+  public void testGetStackOperatingSystemsWithRepository() throws Exception {
+    RepositoryVersionDAO dao = injector.getInstance(RepositoryVersionDAO.class);
+    StackDAO stackDAO = injector.getInstance(StackDAO.class);
+    StackEntity stackEntity = stackDAO.find(STACK_NAME, STACK_VERSION);
+    assertNotNull(stackEntity);
+
+    dao.create(stackEntity, "0.2.2", "HDP-0.2", ClusterStackVersionResourceProviderTest.OS_JSON);
+
+    OperatingSystemRequest request = new OperatingSystemRequest(STACK_NAME, STACK_VERSION, null);
+    Set<OperatingSystemResponse> responses = controller.getOperatingSystems(Collections.singleton(request));
+    Assert.assertEquals(OS_CNT, responses.size());
+
+    OperatingSystemRequest requestWithParams = new OperatingSystemRequest(STACK_NAME, STACK_VERSION, OS_TYPE);
+    requestWithParams.setVersionDefinitionId("1");
+
+    Set<OperatingSystemResponse> responsesWithParams = controller.getOperatingSystems(Collections.singleton(requestWithParams));
+    Assert.assertEquals(1, responsesWithParams.size());
+
+  }
+
+  @Test
   public void testStackServiceCheckSupported() throws Exception {
     StackServiceRequest hdfsServiceRequest = new StackServiceRequest(
         STACK_NAME, "2.0.8", SERVICE_NAME);

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
index 58f00e9..4da8896 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java
@@ -134,7 +134,7 @@ public class ClusterStackVersionResourceProviderTest {
   private HostVersionDAO hostVersionDAO;
   private HostComponentStateDAO hostComponentStateDAO;
 
-  private static final String OS_JSON = "[\n" +
+  public static final String OS_JSON = "[\n" +
           "   {\n" +
           "      \"repositories\":[\n" +
           "         {\n" +

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java
index efdf84e..5a63606 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java
@@ -17,8 +17,12 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import static org.junit.Assert.fail;
+
 import java.io.File;
 import java.io.FileInputStream;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -41,6 +45,7 @@ import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
+import org.apache.ambari.server.stack.StackManager;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
@@ -78,7 +83,6 @@ public class VersionDefinitionResourceProviderTest {
 
     RepositoryVersionDAO dao = injector.getInstance(RepositoryVersionDAO.class);
     dao.create(entity);
-
   }
 
   @After
@@ -237,4 +241,74 @@ public class VersionDefinitionResourceProviderTest {
     Assert.assertEquals("http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.4/",
         vals.get("notes"));
   }
+
+  @Test
+  public void testGetAvailable() throws Exception {
+    AmbariMetaInfo ami = injector.getInstance(AmbariMetaInfo.class);
+    // ensure that all of the latest repo retrieval tasks have completed
+    StackManager sm = ami.getStackManager();
+    int maxWait = 15000;
+    int waitTime = 0;
+    while (waitTime < maxWait && ! sm.haveAllRepoUrlsBeenResolved()) {
+      Thread.sleep(5);
+      waitTime += 5;
+    }
+
+    if (waitTime >= maxWait) {
+      fail("Latest Repo tasks did not complete");
+    }
+
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    final ResourceProvider versionProvider = new VersionDefinitionResourceProvider();
+
+    Request getRequest = PropertyHelper.getReadRequest("VersionDefinition");
+
+    Predicate predicate = new PredicateBuilder().property(
+        VersionDefinitionResourceProvider.SHOW_AVAILABLE).equals("true").toPredicate();
+
+    Set<Resource> results = versionProvider.getResources(getRequest, predicate);
+    Assert.assertEquals(1, results.size());
+
+    Resource res = results.iterator().next();
+
+    Assert.assertEquals("HDP-2.2.0-2.2.1.0", res.getPropertyValue("VersionDefinition/id"));
+  }
+
+  @Test
+  public void testCreateByAvailable() throws Exception {
+    AmbariMetaInfo ami = injector.getInstance(AmbariMetaInfo.class);
+    // ensure that all of the latest repo retrieval tasks have completed
+    StackManager sm = ami.getStackManager();
+    int maxWait = 15000;
+    int waitTime = 0;
+    while (waitTime < maxWait && ! sm.haveAllRepoUrlsBeenResolved()) {
+      Thread.sleep(5);
+      waitTime += 5;
+    }
+
+    if (waitTime >= maxWait) {
+      fail("Latest Repo tasks did not complete");
+    }
+
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    final ResourceProvider versionProvider = new VersionDefinitionResourceProvider();
+
+    Request getRequest = PropertyHelper.getReadRequest("VersionDefinition");
+    Set<Resource> results = versionProvider.getResources(getRequest, null);
+    Assert.assertEquals(0, results.size());
+
+    Map<String, Object> createMap = new HashMap<>();
+    createMap.put("VersionDefinition/available", "HDP-2.2.0-2.2.1.0");
+
+    Request createRequest = PropertyHelper.getCreateRequest(Collections.singleton(createMap), null);
+    versionProvider.createResources(createRequest);
+
+    results = versionProvider.getResources(getRequest, null);
+    Assert.assertEquals(1, results.size());
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
index 707057f..d262df3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.state.repository;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -168,6 +169,45 @@ public class VersionDefinitionTest {
     assertTrue(foundHive);
   }
 
+  @Test
+  public void testSerialization() throws Exception {
+
+    File f = new File("src/test/resources/version_definition_test_all_services.xml");
+
+    VersionDefinitionXml xml = VersionDefinitionXml.load(f.toURI().toURL());
+
+    String xmlString = xml.toXml();
+
+    xml = VersionDefinitionXml.load(xmlString);
+
+    assertNotNull(xml.release.build);
+    assertEquals("1234", xml.release.build);
+  }
+
+
+  @Test
+  public void testMerger() throws Exception {
+    File f = new File("src/test/resources/version_definition_test_all_services.xml");
+
+    VersionDefinitionXml xml1 = VersionDefinitionXml.load(f.toURI().toURL());
+    VersionDefinitionXml xml2 = VersionDefinitionXml.load(f.toURI().toURL());
+    xml2.release.version = "2.3.4.2";
+    xml2.release.build = "2468";
+
+    VersionDefinitionXml.Merger builder = new VersionDefinitionXml.Merger();
+    VersionDefinitionXml xml3 = builder.merge();
+
+    assertNull(xml3);
+
+    builder.add(xml1.release.version, xml1);
+    builder.add("", xml2);
+    xml3 = builder.merge();
+
+    assertNotNull(xml3);
+    assertNull("Merged definition cannot have a build", xml3.release.build);
+    assertEquals(xml3.release.version, "2.3.4.1");
+  }
+
   private static ServiceInfo makeService(final String name) {
     return new ServiceInfo() {
       @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
index 37a6a60..f80fc0a 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/hdp.json
@@ -5,6 +5,11 @@
       "redhat6": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.2.2.0-123",
       "oraclelinux6": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.2.0.0-123",
       "suse11": "http://s3.amazonaws.com/dev.hortonworks.com/HDP/suse11/2.x/BUILDS/2.2.0.0-123/hdp.repo"
+    },
+    "manifests": {
+      "2.2.1.0": {
+        "centos6": "./version-2.2.0.4-123.xml"
+      }
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/version-2.2.0.4-123.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/version-2.2.0.4-123.xml b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/version-2.2.0.4-123.xml
new file mode 100644
index 0000000..0b027ee
--- /dev/null
+++ b/ambari-server/src/test/resources/stacks/HDP/2.2.0/repos/version-2.2.0.4-123.xml
@@ -0,0 +1,49 @@
+<?xml version="1.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.
+-->
+<repository-version xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="version_definition.xsd">
+  <release>
+    <type>STANDARD</type>
+    <stack-id>HDP-2.2.0</stack-id>
+    <version>2.2.0.4</version>
+    <build>123</build>
+    <release-notes>http://example.com</release-notes>
+    <display>HDP-2.2.0.4-1234</display>
+    <compatible-with>2.2.0.0</compatible-with>
+  </release>
+  <manifest>
+    <service id="HDFS-271" name="HDFS" version="2.7.1.2.4"/>
+    <service id="HBASE-132" name="HBASE" version="1.3.2.4.3"/>
+  </manifest>
+  <available-services>
+    <service idref="HDFS-271"/>
+  </available-services>
+  <repository-info>
+    <os family="redhat6">
+      <repo>
+        <baseurl>http://baseurl1</baseurl>
+        <repoid>HDP-2.4</repoid>
+        <reponame>HDP</reponame>
+      </repo>
+      <repo>
+        <baseurl>http://baseurl2</baseurl>
+        <repoid>HDP-UTILS-1.1.0.20</repoid>
+        <reponame>HDP-UTILS</reponame>
+      </repo>
+    </os>
+  </repository-info>
+</repository-version>

http://git-wip-us.apache.org/repos/asf/ambari/blob/69c636eb/contrib/version-builder/version_builder.py
----------------------------------------------------------------------
diff --git a/contrib/version-builder/version_builder.py b/contrib/version-builder/version_builder.py
index f209894..5d101be 100644
--- a/contrib/version-builder/version_builder.py
+++ b/contrib/version-builder/version_builder.py
@@ -69,10 +69,10 @@ class VersionBuilder:
       raise Exception(stderr)
 
     if len(stdout) > 0:
-      print(stdout)
+      print(stdout.decode("UTF-8"))
 
     if len(stderr) > 0:
-      print(stderr)
+      print(stderr.decode("UTF-8"))
 
   def set_release(self, type=None, stack=None, version=None, build=None, notes=None, display=None,
     compatible=None, package_version=None):


Mime
View raw message