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 <tbeerbo...@hortonworks.com> Authored: Mon Apr 13 19:23:28 2015 -0400 Committer: tbeerbower <tbeerbo...@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>