You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by tb...@apache.org on 2015/01/19 19:58:24 UTC

ambari git commit: AMBARI-9133 - Views: min and max version (tbeerbower)

Repository: ambari
Updated Branches:
  refs/heads/trunk 7e33ea589 -> ddf020dd6


AMBARI-9133 - Views: min and max version (tbeerbower)


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

Branch: refs/heads/trunk
Commit: ddf020dd6102b1918a0d9e1c669f3e54765cd344
Parents: 7e33ea5
Author: tbeerbower <tb...@hortonworks.com>
Authored: Mon Jan 19 13:57:48 2015 -0500
Committer: tbeerbower <tb...@hortonworks.com>
Committed: Mon Jan 19 13:57:58 2015 -0500

----------------------------------------------------------------------
 .../internal/ViewVersionResourceProvider.java   |   8 +
 .../ambari/server/orm/entities/ViewEntity.java  |  11 +-
 .../apache/ambari/server/view/ViewRegistry.java |  95 ++++++++++--
 .../server/view/configuration/ViewConfig.java   |  30 ++++
 .../AmbariPrivilegeResourceProviderTest.java    |   2 +-
 .../ViewPrivilegeResourceProviderTest.java      |   2 +-
 .../server/orm/entities/ViewEntityTest.java     |  13 +-
 .../ambari/server/view/ViewRegistryTest.java    | 149 +++++++++++++++++--
 .../view/configuration/ViewConfigTest.java      |  26 ++++
 ambari-views/src/main/resources/view.xsd        |  10 ++
 10 files changed, 317 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
