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/04/14 01:24:03 UTC

ambari git commit: AMBARI-10424 - Views : Auto create (tbeerbower)

Repository: ambari
Updated Branches:
  refs/heads/trunk 68dbaa64f -> 5a60fa18a


AMBARI-10424 - Views : Auto create (tbeerbower)


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

Branch: refs/heads/trunk
Commit: 5a60fa18a58ec1c38cdde625adb2b7e61eaf936b
Parents: 68dbaa6
Author: tbeerbower <tb...@hortonworks.com>
Authored: Mon Apr 13 19:23:28 2015 -0400
Committer: tbeerbower <tb...@hortonworks.com>
Committed: Mon Apr 13 19:23:48 2015 -0400

----------------------------------------------------------------------
 .../apache/ambari/server/view/ViewRegistry.java | 128 +++++++++++++++-
 .../view/configuration/AutoInstanceConfig.java  |  65 ++++++++
 .../server/view/configuration/ViewConfig.java   |  15 ++
 .../server/api/handlers/CreateHandlerTest.java  |   5 +-
 .../server/api/handlers/DeleteHandlerTest.java  |   5 +-
 .../server/api/handlers/UpdateHandlerTest.java  |   5 +-
 .../resources/BaseResourceDefinitionTest.java   |   5 +-
 .../internal/UpgradeResourceProviderTest.java   |   7 +-
 .../ambari/server/view/ViewRegistryTest.java    | 153 ++++++++++++++++++-
 .../configuration/AutoInstanceConfigTest.java   | 116 ++++++++++++++
 .../view/configuration/ViewConfigTest.java      |  24 +++
 ambari-views/src/main/resources/view.xsd        |  37 +++++
 12 files changed, 553 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/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 1ae1dfd..1564dd1 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
@@ -19,6 +19,8 @@
 package org.apache.ambari.server.view;
 
 import com.google.common.collect.Sets;
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -38,6 +40,8 @@ import org.apache.ambari.server.controller.AmbariSessionManager;
 import org.apache.ambari.server.controller.ControllerModule;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.events.ServiceInstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.MemberDAO;
 import org.apache.ambari.server.orm.dao.PrivilegeDAO;
 import org.apache.ambari.server.orm.dao.ResourceDAO;
@@ -62,7 +66,9 @@ 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.state.Clusters;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.utils.VersionUtils;
+import org.apache.ambari.server.view.configuration.AutoInstanceConfig;
 import org.apache.ambari.server.view.configuration.EntityConfig;
 import org.apache.ambari.server.view.configuration.InstanceConfig;
 import org.apache.ambari.server.view.configuration.ParameterConfig;