index 58cf774..95703fd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
@@ -49,6 +49,8 @@ public class ViewVersionResourceProvider extends AbstractResourceProvider {
   public static final String LABEL_PROPERTY_ID              = "ViewVersionInfo/label";
   public static final String DESCRIPTION_PROPERTY_ID        = "ViewVersionInfo/description";
   public static final String VERSION_PROPERTY_ID            = "ViewVersionInfo/version";
+  public static final String MIN_AMBARI_VERSION_PROPERTY_ID = "ViewVersionInfo/min_ambari_version";
+  public static final String MAX_AMBARI_VERSION_PROPERTY_ID = "ViewVersionInfo/max_ambari_version";
   public static final String PARAMETERS_PROPERTY_ID         = "ViewVersionInfo/parameters";
   public static final String ARCHIVE_PROPERTY_ID            = "ViewVersionInfo/archive";
   public static final String MASKER_CLASS_PROPERTY_ID       = "ViewVersionInfo/masker_class";
@@ -75,6 +77,8 @@ public class ViewVersionResourceProvider extends AbstractResourceProvider {
     propertyIds.add(LABEL_PROPERTY_ID);
     propertyIds.add(DESCRIPTION_PROPERTY_ID);
     propertyIds.add(VERSION_PROPERTY_ID);
+    propertyIds.add(MIN_AMBARI_VERSION_PROPERTY_ID);
+    propertyIds.add(MAX_AMBARI_VERSION_PROPERTY_ID);
     propertyIds.add(PARAMETERS_PROPERTY_ID);
     propertyIds.add(ARCHIVE_PROPERTY_ID);
     propertyIds.add(MASKER_CLASS_PROPERTY_ID);
@@ -131,6 +135,10 @@ public class ViewVersionResourceProvider extends AbstractResourceProvider {
             setResourceProperty(resource, LABEL_PROPERTY_ID, viewDefinition.getLabel(), requestedIds);
             setResourceProperty(resource, DESCRIPTION_PROPERTY_ID, viewDefinition.getDescription(), requestedIds);
             setResourceProperty(resource, VERSION_PROPERTY_ID, viewDefinition.getVersion(), requestedIds);
+            setResourceProperty(resource, MIN_AMBARI_VERSION_PROPERTY_ID,
+                viewDefinition.getConfiguration().getMinAmbariVersion(), requestedIds);
+            setResourceProperty(resource, MAX_AMBARI_VERSION_PROPERTY_ID,
+                viewDefinition.getConfiguration().getMaxAmbariVersion(), requestedIds);
             setResourceProperty(resource, PARAMETERS_PROPERTY_ID,
                 viewDefinition.getConfiguration().getParameters(), requestedIds);
             setResourceProperty(resource, ARCHIVE_PROPERTY_ID, viewDefinition.getArchive(), requestedIds);

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
index 2f83e02..f77c97e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
@@ -161,7 +161,7 @@ public class ViewEntity implements ViewDefinition {
    * The associated view configuration.
    */
   @Transient
-  private final ViewConfig configuration;
+  private ViewConfig configuration;
 
   /**
    * The Ambari configuration properties.
@@ -685,6 +685,15 @@ public class ViewEntity implements ViewDefinition {
   }
 
   /**
+   * Set the view configuration.
+   *
+   * @param configuration  the view configuration
+   */
+  public void setConfiguration(ViewConfig configuration) {
+    this.configuration = configuration;
+  }
+
+  /**
    * Get the associated view configuration.
    *
    * @return the configuration

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 05f9ce1..e422a46 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -26,6 +26,7 @@ import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
 import org.apache.ambari.server.api.resources.SubResourceDefinition;
 import org.apache.ambari.server.api.resources.ViewExternalSubResourceDefinition;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.ViewExternalSubResourceService;
 import org.apache.ambari.server.api.services.ViewSubResourceService;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
@@ -57,6 +58,7 @@ import org.apache.ambari.server.orm.entities.ViewParameterEntity;
 import org.apache.ambari.server.orm.entities.ViewResourceEntity;
 import org.apache.ambari.server.security.SecurityHelper;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.utils.VersionUtils;
 import org.apache.ambari.server.view.configuration.EntityConfig;
 import org.apache.ambari.server.view.configuration.InstanceConfig;
 import org.apache.ambari.server.view.configuration.ParameterConfig;
@@ -80,6 +82,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.security.core.GrantedAuthority;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 import javax.inject.Singleton;
 import java.beans.IntrospectionException;
 import java.io.File;
@@ -110,6 +113,7 @@ public class ViewRegistry {
   private static final String ALL_VIEWS_REG_EXP = ".*";
   protected static final int DEFAULT_REQUEST_CONNECT_TIMEOUT = 5000;
   protected static final int DEFAULT_REQUEST_READ_TIMEOUT    = 10000;
+  private static final String VIEW_AMBARI_VERSION_REGEXP = "^((\\d+\\.)?)*(\\*|\\d+)$";
 
   /**
    * Thread pool
@@ -204,6 +208,12 @@ public class ViewRegistry {
   ResourceTypeDAO resourceTypeDAO;
 
   /**
+   * Ambari meta info.
+   */
+  @Inject
+  Provider<AmbariMetaInfo> ambariMetaInfo;
+
+  /**
    * Ambari configuration.
    */
   @Inject
@@ -826,10 +836,11 @@ public class ViewRegistry {
   }
 
   // setup the given view definition
-  protected ViewEntity setupViewDefinition(ViewEntity viewDefinition, ViewConfig viewConfig,
-                                           ClassLoader cl)
+  protected ViewEntity setupViewDefinition(ViewEntity viewDefinition, ClassLoader cl)
       throws ClassNotFoundException, IntrospectionException {
 
+    ViewConfig viewConfig = viewDefinition.getConfiguration();
+
     viewDefinition.setClassLoader(cl);
 
     List<ParameterConfig> parameterConfigurations = viewConfig.getParameters();
@@ -1275,6 +1286,8 @@ public class ViewRegistry {
 
           Set<Runnable> extractionRunnables = new HashSet<Runnable>();
 
+          final String serverVersion = ambariMetaInfo.get().getServerVersion();
+
           for (final File archiveFile : files) {
             if (!archiveFile.isDirectory()) {
 
@@ -1302,13 +1315,13 @@ public class ViewRegistry {
                 // always load system views up front
                 if (systemView || !useExecutor || extractedArchiveDirFile.exists()) {
                   // if the archive is already extracted then load the view now
-                  readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile);
+                  readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile, serverVersion);
                 } else {
                   // if the archive needs to be extracted then create a runnable to do it
                   extractionRunnables.add(new Runnable() {
                     @Override
                     public void run() {
-                      readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile);
+                      readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile, serverVersion);
                     }
                   });
                 }
@@ -1340,7 +1353,8 @@ public class ViewRegistry {
   // read a view archive
   private void readViewArchive(ViewEntity viewDefinition,
                                File archiveFile,
-                               File extractedArchiveDirFile) {
+                               File extractedArchiveDirFile,
+                               String serverVersion) {
 
     setViewStatus(viewDefinition, ViewEntity.ViewStatus.DEPLOYING, "Deploying " + extractedArchiveDirFile + ".");
 
@@ -1353,19 +1367,22 @@ public class ViewRegistry {
       ViewConfig viewConfig = archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath,
           configuration.isViewValidationEnabled());
 
-      setupViewDefinition(viewDefinition, viewConfig, cl);
+      viewDefinition.setConfiguration(viewConfig);
 
-      Set<ViewInstanceEntity> instanceDefinitions = new HashSet<ViewInstanceEntity>();
+      if (checkViewVersions(viewDefinition, serverVersion)) {
+        setupViewDefinition(viewDefinition, cl);
 
-      for (InstanceConfig instanceConfig : viewConfig.getInstances()) {
-        ViewInstanceEntity instanceEntity = createViewInstanceDefinition(viewConfig, viewDefinition, instanceConfig);
-        instanceEntity.setXmlDriven(true);
-        instanceDefinitions.add(instanceEntity);
-      }
-      persistView(viewDefinition, instanceDefinitions);
+        Set<ViewInstanceEntity> instanceDefinitions = new HashSet<ViewInstanceEntity>();
 
-      setViewStatus(viewDefinition, ViewEntity.ViewStatus.DEPLOYED, "Deployed " + extractedArchiveDirPath + ".");
+        for (InstanceConfig instanceConfig : viewConfig.getInstances()) {
+          ViewInstanceEntity instanceEntity = createViewInstanceDefinition(viewConfig, viewDefinition, instanceConfig);
+          instanceEntity.setXmlDriven(true);
+          instanceDefinitions.add(instanceEntity);
+        }
+        persistView(viewDefinition, instanceDefinitions);
 
+        setViewStatus(viewDefinition, ViewEntity.ViewStatus.DEPLOYED, "Deployed " + extractedArchiveDirPath + ".");
+      }
     } catch (Exception e) {
       String msg = "Caught exception loading view " + viewDefinition.getName();
 
@@ -1374,6 +1391,56 @@ public class ViewRegistry {
     }
   }
 
+  /**
+   * Check the configured view max and min Ambari versions for the given view entity
+   * against the given Ambari server version.
+   *
+   * @param view           the view
+   * @param serverVersion  the server version
+   *
+   * @return true if the given server version >= min version && <= max version for the given view
+   */
+  protected boolean checkViewVersions(ViewEntity view, String serverVersion) {
+    ViewConfig config = view.getConfiguration();
+
+    return checkViewVersion(view, config.getMinAmbariVersion(), serverVersion, "minimum", 1, "less than") &&
+           checkViewVersion(view, config.getMaxAmbariVersion(), serverVersion, "maximum", -1, "greater than");
+
+  }
+
+  // check the given version against the actual Ambari server version
+  private boolean checkViewVersion(ViewEntity view, String version, String serverVersion, String label,
+                                   int errValue, String errMsg) {
+
+    if (version != null && !version.isEmpty()) {
+
+      // make sure that the given version is a valid version string
+      if (!version.matches(VIEW_AMBARI_VERSION_REGEXP)) {
+        String msg = "The configured " + label + " Ambari version " + version + " for view " +
+            view.getName() + " is not valid.";
+
+        setViewStatus(view, ViewEntity.ViewStatus.ERROR, msg);
+        LOG.error(msg);
+        return false;
+      }
+
+      int index = version.indexOf('*');
+
+      int compVal = index == -1 ? VersionUtils.compareVersions(version, serverVersion) :
+                    index > 0 ? VersionUtils.compareVersions(version.substring(0, index), serverVersion, index) : 0;
+
+      if (compVal == errValue) {
+        String msg = "The Ambari server version " + serverVersion + " is " + errMsg + " the configured " + label +
+            " Ambari version " + version + " for view " + view.getName();
+
+        setViewStatus(view, ViewEntity.ViewStatus.ERROR, msg);
+        LOG.error(msg);
+        return false;
+      }
+    }
+    return true;
+  }
+
   // persist the given view and its instances
   @Transactional
   private void persistView(ViewEntity viewDefinition, Set<ViewInstanceEntity> instanceDefinitions) throws Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
index ea04a21..c617b7f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
@@ -59,6 +59,18 @@ public class ViewConfig {
   private String version;
 
   /**
+   * The minimum Ambari version.
+   */
+  @XmlElement(name="min-ambari-version")
+  private String minAmbariVersion;
+
+  /**
+   * The maximum Ambari version.
+   */
+  @XmlElement(name="max-ambari-version")
+  private String maxAmbariVersion;
+
+  /**
    * The icon path in the view archive.
    */
   private String icon;
@@ -173,6 +185,24 @@ public class ViewConfig {
   }
 
   /**
+   * Get the minimum version of Ambari required to run this view.
+   *
+   * @return the minimum Ambari version
+   */
+  public String getMinAmbariVersion() {
+    return minAmbariVersion;
+  }
+
+  /**
+   * Get the maximum version of Ambari that can run this view.
+   *
+   * @return the maximum Ambari version
+   */
+  public String getMaxAmbariVersion() {
+    return maxAmbariVersion;
+  }
+
+  /**
    * Get the icon path in the view archive.
    *
    * @return the icon path

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariPrivilegeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariPrivilegeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariPrivilegeResourceProviderTest.java
index b9e56ee..a6536c7 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariPrivilegeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariPrivilegeResourceProviderTest.java
@@ -98,7 +98,7 @@ public class AmbariPrivilegeResourceProviderTest {
   @Before
   public void resetGlobalMocks() {
     ViewRegistry.initInstance(ViewRegistryTest.getRegistry(viewDAO, viewInstanceDAO, userDAO,
-        memberDAO, privilegeDAO, resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null));
+        memberDAO, privilegeDAO, resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, null));
     reset(privilegeDAO, userDAO, groupDAO, principalDAO, permissionDAO, resourceDAO, clusterDAO, handlerList);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProviderTest.java
index e1a4da3..ed8aed0 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProviderTest.java
@@ -90,7 +90,7 @@ public class ViewPrivilegeResourceProviderTest {
   public void resetGlobalMocks() {
 
     ViewRegistry.initInstance(ViewRegistryTest.getRegistry(viewDAO, viewInstanceDAO, userDAO,
-        memberDAO, privilegeDAO, resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null));
+        memberDAO, privilegeDAO, resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, null));
     reset(privilegeDAO, userDAO, groupDAO, principalDAO, permissionDAO, resourceDAO, handlerList);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewEntityTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewEntityTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewEntityTest.java
index f93403d..a9ceb93 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewEntityTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewEntityTest.java
@@ -47,6 +47,13 @@ import static org.easymock.EasyMock.verify;
  */
 public class ViewEntityTest {
 
+  private static String with_ambari_versions = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <version>1.0.0</version>\n" +
+      "    <min-ambari-version>1.6.1</min-ambari-version>\n" +
+      "    <max-ambari-version>2.0.0</max-ambari-version>\n" +
+      "</view>";
 
   public static ViewEntity getViewEntity() throws Exception {
     return getViewEntity(ViewConfigTest.getConfig());
@@ -122,10 +129,14 @@ public class ViewEntityTest {
   }
 
   @Test
-  public void testGetConfiguration() throws Exception {
+  public void testSetGetConfiguration() throws Exception {
     ViewConfig viewConfig = ViewConfigTest.getConfig();
     ViewEntity viewDefinition = getViewEntity(viewConfig);
     Assert.assertEquals(viewConfig, viewDefinition.getConfiguration());
+
+    ViewConfig newViewConfig = ViewConfigTest.getConfig(with_ambari_versions);
+    viewDefinition.setConfiguration(newViewConfig);
+    Assert.assertEquals(newViewConfig, viewDefinition.getConfiguration());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
index 203ea18..14dd4cf 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
@@ -50,8 +50,9 @@ import java.util.jar.JarInputStream;
 
 import javax.xml.bind.JAXBException;
 
-import junit.framework.TestListener;
+import com.google.inject.Provider;
 import org.apache.ambari.server.api.resources.SubResourceDefinition;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
@@ -172,15 +173,16 @@ public class ViewRegistryTest {
   private static final SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
   private static final Configuration configuration = createNiceMock(Configuration.class);
   private static final ViewInstanceHandlerList handlerList = createNiceMock(ViewInstanceHandlerList.class);
+  private static final AmbariMetaInfo ambariMetaInfo = createNiceMock(AmbariMetaInfo.class);
 
 
   @Before
   public void resetGlobalMocks() {
     ViewRegistry.initInstance(getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO,
-        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null));
+        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, ambariMetaInfo));
 
     reset(viewDAO, resourceDAO, viewInstanceDAO, userDAO, memberDAO,
-        privilegeDAO, resourceTypeDAO, securityHelper, configuration, handlerList);
+        privilegeDAO, resourceTypeDAO, securityHelper, configuration, handlerList, ambariMetaInfo);
   }
 
   @Test
@@ -333,7 +335,7 @@ public class ViewRegistryTest {
     TestViewArchiveUtility archiveUtility = new TestViewArchiveUtility(viewConfigs, files, outputStreams, jarFiles);
 
     ViewRegistry registry = getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO,
-        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, archiveUtility);
+        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, archiveUtility, ambariMetaInfo);
 
     registry.readViewArchives();
 
@@ -501,7 +503,7 @@ public class ViewRegistryTest {
     TestViewArchiveUtility archiveUtility = new TestViewArchiveUtility(viewConfigs, files, outputStreams, jarFiles);
 
     ViewRegistry registry = getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO,
-        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, archiveUtility);
+        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, archiveUtility, ambariMetaInfo);
 
     registry.readViewArchives();
 
@@ -603,7 +605,9 @@ public class ViewRegistryTest {
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
-    registry.setupViewDefinition(viewDefinition, config, getClass().getClassLoader());
+    viewDefinition.setConfiguration(config);
+
+    registry.setupViewDefinition(viewDefinition, getClass().getClassLoader());
 
     Map<Resource.Type, ResourceProvider> providerMap = registry.getResourceProviders();
 
@@ -682,7 +686,9 @@ public class ViewRegistryTest {
 
     ViewRegistry registry = ViewRegistry.getInstance();
 
-    registry.setupViewDefinition(viewDefinition, config, getClass().getClassLoader());
+    viewDefinition.setConfiguration(config);
+
+    registry.setupViewDefinition(viewDefinition, getClass().getClassLoader());
 
     Set<SubResourceDefinition> subResourceDefinitions =
         registry.getSubResourceDefinitions(viewDefinition.getCommonName(), viewDefinition.getVersion());
@@ -1245,6 +1251,117 @@ public class ViewRegistryTest {
   }
 
   @Test
+  public void testCheckViewVersions() {
+    ViewRegistry registry = ViewRegistry.getInstance();
+    ViewEntity viewEntity = createNiceMock(ViewEntity.class);
+
+    ViewConfig config = createNiceMock(ViewConfig.class);
+
+    expect(viewEntity.getConfiguration()).andReturn(config).anyTimes();
+
+    // null, null
+    expect(config.getMinAmbariVersion()).andReturn(null);
+    expect(config.getMaxAmbariVersion()).andReturn(null);
+
+    // 1.0.0, 3.0.0
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn("3.0.0");
+
+    // 1.0.0, 1.5
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn("1.5");
+
+    // 2.5
+    expect(config.getMinAmbariVersion()).andReturn("2.5");
+
+    // null, 3.0.0
+    expect(config.getMinAmbariVersion()).andReturn(null);
+    expect(config.getMaxAmbariVersion()).andReturn("3.0.0");
+
+    // 1.0.0, null
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn(null);
+
+    // 1.0.0, *
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn("*");
+
+    // *, 3.0.0
+    expect(config.getMinAmbariVersion()).andReturn("*");
+    expect(config.getMaxAmbariVersion()).andReturn("3.0.0");
+
+    // 1.0.0, 2.*
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn("2.*");
+
+    // 1.*, 3.0.0
+    expect(config.getMinAmbariVersion()).andReturn("1.*");
+    expect(config.getMaxAmbariVersion()).andReturn("3.0.0");
+
+    // 1.0.0, 2.1.*
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn("2.1.*");
+
+    // 1.5.*, 3.0.0
+    expect(config.getMinAmbariVersion()).andReturn("1.5.*");
+    expect(config.getMaxAmbariVersion()).andReturn("3.0.0");
+
+    // 1.0.0, 1.9.9.*
+    expect(config.getMinAmbariVersion()).andReturn("1.0.0");
+    expect(config.getMaxAmbariVersion()).andReturn("1.9.9.*");
+
+    // 2.0.0.1.*, 3.0.0
+    expect(config.getMinAmbariVersion()).andReturn("2.0.0.1.*");
+
+    replay(viewEntity, config);
+
+    // null, null
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, 3.0.0
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, 1.5
+    Assert.assertFalse(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 2.5, 3.0.0
+    Assert.assertFalse(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // null, 3.0.0
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, null
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, *
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // *, 3.0.0
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, 2.*
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.*, 3.0.0
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, 2.1.*
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.5.*, 3.0.0
+    Assert.assertTrue(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 1.0.0, 1.9.9.*
+    Assert.assertFalse(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    // 2.0.0.1.*, 3.0.0
+    Assert.assertFalse(registry.checkViewVersions(viewEntity, "2.0.0"));
+
+    verify(viewEntity, config);
+
+  }
+
+  @Test
   public void testExtractViewArchive() throws Exception {
 
     File viewDir = createNiceMock(File.class);
@@ -1436,7 +1553,9 @@ public class ViewRegistryTest {
                                          PrivilegeDAO privilegeDAO, ResourceDAO resourceDAO,
                                          ResourceTypeDAO resourceTypeDAO, SecurityHelper securityHelper,
                                          ViewInstanceHandlerList handlerList,
-                                         ViewExtractor viewExtractor, ViewArchiveUtility archiveUtility) {
+                                         ViewExtractor viewExtractor,
+                                         ViewArchiveUtility archiveUtility,
+                                         AmbariMetaInfo ambariMetaInfo) {
 
     ViewRegistry instance = new ViewRegistry();
 
@@ -1454,6 +1573,14 @@ public class ViewRegistryTest {
     instance.archiveUtility = archiveUtility == null ? new ViewArchiveUtility() : archiveUtility;
     instance.extractor.archiveUtility = instance.archiveUtility;
 
+    final AmbariMetaInfo finalMetaInfo = ambariMetaInfo;
+    instance.ambariMetaInfo = new Provider<AmbariMetaInfo>() {
+      @Override
+      public AmbariMetaInfo get() {
+        return finalMetaInfo;
+      }
+    };
+
     return instance;
   }
 
@@ -1461,11 +1588,11 @@ public class ViewRegistryTest {
                                      ClassLoader cl, String archivePath) throws Exception{
 
     ViewRegistry registry = getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO,
-        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null);
+        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, null);
 
     ViewEntity viewDefinition = new ViewEntity(viewConfig, ambariConfig, archivePath);
 
-    registry.setupViewDefinition(viewDefinition, viewConfig, cl);
+    registry.setupViewDefinition(viewDefinition, cl);
 
     return viewDefinition;
   }
@@ -1473,7 +1600,7 @@ public class ViewRegistryTest {
   public static ViewInstanceEntity getViewInstanceEntity(ViewEntity viewDefinition, InstanceConfig instanceConfig) throws Exception {
 
     ViewRegistry registry = getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO,
-        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null);
+        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, null);
 
     ViewInstanceEntity viewInstanceDefinition =
         new ViewInstanceEntity(viewDefinition, instanceConfig);

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
index 50a1223..75ab10a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
@@ -139,6 +139,14 @@ public class ViewConfigTest {
       "    <system>false</system>\n" +
       "</view>";
 
+  private static String with_ambari_versions = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <version>1.0.0</version>\n" +
+      "    <min-ambari-version>1.6.1</min-ambari-version>\n" +
+      "    <max-ambari-version>2.0.0</max-ambari-version>\n" +
+      "</view>";
+
   @Test
   public void testGetName() throws Exception {
     ViewConfig config = getConfig();
@@ -247,6 +255,24 @@ public class ViewConfigTest {
     Assert.assertFalse(config.isSystem());
   }
 
+  @Test
+  public void testGetMinAmbariVersion() throws Exception {
+    ViewConfig config = getConfig();
+    Assert.assertNull(config.getMinAmbariVersion());
+
+    config = getConfig(with_ambari_versions);
+    Assert.assertEquals("1.6.1", config.getMinAmbariVersion());
+  }
+
+  @Test
+  public void testGetMaxAmbariVersion() throws Exception {
+    ViewConfig config = getConfig();
+    Assert.assertNull(config.getMaxAmbariVersion());
+
+    config = getConfig(with_ambari_versions);
+    Assert.assertEquals("2.0.0", config.getMaxAmbariVersion());
+  }
+
   public static  ViewConfig getConfig() throws JAXBException {
       return getConfig(xml);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ddf020dd/ambari-views/src/main/resources/view.xsd
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/resources/view.xsd b/ambari-views/src/main/resources/view.xsd
index f4d65c4..e994faf 100644
--- a/ambari-views/src/main/resources/view.xsd
+++ b/ambari-views/src/main/resources/view.xsd
@@ -235,6 +235,16 @@
             <xs:documentation>The version of the view.</xs:documentation>
           </xs:annotation>
         </xs:element>
+        <xs:element type="xs:string" name="min-ambari-version" minOccurs="0" maxOccurs="1">
+          <xs:annotation>
+            <xs:documentation>The minimum version of Ambari server required to run this view.</xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element type="xs:string" name="max-ambari-version" minOccurs="0" maxOccurs="1">
+          <xs:annotation>
+            <xs:documentation>The maximum version of Ambari server that can run this view.</xs:documentation>
+          </xs:annotation>
+        </xs:element>
         <xs:element type="xs:string" name="description" minOccurs="0" maxOccurs="1">
           <xs:annotation>
             <xs:documentation>The description of the view.</xs:documentation>