@@ -257,7 +263,18 @@ public class ViewRegistry {
   AmbariSessionManager ambariSessionManager;
 
 
-  // ----- ViewRegistry ------------------------------------------------------
+ // ----- Constructors -----------------------------------------------------
+
+  /**
+   * Create the view registry.
+   */
+  @Inject
+  public ViewRegistry(AmbariEventPublisher publisher) {
+    publisher.register(this);
+  }
+
+
+// ----- ViewRegistry ------------------------------------------------------
 
   /**
    * Registry main method.
@@ -843,9 +860,104 @@ public class ViewRegistry {
     return null;
   }
 
+  /**
+   * Receive notification that a new service has been added to a cluster.
+   * </p>
+   * Used for view instance auto creation.
+   *
+   * @param event  the service installed event
+   */
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onAmbariEvent(ServiceInstalledEvent event) {
+
+    Clusters clusters  = clustersProvider.get();
+    Long     clusterId = event.getClusterId();
+
+    try {
+      org.apache.ambari.server.state.Cluster cluster = clusters.getClusterById(clusterId);
+      String clusterName = cluster.getClusterName();
+
+      StackId     stackId       = cluster.getCurrentStackVersion();
+      Set<String> serviceNames  = cluster.getServices().keySet();
+
+      for (ViewEntity viewEntity : getDefinitions()) {
+
+        String             viewName   = viewEntity.getName();
+        ViewConfig         viewConfig = viewEntity.getConfiguration();
+        AutoInstanceConfig autoConfig = viewConfig.getAutoInstance();
+
+        try {
+          if (checkAutoInstanceConfig(autoConfig, stackId, event.getServiceName(), serviceNames)) {
+
+            LOG.info("Auto creating instance of view " + viewName + " for cluster " + clusterName + ".");
+            ViewInstanceEntity viewInstanceEntity = createViewInstanceEntity(viewEntity, viewConfig, autoConfig);
+            viewInstanceEntity.setClusterHandle(clusterName);
+            installViewInstance(viewInstanceEntity);
+          }
+        } catch (Exception e) {
+          LOG.error("Can't auto create instance of view " + viewName + " for cluster " + clusterName +
+              ".  Caught exception :" + e.getMessage(), e);
+        }
+      }
+    } catch (AmbariException e) {
+      LOG.warn("Unknown cluster id " + clusterId + ".");
+    }
+  }
+
+
   // ----- helper methods ----------------------------------------------------
 
   /**
+   * Determine whether a new view instance should be automatically created and associated with
+   * a cluster based on the given configuration and cluster state.
+   *
+   * @param autoConfig    the view instance auto creation configuration
+   * @param stackId       the stack id of the cluster
+   * @param serviceName   the name of the service added which triggered this check
+   * @param serviceNames  the set of service names of the cluster
+   *
+   * @return true if a new view instance should be created
+   */
+  private boolean checkAutoInstanceConfig(AutoInstanceConfig autoConfig, StackId stackId,
+                                          String serviceName, Set<String> serviceNames) {
+
+    if (autoConfig != null) {
+      List<String> autoCreateServices = autoConfig.getServices();
+
+      if (autoCreateServices != null && autoCreateServices.contains(serviceName) &&
+          serviceNames.containsAll(autoCreateServices)) {
+
+        String configStackId = autoConfig.getStackId();
+
+        if (configStackId != null) {
+          StackId id = new StackId(configStackId);
+
+          if (id.getStackName().equals(stackId.getStackName())) {
+
+            String stackVersion       = stackId.getStackVersion();
+            String configStackVersion = id.getStackVersion();
+
+            // make sure that the configured stack version equals the cluster stack version (account for *)
+            int compVal = 0;
+
+            int index = configStackVersion.indexOf('*');
+            if (index == -1) {
+              compVal = VersionUtils.compareVersions(configStackVersion, stackVersion);
+            } else  if (index > 0) {
+              String[] parts = configStackVersion.substring(0, index).split("\\.");
+              compVal = VersionUtils.compareVersions(configStackVersion, stackVersion, parts.length);
+            }
+
+            return compVal == 0;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
    * Clear the registry.
    */
   protected void clear() {
@@ -992,6 +1104,17 @@ public class ViewRegistry {
   protected ViewInstanceEntity createViewInstanceDefinition(ViewConfig viewConfig, ViewEntity viewDefinition,
                                                             InstanceConfig instanceConfig)
       throws ValidationException, ClassNotFoundException, SystemException {
+    ViewInstanceEntity viewInstanceDefinition = createViewInstanceEntity(viewDefinition, viewConfig, instanceConfig);
+    viewInstanceDefinition.validate(viewDefinition, Validator.ValidationContext.PRE_CREATE);
+
+    bindViewInstance(viewDefinition, viewInstanceDefinition);
+    return viewInstanceDefinition;
+  }
+
+  // create a view instance from the given configuration
+  private ViewInstanceEntity createViewInstanceEntity(ViewEntity viewDefinition, ViewConfig viewConfig,
+                                                      InstanceConfig instanceConfig)
+      throws SystemException {
     ViewInstanceEntity viewInstanceDefinition =
         new ViewInstanceEntity(viewDefinition, instanceConfig);
 
@@ -1001,9 +1124,6 @@ public class ViewRegistry {
       properties.put(propertyConfig.getKey(), propertyConfig.getValue());
     }
     setViewInstanceProperties(viewInstanceDefinition, properties, viewConfig, viewDefinition.getClassLoader());
-    viewInstanceDefinition.validate(viewDefinition, Validator.ValidationContext.PRE_CREATE);
-
-    bindViewInstance(viewDefinition, viewInstanceDefinition);
     return viewInstanceDefinition;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/AutoInstanceConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/AutoInstanceConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/AutoInstanceConfig.java
new file mode 100644
index 0000000..e837464
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/AutoInstanceConfig.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view.configuration;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import java.util.List;
+
+/**
+ * View auto instance configuration.
+ * </p>
+ * Used by Ambari to automatically create an instance of a view and associate it with
+ * a cluster if the cluster's stack and services match those given in this configuration.
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class AutoInstanceConfig extends InstanceConfig {
+  /**
+   * The stack id.
+   */
+  @XmlElement(name="stack-id")
+  private String stackId;
+
+  /**
+   * The list of view instances.
+   */
+  @XmlElementWrapper
+  @XmlElement(name="service")
+  private List<String> services;
+
+  /**
+   * Get the stack id used for auto instance creation.
+   *
+   * @return the stack id
+   */
+  public String getStackId() {
+    return stackId;
+  }
+
+  /**
+   * Get the services used for auto instance creation.
+   *
+   * @return the services
+   */
+  public List<String> getServices() {
+    return services;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/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 c617b7f..6164bb7 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
@@ -131,6 +131,12 @@ public class ViewConfig {
   private List<ResourceConfig> resources;
 
   /**
+   * The view instance auto create configuration.
+   */
+  @XmlElement(name="auto-instance")
+  private AutoInstanceConfig autoInstance;
+
+  /**
    * The list of view instances.
    */
   @XmlElement(name="instance")
@@ -326,6 +332,15 @@ public class ViewConfig {
   }
 
   /**
+   * Get the configuration for the view instance auto create.
+   *
+   * @return the view instance auto create; null if no auto instance is specified
+   */
+  public AutoInstanceConfig getAutoInstance() {
+    return autoInstance;
+  }
+
+  /**
    * Get the list of view instances.
    *
    * @return the list of view instances

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/CreateHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/CreateHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/CreateHandlerTest.java
index 87c07c8..2b50064 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/CreateHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/CreateHandlerTest.java
@@ -28,6 +28,7 @@ import org.apache.ambari.server.api.services.persistence.PersistenceManager;
 import org.apache.ambari.server.api.util.TreeNode;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.view.ViewRegistry;
 import org.junit.Before;
 import org.junit.Test;
@@ -44,7 +45,9 @@ public class CreateHandlerTest {
 
   @Before
   public void before() {
-    ViewRegistry.initInstance(new ViewRegistry());
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
+    replay(publisher);
+    ViewRegistry.initInstance(new ViewRegistry(publisher));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/DeleteHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/DeleteHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/DeleteHandlerTest.java
index 7e19129..4f053fd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/DeleteHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/DeleteHandlerTest.java
@@ -31,6 +31,7 @@ import org.apache.ambari.server.api.util.TreeNode;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.view.ViewRegistry;
 import org.junit.Before;
 import org.junit.Test;
@@ -50,7 +51,9 @@ public class DeleteHandlerTest {
 
   @Before
   public void before() {
-    ViewRegistry.initInstance(new ViewRegistry());
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
+    replay(publisher);
+    ViewRegistry.initInstance(new ViewRegistry(publisher));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/UpdateHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/UpdateHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/UpdateHandlerTest.java
index 5ef3e53..c88a0ec 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/UpdateHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/handlers/UpdateHandlerTest.java
@@ -28,6 +28,7 @@ import org.apache.ambari.server.api.util.TreeNode;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.view.ViewRegistry;
 import org.junit.Before;
 import org.junit.Test;
@@ -44,7 +45,9 @@ public class UpdateHandlerTest {
 
   @Before
   public void before() {
-    ViewRegistry.initInstance(new ViewRegistry());
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
+    replay(publisher);
+    ViewRegistry.initInstance(new ViewRegistry(publisher));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/test/java/org/apache/ambari/server/api/resources/BaseResourceDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/BaseResourceDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/BaseResourceDefinitionTest.java
index da3fe3f..3f64d9a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/BaseResourceDefinitionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/BaseResourceDefinitionTest.java
@@ -42,6 +42,7 @@ import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.view.ViewRegistry;
 import org.junit.Assert;
@@ -62,7 +63,9 @@ public class BaseResourceDefinitionTest {
 
   @Before
   public void before() {
-    ViewRegistry.initInstance(new ViewRegistry());
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
+    replay(publisher);
+    ViewRegistry.initInstance(new ViewRegistry(publisher));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
index baa885c..d2f7f80 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
@@ -17,7 +17,9 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -44,6 +46,7 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
@@ -125,7 +128,9 @@ public class UpgradeResourceProviderTest {
     upgradeDao = injector.getInstance(UpgradeDAO.class);
     repoVersionDao = injector.getInstance(RepositoryVersionDAO.class);
 
-    ViewRegistry.initInstance(new ViewRegistry());
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
+    replay(publisher);
+    ViewRegistry.initInstance(new ViewRegistry(publisher));
 
     RepositoryVersionEntity repoVersionEntity = new RepositoryVersionEntity();
     repoVersionEntity.setDisplayName("My New Version 1");

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/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 3a57b1b..1b7c9a5 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
@@ -56,6 +56,8 @@ 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;
+import org.apache.ambari.server.events.ServiceInstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.MemberDAO;
 import org.apache.ambari.server.orm.dao.PrivilegeDAO;
 import org.apache.ambari.server.orm.dao.ResourceDAO;
@@ -76,6 +78,10 @@ import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntityTest;
 import org.apache.ambari.server.security.SecurityHelper;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.view.configuration.InstanceConfig;
 import org.apache.ambari.server.view.configuration.InstanceConfigTest;
 import org.apache.ambari.server.view.configuration.PropertyConfig;
@@ -162,6 +168,39 @@ public class ViewRegistryTest {
       "    </instance>\n" +
       "</view>";
 
+  private static String AUTO_VIEW_XML = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <version>1.0.0</version>\n" +
+      "    <auto-instance>\n" +
+      "        <name>AUTO-INSTANCE</name>\n" +
+      "        <stack-id>HDP-2.0</stack-id>\n" +
+      "        <services><service>HIVE</service><service>HDFS</service></services>\n" +
+      "    </auto-instance>\n" +
+      "</view>";
+
+  private static String AUTO_VIEW_WILD_STACK_XML = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <version>1.0.0</version>\n" +
+      "    <auto-instance>\n" +
+      "        <name>AUTO-INSTANCE</name>\n" +
+      "        <stack-id>HDP-2.*</stack-id>\n" +
+      "        <services><service>HIVE</service><service>HDFS</service></services>\n" +
+      "    </auto-instance>\n" +
+      "</view>";
+
+  private static String AUTO_VIEW_BAD_STACK_XML = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <version>1.0.0</version>\n" +
+      "    <auto-instance>\n" +
+      "        <name>AUTO-INSTANCE</name>\n" +
+      "        <stack-id>HDP-2.5</stack-id>\n" +
+      "        <services><service>HIVE</service><service>HDFS</service></services>\n" +
+      "    </auto-instance>\n" +
+      "</view>";
+
   // registry mocks
   private static final ViewDAO viewDAO = createMock(ViewDAO.class);
   private static final ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
@@ -174,15 +213,17 @@ public class ViewRegistryTest {
   private static final Configuration configuration = createNiceMock(Configuration.class);
   private static final ViewInstanceHandlerList handlerList = createNiceMock(ViewInstanceHandlerList.class);
   private static final AmbariMetaInfo ambariMetaInfo = createNiceMock(AmbariMetaInfo.class);
+  private static final Clusters clusters = createNiceMock(Clusters.class);
 
 
   @Before
   public void resetGlobalMocks() {
     ViewRegistry.initInstance(getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO,
-        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, ambariMetaInfo));
+        resourceDAO, resourceTypeDAO, securityHelper, handlerList, null, null, ambariMetaInfo, clusters));
 
     reset(viewDAO, resourceDAO, viewInstanceDAO, userDAO, memberDAO,
-        privilegeDAO, resourceTypeDAO, securityHelper, configuration, handlerList, ambariMetaInfo);
+        privilegeDAO, resourceTypeDAO, securityHelper, configuration, handlerList, ambariMetaInfo,
+        clusters);
   }
 
 
@@ -1265,6 +1306,42 @@ public class ViewRegistryTest {
   }
 
   @Test
+  public void testOnAmbariEventServiceCreation() throws Exception {
+    Set<String> serviceNames = new HashSet<String>();
+    serviceNames.add("HDFS");
+    serviceNames.add("HIVE");
+
+    testOnAmbariEventServiceCreation(AUTO_VIEW_XML, serviceNames, true);
+  }
+
+  @Test
+  public void testOnAmbariEventServiceCreation_widcardStackVersion() throws Exception {
+    Set<String> serviceNames = new HashSet<String>();
+    serviceNames.add("HDFS");
+    serviceNames.add("HIVE");
+
+    testOnAmbariEventServiceCreation(AUTO_VIEW_WILD_STACK_XML, serviceNames, true);
+  }
+
+  @Test
+  public void testOnAmbariEventServiceCreation_mismatchStackVersion() throws Exception {
+    Set<String> serviceNames = new HashSet<String>();
+    serviceNames.add("HDFS");
+    serviceNames.add("HIVE");
+
+    testOnAmbariEventServiceCreation(AUTO_VIEW_BAD_STACK_XML, serviceNames, false);
+  }
+
+  @Test
+  public void testOnAmbariEventServiceCreation_missingClusterService() throws Exception {
+    Set<String> serviceNames = new HashSet<String>();
+    serviceNames.add("STORM");
+    serviceNames.add("HIVE");
+
+    testOnAmbariEventServiceCreation(AUTO_VIEW_XML, serviceNames, false);
+  }
+
+  @Test
   public void testIncludeDefinitionForNoApiAuthentication() {
     ViewRegistry registry = ViewRegistry.getInstance();
     ViewEntity viewEntity = createNiceMock(ViewEntity.class);
@@ -1599,8 +1676,27 @@ public class ViewRegistryTest {
                                          ViewExtractor viewExtractor,
                                          ViewArchiveUtility archiveUtility,
                                          AmbariMetaInfo ambariMetaInfo) {
+    return getRegistry(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, resourceDAO, resourceTypeDAO,
+        securityHelper, handlerList, viewExtractor, archiveUtility, ambariMetaInfo, null);
+  }
+
+  public static ViewRegistry getRegistry(ViewDAO viewDAO, ViewInstanceDAO viewInstanceDAO,
+                                         UserDAO userDAO, MemberDAO memberDAO,
+                                         PrivilegeDAO privilegeDAO, ResourceDAO resourceDAO,
+                                         ResourceTypeDAO resourceTypeDAO, SecurityHelper securityHelper,
+                                         ViewInstanceHandlerList handlerList,
+                                         ViewExtractor viewExtractor,
+                                         ViewArchiveUtility archiveUtility,
+                                         AmbariMetaInfo ambariMetaInfo,
+                                         Clusters clusters) {
+
+
+
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
+    replay(publisher);
 
-    ViewRegistry instance = new ViewRegistry();
+
+    ViewRegistry instance = new ViewRegistry(publisher);
 
     instance.viewDAO = viewDAO;
     instance.resourceDAO = resourceDAO;
@@ -1624,6 +1720,13 @@ public class ViewRegistryTest {
       }
     };
 
+    final Clusters finalClusters = clusters;
+    instance.clustersProvider = new Provider<Clusters>() {
+      @Override
+      public Clusters get() {
+        return finalClusters;
+      }
+    };
     return instance;
   }
 
@@ -1655,4 +1758,48 @@ public class ViewRegistryTest {
     registry.bindViewInstance(viewDefinition, viewInstanceDefinition);
     return viewInstanceDefinition;
   }
+
+  private void testOnAmbariEventServiceCreation(String xml, Set<String> serviceNames, boolean success) throws Exception {
+    ViewConfig config = ViewConfigTest.getConfig(xml);
+
+    ViewEntity viewDefinition = ViewEntityTest.getViewEntity(config);
+
+    ViewRegistry registry = ViewRegistry.getInstance();
+    registry.addDefinition(viewDefinition);
+
+    ViewInstanceEntity viewInstanceEntity = createNiceMock(ViewInstanceEntity.class);
+    Cluster cluster = createNiceMock(Cluster.class);
+    Service service = createNiceMock(Service.class);
+
+    Map<String, Service> serviceMap = new HashMap<String, Service>();
+
+    for (String serviceName : serviceNames) {
+      serviceMap.put(serviceName, service);
+    }
+
+    StackId stackId = new StackId("HDP-2.0");
+
+    expect(clusters.getClusterById(99L)).andReturn(cluster);
+    expect(cluster.getClusterName()).andReturn("c1").anyTimes();
+    expect(cluster.getCurrentStackVersion()).andReturn(stackId).anyTimes();
+    expect(cluster.getServices()).andReturn(serviceMap).anyTimes();
+
+    Capture<ViewInstanceEntity> viewInstanceCapture = new Capture<ViewInstanceEntity>();
+
+    expect(viewInstanceDAO.merge(capture(viewInstanceCapture))).andReturn(viewInstanceEntity).anyTimes();
+    expect(viewInstanceDAO.findByName("MY_VIEW{1.0.0}", "AUTO-INSTANCE")).andReturn(viewInstanceEntity).anyTimes();
+
+    replay(securityHelper, configuration, viewInstanceDAO, clusters, cluster, viewInstanceEntity);
+
+
+    ServiceInstalledEvent event = new ServiceInstalledEvent(99L, "HDP", "2.0", "HIVE");
+
+    registry.onAmbariEvent(event);
+
+    if (success) {
+      Assert.assertEquals(viewInstanceCapture.getValue(), registry.getInstanceDefinition("MY_VIEW", "1.0.0", "AUTO-INSTANCE"));
+    }
+
+    verify(securityHelper, configuration, viewInstanceDAO, clusters, cluster, viewInstanceEntity);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/AutoInstanceConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/AutoInstanceConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/AutoInstanceConfigTest.java
new file mode 100644
index 0000000..fde5376
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/AutoInstanceConfigTest.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view.configuration;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+import javax.xml.bind.JAXBException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+/**
+ * AutoInstanceConfig tests.
+ */
+public class AutoInstanceConfigTest {
+
+
+  private static String VIEW_XML = "<view>\n" +
+      "    <name>MY_VIEW</name>\n" +
+      "    <label>My View!</label>\n" +
+      "    <description>Description</description>" +
+      "    <version>1.0.0</version>\n" +
+      "    <system>true</system>\n" +
+      "    <icon64>/this/is/the/icon/url/icon64.png</icon64>\n" +
+      "    <icon>/this/is/the/icon/url/icon.png</icon>\n" +
+      "    <validator-class>org.apache.ambari.server.view.configuration.ViewConfigTest$MyValidator</validator-class>" +
+      "    <masker-class>org.apache.ambari.server.view.DefaultMasker</masker-class>" +
+      "    <parameter>\n" +
+      "        <name>p1</name>\n" +
+      "        <description>Parameter 1.</description>\n" +
+      "        <label>Label 1.</label>\n" +
+      "        <placeholder>Placeholder 1.</placeholder>\n" +
+      "        <required>true</required>\n" +
+      "    </parameter>\n" +
+      "    <parameter>\n" +
+      "        <name>p2</name>\n" +
+      "        <description>Parameter 2.</description>\n" +
+      "        <default-value>Default value 1.</default-value>\n" +
+      "        <cluster-config>hdfs-site/dfs.namenode.http-address</cluster-config>\n" +
+      "        <required>false</required>\n" +
+      "        <masked>true</masked>" +
+      "    </parameter>\n" +
+      "    <auto-instance>\n" +
+      "        <name>INSTANCE1</name>\n" +
+      "        <label>My Instance 1!</label>\n" +
+      "        <description>This is a description.</description>\n" +
+      "        <icon64>/this/is/the/icon/url/instance_1_icon64.png</icon64>\n" +
+      "        <icon>/this/is/the/icon/url/instance_1_icon.png</icon>\n" +
+      "        <property>\n" +
+      "            <key>p1</key>\n" +
+      "            <value>v1-1</value>\n" +
+      "        </property>\n" +
+      "        <property>\n" +
+      "            <key>p2</key>\n" +
+      "            <value>v2-1</value>\n" +
+      "        </property>\n" +
+      "        <stack-id>HDP-2.0</stack-id>\n" +
+      "        <services><service>HIVE</service><service>HDFS</service></services>\n" +
+      "    </auto-instance>\n" +
+      "</view>";
+
+  @Test
+  public void testGetName() throws Exception {
+    AutoInstanceConfig config = getAutoInstanceConfigs(VIEW_XML);
+
+    Assert.assertEquals("INSTANCE1", config.getName());
+  }
+
+  @Test
+  public void testDescription() throws Exception {
+    AutoInstanceConfig config = getAutoInstanceConfigs(VIEW_XML);
+
+    assertEquals("This is a description.", config.getDescription());
+  }
+
+  @Test
+  public void testGetStackId() throws Exception {
+    AutoInstanceConfig config = getAutoInstanceConfigs(VIEW_XML);
+
+    assertEquals("HDP-2.0", config.getStackId());
+  }
+
+  @Test
+  public void testGetServices() throws Exception {
+    AutoInstanceConfig config = getAutoInstanceConfigs(VIEW_XML);
+    List<String> serviceNames = config.getServices();
+
+    assertEquals(2, serviceNames.size());
+    assertTrue(serviceNames.contains("HIVE"));
+    assertTrue(serviceNames.contains("HDFS"));
+  }
+
+  public static AutoInstanceConfig getAutoInstanceConfigs(String xml) throws JAXBException {
+    ViewConfig config = ViewConfigTest.getConfig(xml);
+    return config.getAutoInstance();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/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 1875238..beb8bde 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
@@ -87,6 +87,23 @@ public class ViewConfigTest {
       "        <provider-class>org.apache.ambari.server.view.configuration.ViewConfigTest$MyResourceProvider</provider-class>\n" +
       "        <service-class>org.apache.ambari.server.view.configuration.ViewConfigTest$MyResourceService</service-class>\n" +
       "    </resource>\n" +
+      "    <auto-instance>\n" +
+      "        <name>AUTO-INSTANCE</name>\n" +
+      "        <label>My Instance 1!</label>\n" +
+      "        <description>This is a description.</description>\n" +
+      "        <icon64>/this/is/the/icon/url/instance_1_icon64.png</icon64>\n" +
+      "        <icon>/this/is/the/icon/url/instance_1_icon.png</icon>\n" +
+      "        <property>\n" +
+      "            <key>p1</key>\n" +
+      "            <value>v1-1</value>\n" +
+      "        </property>\n" +
+      "        <property>\n" +
+      "            <key>p2</key>\n" +
+      "            <value>v2-1</value>\n" +
+      "        </property>\n" +
+      "        <stack-id>HDP-2.0</stack-id>\n" +
+      "        <services><service>HIVE</service><service>HDFS</service></services>\n" +
+      "    </auto-instance>\n" +
       "    <instance>\n" +
       "        <name>INSTANCE1</name>\n" +
       "        <label>My Instance 1!</label>\n" +
@@ -233,6 +250,13 @@ public class ViewConfigTest {
   }
 
   @Test
+  public void testGetAutoInstance() throws Exception {
+    ViewConfig config = getConfig(xml);
+    AutoInstanceConfig instance = config.getAutoInstance();
+    Assert.assertEquals("AUTO-INSTANCE", instance.getName());
+  }
+
+  @Test
   public void testGetInstances() throws Exception {
     ViewConfig config = getConfig(xml);
     List<InstanceConfig> instances = config.getInstances();

http://git-wip-us.apache.org/repos/asf/ambari/blob/5a60fa18/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 b5ed669..37737c1 100644
--- a/ambari-views/src/main/resources/view.xsd
+++ b/ambari-views/src/main/resources/view.xsd
@@ -219,6 +219,38 @@
     </xs:sequence>
   </xs:complexType>
 
+  <xs:complexType name="ServiceType">
+    <xs:annotation>
+      <xs:documentation>Defines a persistence entity used by the view.</xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element type="xs:string" name="service" minOccurs="1" maxOccurs="unbounded">
+        <xs:annotation>
+          <xs:documentation>The name of a service required to auto create an instance of this view.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="AutoInstanceType">
+    <xs:complexContent>
+      <xs:extension base="InstanceType">
+        <xs:sequence>
+          <xs:element name="stack-id" type="xs:string" minOccurs="1" maxOccurs="1">
+            <xs:annotation>
+              <xs:documentation>The stack id required to auto create an instance of this view.  The wildcard character '*' is supported (e.g. 'HDP-2.*').</xs:documentation>
+            </xs:annotation>
+          </xs:element>
+          <xs:element type="ServiceType" name="services" minOccurs="1"  maxOccurs="1">
+            <xs:annotation>
+              <xs:documentation>The services required to auto create an instance of this view.</xs:documentation>
+            </xs:annotation>
+          </xs:element>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
   <xs:element name="view">
     <xs:annotation>
       <xs:documentation>Defines a view.</xs:documentation>
@@ -310,6 +342,11 @@
             <xs:documentation>Defines the persistence entities used by the view.</xs:documentation>
           </xs:annotation>
         </xs:element>
+        <xs:element type="AutoInstanceType" name="auto-instance" minOccurs="0" maxOccurs="1">
+          <xs:annotation>
+            <xs:documentation>Defines an auto create instance of the view.</xs:documentation>
+          </xs:annotation>
+        </xs:element>
         <xs:element type="InstanceType" name="instance" minOccurs="0" maxOccurs="unbounded">
           <xs:annotation>
             <xs:documentation>Defines a static instance of the view.</xs:documentation>