http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionModule.java new file mode 100644 index 0000000..e3f8d0d --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionModule.java @@ -0,0 +1,540 @@ +/** + * 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.stack; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.state.ConfigHelper; +import org.apache.ambari.server.state.ExtensionInfo; +import org.apache.ambari.server.state.PropertyDependencyInfo; +import org.apache.ambari.server.state.PropertyInfo; +import org.apache.ambari.server.state.RepositoryInfo; +import org.apache.ambari.server.state.ServiceInfo; +import org.apache.ambari.server.state.stack.ExtensionMetainfoXml; +import org.apache.ambari.server.state.stack.RepositoryXml; +import org.apache.ambari.server.state.stack.ServiceMetainfoXml; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Extension module which provides all functionality related to parsing and fully + * resolving extensions from the extension definition. + * + * An extension version is like a stack version but it contains custom services. Linking an extension + * version to the current stack version allows the cluster to install the custom services contained in + * the extension version. + * + * <p> + * Each extension node is identified by name and version, contains service + * child nodes and may extend a single parent extension. + * </p> + * + * <p> + * Resolution of a extension is a depth first traversal up the inheritance chain where each extension node + * calls resolve on its parent before resolving itself. After the parent resolve call returns, all + * ancestors in the inheritance tree are fully resolved. The act of resolving the extension includes + * resolution of the services children of the extension as well as merging of other extension + * state with the fully resolved parent. + * </p> + * + * <p> + * Because a service may explicitly extend another service in a extension outside of the inheritance tree, + * service child node resolution involves a depth first resolution of the extension associated with the + * services explicit parent, if any. This follows the same steps defined above fore extension node + * resolution. After the services explicit parent is fully resolved, the services state is merged + * with it's parent. + * </p> + * + * <p> + * If a cycle in a extension definition is detected, an exception is thrown from the resolve call. + * </p> + * + */ +public class ExtensionModule extends BaseModule<ExtensionModule, ExtensionInfo> implements Validable { + + /** + * Context which provides access to external functionality + */ + private StackContext stackContext; + + /** + * Map of child configuration modules keyed by configuration type + */ + private Map<String, ConfigurationModule> configurationModules = new HashMap<String, ConfigurationModule>(); + + /** + * Map of child service modules keyed by service name + */ + private Map<String, ServiceModule> serviceModules = new HashMap<String, ServiceModule>(); + + /** + * Corresponding ExtensionInfo instance + */ + private ExtensionInfo extensionInfo; + + /** + * Encapsulates IO operations on extension directory + */ + private ExtensionDirectory extensionDirectory; + + /** + * Extension id which is in the form extensionName:extensionVersion + */ + private String id; + + /** + * validity flag + */ + protected boolean valid = true; + + /** + * Logger + */ + private final static Logger LOG = LoggerFactory.getLogger(ExtensionModule.class); + + /** + * Constructor. + * @param extensionDirectory represents extension directory + * @param extensionContext general extension context + */ + public ExtensionModule(ExtensionDirectory extensionDirectory, StackContext stackContext) { + this.extensionDirectory = extensionDirectory; + this.stackContext = stackContext; + this.extensionInfo = new ExtensionInfo(); + populateExtensionInfo(); + } + + public Map<String, ServiceModule> getServiceModules() { + return serviceModules; + } + + /** + * Fully resolve the extension. See extension resolution description in the class documentation. + * If the extension has a parent, this extension will be merged against its fully resolved parent + * if one is specified. Merging applies to all extension state including child service and + * configuration modules. Services may extend a service in another version in the + * same extension hierarchy or may explicitly extend a service in a different + * hierarchy. + * + * @param parentModule not used. Each extension determines its own parent since extensions don't + * have containing modules + * @param allStacks all stacks modules contained in the stack definition + * @param commonServices all common services + * @param extensions all extensions + * + * @throws AmbariException if an exception occurs during extension resolution + */ + @Override + public void resolve( + ExtensionModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + moduleState = ModuleState.VISITED; + checkExtensionName(allStacks); + + String parentVersion = extensionInfo.getParentExtensionVersion(); + mergeServicesWithExplicitParent(allStacks, commonServices, extensions); + // merge with parent version of same extension definition + if (parentVersion != null) { + mergeExtensionWithParent(parentVersion, allStacks, commonServices, extensions); + } + moduleState = ModuleState.RESOLVED; + } + + @Override + public ExtensionInfo getModuleInfo() { + return extensionInfo; + } + + @Override + public boolean isDeleted() { + return false; + } + + @Override + public String getId() { + return id; + } + + @Override + public void finalizeModule() { + finalizeChildModules(serviceModules.values()); + finalizeChildModules(configurationModules.values()); + } + + /** + * Get the associated extension directory. + * + * @return associated extension directory + */ + public ExtensionDirectory getExtensionDirectory() { + return extensionDirectory; + } + + /** + * Merge the extension with its parent. + * + * @param allStacks all stacks in stack definition + * @param commonServices all common services specified in the stack definition + * @param parentVersion version of the extensions parent + * + * @throws AmbariException if an exception occurs merging with the parent + */ + private void mergeExtensionWithParent( + String parentVersion, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + + String parentExtensionKey = extensionInfo.getName() + StackManager.PATH_DELIMITER + parentVersion; + ExtensionModule parentExtension = extensions.get(parentExtensionKey); + + if (parentExtension == null) { + throw new AmbariException("Extension '" + extensionInfo.getName() + ":" + extensionInfo.getVersion() + + "' specifies a parent that doesn't exist"); + } + + resolveExtension(parentExtension, allStacks, commonServices, extensions); + /*mergeConfigurations(parentStack, allStacks, commonServices); + mergeRoleCommandOrder(parentStack);*/ + + /*if (extensionInfo.getStackHooksFolder() == null) { + extensionInfo.setStackHooksFolder(parentStack.getModuleInfo().getStackHooksFolder()); + } + + if (extensionInfo.getKerberosDescriptorFileLocation() == null) { + extensionInfo.setKerberosDescriptorFileLocation(parentStack.getModuleInfo().getKerberosDescriptorFileLocation()); + } + + if (extensionInfo.getWidgetsDescriptorFileLocation() == null) { + extensionInfo.setWidgetsDescriptorFileLocation(parentStack.getModuleInfo().getWidgetsDescriptorFileLocation()); + }*/ + + mergeServicesWithParent(parentExtension, allStacks, commonServices, extensions); + } + + /** + * Merge child services with parent extension. + * + * @param parentExtension parent extension module + * @param allStacks all stacks in stack definition + * @param commonServices all common services + * @param extensions all extensions + * + * @throws AmbariException if an exception occurs merging the child services with the parent extension + */ + private void mergeServicesWithParent( + ExtensionModule parentExtension, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + extensionInfo.getServices().clear(); + + LOG.info("***Merging extension services with parent: " + parentExtension.getId()); + + Collection<ServiceModule> mergedModules = mergeChildModules( + allStacks, commonServices, extensions, serviceModules, parentExtension.serviceModules); + for (ServiceModule module : mergedModules) { + serviceModules.put(module.getId(), module); + extensionInfo.getServices().add(module.getModuleInfo()); + } + } + + /** + * Merge services with their explicitly specified parent if one has been specified. + * @param allStacks all stacks in stack definition + * @param commonServices all common services specified in the stack definition + * + * @throws AmbariException if an exception occurs while merging child services with their explicit parents + */ + private void mergeServicesWithExplicitParent( + Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { + for (ServiceModule service : serviceModules.values()) { + ServiceInfo serviceInfo = service.getModuleInfo(); + String parent = serviceInfo.getParent(); + if (parent != null) { + mergeServiceWithExplicitParent(service, parent, allStacks, commonServices, extensions); + } + } + } + + /** + * Merge a service with its explicitly specified parent. + * @param service the service to merge + * @param parent the explicitly specified parent service + * @param allStacks all stacks specified in the stack definition + * @param commonServices all common services specified in the stack definition + * + * @throws AmbariException if an exception occurs merging a service with its explicit parent + */ + private void mergeServiceWithExplicitParent( + ServiceModule service, String parent, Map<String, StackModule> allStacks, + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + if(isCommonServiceParent(parent)) { + LOG.info("merging with common service: " + service.getModuleInfo().getName()); + mergeServiceWithCommonServiceParent(service, parent, allStacks, commonServices, extensions); + LOG.info("display name: " + service.getModuleInfo().getDisplayName()); + } else { + throw new AmbariException("The service '" + service.getModuleInfo().getName() + "' in extension '" + extensionInfo.getName() + ":" + + extensionInfo.getVersion() + "' extends an invalid parent: '" + parent + "'"); + } + } + + /** + * @param allStacks all stacks specified in the stack definition + * + * @throws AmbariException if the extension name is the same as any of the stacks + */ + private void checkExtensionName(Map<String, StackModule> allStacks) + throws AmbariException { + + String name = extensionInfo.getName(); + for (StackModule stack : allStacks.values()) { + String stackName = stack.getModuleInfo().getName(); + if (name.equals(stackName)) { + throw new AmbariException("The extension '" + name + "' has a name which matches a stack name"); + } + } + } + + /** + * Check if parent is common service + * @param parent Parent string + * @return true: if parent is common service, false otherwise + */ + private boolean isCommonServiceParent(String parent) { + return parent != null + && !parent.isEmpty() + && parent.split(StackManager.PATH_DELIMITER)[0].equalsIgnoreCase(StackManager.COMMON_SERVICES); + } + + /** + * Merge a service with its explicitly specified common service as parent. + * Parent: common-services/<serviceName>/<serviceVersion> + * Common Services Lookup Key: <serviceName>/<serviceVersion> + * Example: + * Parent: common-services/HDFS/2.1.0.2.0 + * Key: HDFS/2.1.0.2.0 + * + * @param service the service to merge + * @param parent the explicitly specified common service as parent + * @param allStacks all stacks specified in the stack definition + * @param commonServices all common services specified in the stack definition + * @throws AmbariException + */ + private void mergeServiceWithCommonServiceParent( + ServiceModule service, String parent, Map<String, StackModule> allStacks, + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + ServiceInfo serviceInfo = service.getModuleInfo(); + String[] parentToks = parent.split(StackManager.PATH_DELIMITER); + if(parentToks.length != 3 || !parentToks[0].equalsIgnoreCase(StackManager.COMMON_SERVICES)) { + throw new AmbariException("The service '" + serviceInfo.getName() + "' in extension '" + extensionInfo.getName() + ":" + + extensionInfo.getVersion() + "' extends an invalid parent: '" + parent + "'"); + } + + String baseServiceKey = parentToks[1] + StackManager.PATH_DELIMITER + parentToks[2]; + ServiceModule baseService = commonServices.get(baseServiceKey); + if (baseService == null) { + setValid(false); + extensionInfo.setValid(false); + String error = "The service '" + serviceInfo.getName() + "' in extension '" + extensionInfo.getName() + ":" + + extensionInfo.getVersion() + "' extends a non-existent service: '" + parent + "'"; + addError(error); + extensionInfo.addError(error); + } else { + if (baseService.isValid()) { + service.resolveExplicit(baseService, allStacks, commonServices, extensions); + } else { + setValid(false); + extensionInfo.setValid(false); + addErrors(baseService.getErrors()); + extensionInfo.addErrors(baseService.getErrors()); + } + } + } + + /** + * Populate the extension module and info from the extension definition. + */ + private void populateExtensionInfo() { + extensionInfo.setName(extensionDirectory.getExtensionDirName()); + extensionInfo.setVersion(extensionDirectory.getName()); + + id = String.format("%s:%s", extensionInfo.getName(), extensionInfo.getVersion()); + + LOG.debug("Adding new extension to known extensions" + + ", extensionName = " + extensionInfo.getName() + + ", extensionVersion = " + extensionInfo.getVersion()); + + + //todo: give additional thought on handling missing metainfo.xml + ExtensionMetainfoXml emx = extensionDirectory.getMetaInfoFile(); + if (emx != null) { + if (!emx.isValid()) { + extensionInfo.setValid(false); + extensionInfo.addErrors(emx.getErrors()); + } + extensionInfo.setParentExtensionVersion(emx.getExtends()); + extensionInfo.setStacks(emx.getStacks()); + extensionInfo.setExtensions(emx.getExtensions()); + } + + try { + // Read the service for this extension + populateServices(); + if (!extensionInfo.isValid()) { + setValid(false); + addErrors(extensionInfo.getErrors()); + } + + //todo: shouldn't blindly catch Exception, re-evaluate this. + } catch (Exception e) { + String error = "Exception caught while populating services for extension: " + + extensionInfo.getName() + "-" + extensionInfo.getVersion(); + setValid(false); + extensionInfo.setValid(false); + addError(error); + extensionInfo.addError(error); + LOG.error(error); + } + } + + /** + * Populate the child services. + */ + private void populateServices()throws AmbariException { + for (ServiceDirectory serviceDir : extensionDirectory.getServiceDirectories()) { + populateService(serviceDir); + } + } + + /** + * Populate a child service. + * + * @param serviceDirectory the child service directory + */ + private void populateService(ServiceDirectory serviceDirectory) { + Collection<ServiceModule> serviceModules = new ArrayList<ServiceModule>(); + // unfortunately, we allow multiple services to be specified in the same metainfo.xml, + // so we can't move the unmarshal logic into ServiceModule + ServiceMetainfoXml metaInfoXml = serviceDirectory.getMetaInfoFile(); + if (!metaInfoXml.isValid()){ + extensionInfo.setValid(metaInfoXml.isValid()); + setValid(metaInfoXml.isValid()); + extensionInfo.addErrors(metaInfoXml.getErrors()); + addErrors(metaInfoXml.getErrors()); + return; + } + List<ServiceInfo> serviceInfos = metaInfoXml.getServices(); + + for (ServiceInfo serviceInfo : serviceInfos) { + ServiceModule serviceModule = new ServiceModule(stackContext, serviceInfo, serviceDirectory); + serviceModules.add(serviceModule); + if (!serviceModule.isValid()){ + extensionInfo.setValid(false); + setValid(false); + extensionInfo.addErrors(serviceModule.getErrors()); + addErrors(serviceModule.getErrors()); + } + } + addServices(serviceModules); + } + + /** + * Resolve another extension module. + * + * @param parentExtension extension module to be resolved + * @param allStacks all stack modules in stack definition + * @param commonServices all common services specified in the stack definition + * @param extensions all extensions + * @throws AmbariException if unable to resolve the extension + */ + private void resolveExtension( + ExtensionModule parentExtension, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + if (parentExtension.getModuleState() == ModuleState.INIT) { + parentExtension.resolve(null, allStacks, commonServices, extensions); + } else if (parentExtension.getModuleState() == ModuleState.VISITED) { + //todo: provide more information to user about cycle + throw new AmbariException("Cycle detected while parsing extension definition"); + } + if (!parentExtension.isValid() || (parentExtension.getModuleInfo() != null && !parentExtension.getModuleInfo().isValid())) { + setValid(parentExtension.isValid()); + extensionInfo.setValid(parentExtension.extensionInfo.isValid()); + addErrors(parentExtension.getErrors()); + extensionInfo.addErrors(parentExtension.getErrors()); + } + } + + /** + * Add a child service module to the extension. + * + * @param service service module to add + */ + private void addService(ServiceModule service) { + ServiceInfo serviceInfo = service.getModuleInfo(); + Object previousValue = serviceModules.put(service.getId(), service); + if (previousValue == null) { + extensionInfo.getServices().add(serviceInfo); + } + } + + /** + * Add child service modules to the extension. + * + * @param services collection of service modules to add + */ + private void addServices(Collection<ServiceModule> services) { + for (ServiceModule service : services) { + addService(service); + } + } + + @Override + public boolean isValid() { + return valid; + } + + @Override + public void setValid(boolean valid) { + this.valid = valid; + } + + private Set<String> errorSet = new HashSet<String>(); + + @Override + public Collection getErrors() { + return errorSet; + } + + @Override + public void addError(String error) { + errorSet.add(error); + } + + @Override + public void addErrors(Collection<String> errors) { + this.errorSet.addAll(errors); + } + +}
http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java index 9e2f997..7d47339 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java @@ -20,6 +20,7 @@ package org.apache.ambari.server.stack; import org.apache.ambari.server.state.stack.ConfigUpgradePack; import org.apache.ambari.server.state.stack.ConfigurationXml; +import org.apache.ambari.server.state.stack.ExtensionMetainfoXml; import org.apache.ambari.server.state.stack.RepositoryXml; import org.apache.ambari.server.state.stack.ServiceMetainfoXml; import org.apache.ambari.server.state.stack.StackMetainfoXml; @@ -27,7 +28,9 @@ import org.apache.ambari.server.state.stack.UpgradePack; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; + import java.io.File; import java.util.HashMap; import java.util.Map; @@ -72,6 +75,7 @@ class ModuleFileUnmarshaller { jaxbContexts.put(UpgradePack.class, ctx); jaxbContexts.put(ConfigUpgradePack.class, ctx); jaxbContexts.put(ServiceMetainfoXml.class, JAXBContext.newInstance(ServiceMetainfoXml.class)); + jaxbContexts.put(ExtensionMetainfoXml.class, JAXBContext.newInstance(ExtensionMetainfoXml.class)); } catch (JAXBException e) { throw new RuntimeException (e); } http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java index 84da70e..ed8e8cf 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java @@ -83,7 +83,7 @@ public class QuickLinksConfigurationModule extends BaseModule<QuickLinksConfigur } @Override - public void resolve(QuickLinksConfigurationModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) throws AmbariException { + public void resolve(QuickLinksConfigurationModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> allExtensions) throws AmbariException { QuickLinksConfigurationInfo parentModuleInfo = parent.getModuleInfo(); if (parent.getModuleInfo() != null && !moduleInfo.isDeleted()) { http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java index 9ed2c24..e938e68 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java @@ -22,11 +22,17 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.stack.ServiceMetainfoXml; +import org.apache.ambari.server.state.stack.StackRoleCommandOrder; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.xml.bind.JAXBException; + import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.Map; @@ -60,6 +66,16 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { private File kerberosDescriptorFile; /** + * RCO file + */ + private File rcoFile; + + /** + * role command order + */ + private StackRoleCommandOrder roleCommandOrder; + + /** * widgets descriptor file */ private Map<String, File> widgetsDescriptorFileMap = new HashMap<String, File>(); @@ -119,33 +135,6 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { public ServiceDirectory(String servicePath) throws AmbariException { super(servicePath); parsePath(); - - File af = new File(directory.getAbsolutePath() - + File.separator + AmbariMetaInfo.SERVICE_ALERT_FILE_NAME); - alertsFile = af.exists() ? af : null; - - File kdf = new File(directory.getAbsolutePath() - + File.separator + AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME); - kerberosDescriptorFile = kdf.exists() ? kdf : null; - - if (metaInfoXml.getServices() != null) { - for (ServiceInfo serviceInfo : metaInfoXml.getServices()) { - File mf = new File(directory.getAbsolutePath() - + File.separator + serviceInfo.getMetricsFileName()); - metricsFileMap.put(serviceInfo.getName(), mf.exists() ? mf : null); - - File wdf = new File(directory.getAbsolutePath() - + File.separator + serviceInfo.getWidgetsFileName()); - widgetsDescriptorFileMap.put(serviceInfo.getName(), wdf.exists() ? wdf : null); - } - } - - File advFile = new File(directory.getAbsolutePath() - + File.separator + AmbariMetaInfo.SERVICE_ADVISOR_FILE_NAME); - advisorFile = advFile.exists() ? advFile : null; - - File themeFile = new File(directory.getAbsolutePath() + File.separator + AmbariMetaInfo.SERVICE_THEME_FILE_NAME); - this.themeFile = themeFile.exists() ? themeFile : null; } /** @@ -237,9 +226,54 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { } /** + * Obtain the object representation of the service role_command_order.json file + * + * @return object representation of the service role_command_order.json file + */ + public StackRoleCommandOrder getRoleCommandOrder() { + return roleCommandOrder; + } + + /** * Parse the service directory. */ - protected abstract void parsePath() throws AmbariException; + protected void parsePath() throws AmbariException { + calculateDirectories(); + parseMetaInfoFile(); + + File af = new File(directory, AmbariMetaInfo.SERVICE_ALERT_FILE_NAME); + alertsFile = af.exists() ? af : null; + + File kdf = new File(directory, AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME); + kerberosDescriptorFile = kdf.exists() ? kdf : null; + + File rco = new File(directory, AmbariMetaInfo.RCO_FILE_NAME); + if (rco.exists()) { + rcoFile = rco; + parseRoleCommandOrder(); + } + + if (metaInfoXml.getServices() != null) { + for (ServiceInfo serviceInfo : metaInfoXml.getServices()) { + File mf = new File(directory, serviceInfo.getMetricsFileName()); + metricsFileMap.put(serviceInfo.getName(), mf.exists() ? mf : null); + + File wdf = new File(directory, serviceInfo.getWidgetsFileName()); + widgetsDescriptorFileMap.put(serviceInfo.getName(), wdf.exists() ? wdf : null); + } + } + + File advFile = new File(directory, AmbariMetaInfo.SERVICE_ADVISOR_FILE_NAME); + advisorFile = advFile.exists() ? advFile : null; + + File themeFile = new File(directory, AmbariMetaInfo.SERVICE_THEME_FILE_NAME); + this.themeFile = themeFile.exists() ? themeFile : null; + } + + /** + * Calculate the service specific directories. + */ + protected abstract void calculateDirectories(); /** * Unmarshal the metainfo file into its object representation. @@ -266,4 +300,28 @@ public abstract class ServiceDirectory extends StackDefinitionDirectory { } } + /** + * Parse role command order file + */ + private void parseRoleCommandOrder() { + if (rcoFile == null) + return; + + try { + ObjectMapper mapper = new ObjectMapper(); + TypeReference<Map<String, Object>> rcoElementTypeReference = new TypeReference<Map<String, Object>>() {}; + HashMap<String, Object> result = mapper.readValue(rcoFile, rcoElementTypeReference); + LOG.info("Role command order info was loaded from file: {}", rcoFile.getAbsolutePath()); + + roleCommandOrder = new StackRoleCommandOrder(result); + + if (LOG.isDebugEnabled() && rcoFile != null) { + LOG.debug("Role Command Order for " + rcoFile.getAbsolutePath()); + roleCommandOrder.printRoleCommandOrder(LOG); + } + } catch (IOException e) { + LOG.error(String.format("Can not read role command order info %s", rcoFile.getAbsolutePath()), e); + } + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java index 17a2a93..bc94104 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java @@ -36,6 +36,8 @@ import org.apache.ambari.server.state.ThemeInfo; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; @@ -102,6 +104,11 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem protected boolean valid = true; /** + * Logger + */ + private final static Logger LOG = LoggerFactory.getLogger(ServiceModule.class); + + /** * Constructor. * * @param stackContext stack context which provides module access to external functionality @@ -131,6 +138,7 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem serviceInfo.setAlertsFile(serviceDirectory.getAlertsFile()); serviceInfo.setKerberosDescriptorFile(serviceDirectory.getKerberosDescriptorFile()); serviceInfo.setWidgetsDescriptorFile(serviceDirectory.getWidgetsDescriptorFile(serviceInfo.getName())); + serviceInfo.setRoleCommandOrder(serviceDirectory.getRoleCommandOrder()); serviceInfo.setSchemaVersion(AmbariMetaInfo.SCHEMA_VERSION_2); serviceInfo.setServicePackageFolder(serviceDirectory.getPackageDir()); serviceInfo.setServiceUpgradesFolder(serviceDirectory.getUpgradesDir()); @@ -152,25 +160,27 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem @Override public void resolve( - ServiceModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + ServiceModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { - resolveInternal(parentModule, allStacks, commonServices, false); + resolveInternal(parentModule, allStacks, commonServices, extensions, false); } public void resolveExplicit( - ServiceModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + ServiceModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { - resolveInternal(parentModule, allStacks, commonServices, true); + resolveInternal(parentModule, allStacks, commonServices, extensions, true); } public void resolveInternal( ServiceModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, - boolean resolveExplicit) + Map<String, ExtensionModule> extensions, boolean resolveExplicit) throws AmbariException { if (!serviceInfo.isValid() || !parentModule.isValid()) { return; } + LOG.info("Resolve service"); + // If resolving against parent stack service module (stack inheritance), do not merge if an // explicit parent is specified if(!StringUtils.isBlank(serviceInfo.getParent()) && !resolveExplicit) { @@ -182,6 +192,7 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem if (serviceInfo.getComment() == null) { serviceInfo.setComment(parent.getComment()); } + LOG.info("Display name service/parent: " + serviceInfo.getDisplayName() + "/" + parent.getDisplayName()); if (serviceInfo.getDisplayName() == null) { serviceInfo.setDisplayName(parent.getDisplayName()); } @@ -239,17 +250,19 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem serviceInfo.setAdvisorName(parent.getAdvisorName()); } + if (serviceInfo.getRoleCommandOrder() == null) { + serviceInfo.setRoleCommandOrder(parent.getRoleCommandOrder()); + } + mergeCustomCommands(parent.getCustomCommands(), serviceInfo.getCustomCommands()); mergeConfigDependencies(parent); - mergeComponents(parentModule, allStacks, commonServices); - mergeConfigurations(parentModule, allStacks, commonServices); - mergeThemes(parentModule, allStacks, commonServices); - mergeQuickLinksConfigurations(parentModule, allStacks, commonServices); + mergeComponents(parentModule, allStacks, commonServices, extensions); + mergeConfigurations(parentModule, allStacks, commonServices, extensions); + mergeThemes(parentModule, allStacks, commonServices, extensions); + mergeQuickLinksConfigurations(parentModule, allStacks, commonServices, extensions); mergeExcludedConfigTypes(parent); - mergeServiceProperties(parent.getServicePropertyList()); - } /** @@ -296,7 +309,7 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem * * @throws AmbariException */ - public void resolveCommonService(Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + public void resolveCommonService(Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { if(!isCommonService) { throw new AmbariException("Not a common service"); @@ -314,12 +327,12 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem ServiceModule baseService = commonServices.get(baseServiceKey); ModuleState baseModuleState = baseService.getModuleState(); if (baseModuleState == ModuleState.INIT) { - baseService.resolveCommonService(allStacks, commonServices); + baseService.resolveCommonService(allStacks, commonServices, extensions); } else if (baseModuleState == ModuleState.VISITED) { //todo: provide more information to user about cycle throw new AmbariException("Cycle detected while parsing common service"); } - resolveExplicit(baseService, allStacks, commonServices); + resolveExplicit(baseService, allStacks, commonServices, extensions); } else { throw new AmbariException("Common service cannot inherit from a non common service"); } @@ -414,8 +427,8 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem * Merge theme modules. */ private void mergeThemes(ServiceModule parent, Map<String, StackModule> allStacks, - Map<String, ServiceModule> commonServices) throws AmbariException { - Collection<ThemeModule> mergedModules = mergeChildModules(allStacks, commonServices, themeModules, parent.themeModules); + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { + Collection<ThemeModule> mergedModules = mergeChildModules(allStacks, commonServices, extensions, themeModules, parent.themeModules); for (ThemeModule mergedModule : mergedModules) { themeModules.put(mergedModule.getId(), mergedModule); @@ -448,8 +461,8 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem * Merge theme modules. */ private void mergeQuickLinksConfigurations(ServiceModule parent, Map<String, StackModule> allStacks, - Map<String, ServiceModule> commonServices) throws AmbariException { - Collection<QuickLinksConfigurationModule> mergedModules = mergeChildModules(allStacks, commonServices, quickLinksConfigurationModules, parent.quickLinksConfigurationModules); + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { + Collection<QuickLinksConfigurationModule> mergedModules = mergeChildModules(allStacks, commonServices, extensions, quickLinksConfigurationModules, parent.quickLinksConfigurationModules); for (QuickLinksConfigurationModule mergedModule : mergedModules) { quickLinksConfigurationModules.put(mergedModule.getId(), mergedModule); @@ -514,13 +527,13 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem * @param commonServices common service modules */ private void mergeConfigurations( - ServiceModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + ServiceModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { serviceInfo.getProperties().clear(); serviceInfo.setAllConfigAttributes(new HashMap<String, Map<String, Map<String, String>>>()); Collection<ConfigurationModule> mergedModules = mergeChildModules( - allStacks, commonServices, configurationModules, parent.configurationModules); + allStacks, commonServices, extensions, configurationModules, parent.configurationModules); for (ConfigurationModule module : mergedModules) { configurationModules.put(module.getId(), module); @@ -540,11 +553,11 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem * @param commonServices common service modules */ private void mergeComponents( - ServiceModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + ServiceModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { serviceInfo.getComponents().clear(); Collection<ComponentModule> mergedModules = mergeChildModules( - allStacks, commonServices, componentModules, parent.componentModules); + allStacks, commonServices, extensions, componentModules, parent.componentModules); componentModules.clear(); for (ComponentModule module : mergedModules) { componentModules.put(module.getId(), module); http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionModule.java index b35afb2..0e834b8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionModule.java @@ -37,10 +37,11 @@ public interface StackDefinitionModule <T, I> { * @param parent the parent that this module will be merged with * @param allStacks collection of all stack modules in the tree * @param commonServices collection of all common service modules in the tree + * @param extensions collection of all extension modules in the tree * * @throws AmbariException if resolution fails */ - public void resolve(T parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) throws AmbariException; + public void resolve(T parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException; /** * Obtain the associated module information. http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java index ee9e383..bfba021 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java @@ -272,7 +272,6 @@ public class StackDirectory extends StackDefinitionDirectory { * * @return object representation of the stack role_command_order.json file */ - public StackRoleCommandOrder getRoleCommandOrder() { return roleCommandOrder; } @@ -509,7 +508,6 @@ public class StackDirectory extends StackDefinitionDirectory { result = new HashMap<String, Object>(); } roleCommandOrder = new StackRoleCommandOrder(result); - parseRoleCommandOrdersForServices(); if (LOG.isDebugEnabled()) { LOG.debug("Role Command Order for " + rcoFilePath); roleCommandOrder.printRoleCommandOrder(LOG); @@ -518,34 +516,4 @@ public class StackDirectory extends StackDefinitionDirectory { LOG.error(String.format("Can not read role command order info %s", rcoFilePath), e); } } - - private void parseRoleCommandOrdersForServices() { - if (rcoFilePath != null) { - File stack = new File(rcoFilePath).getParentFile(); - File servicesDir = new File(stack, "services"); - File[] services = servicesDir.listFiles(); - for (File service : services) { - if (service.isDirectory()) { - File rcoFile = new File(service, ROLE_COMMAND_ORDER_FILE); - if (rcoFile.exists()) - parseRoleCommandOrdersForService(rcoFile); - } - } - } - } - - private void parseRoleCommandOrdersForService(File rcoFile) { - HashMap<String, Object> result = null; - ObjectMapper mapper = new ObjectMapper(); - TypeReference<Map<String, Object>> rcoElementTypeReference = new TypeReference<Map<String, Object>>() {}; - try { - result = mapper.readValue(rcoFile, rcoElementTypeReference); - LOG.info("Role command order info was loaded from file: {}", rcoFile.getAbsolutePath()); - StackRoleCommandOrder serviceRoleCommandOrder = new StackRoleCommandOrder(result); - roleCommandOrder.merge(serviceRoleCommandOrder, true); - } catch (IOException e) { - LOG.error(String.format("Can not read role command order info %s", rcoFile), e); - } - } - } http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java index c224b56..6c0d5e4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java @@ -22,6 +22,7 @@ import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import javax.annotation.Nullable; @@ -35,9 +36,14 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.metadata.ActionMetadata; +import org.apache.ambari.server.orm.dao.ExtensionDAO; +import org.apache.ambari.server.orm.dao.ExtensionLinkDAO; import org.apache.ambari.server.orm.dao.MetainfoDAO; import org.apache.ambari.server.orm.dao.StackDAO; +import org.apache.ambari.server.orm.entities.ExtensionEntity; +import org.apache.ambari.server.orm.entities.ExtensionLinkEntity; import org.apache.ambari.server.orm.entities.StackEntity; +import org.apache.ambari.server.state.ExtensionInfo; import org.apache.ambari.server.state.ServiceInfo; import org.apache.ambari.server.state.StackInfo; import org.apache.ambari.server.state.stack.OsFamily; @@ -72,10 +78,19 @@ public class StackManager { public static final String COMMON_SERVICES = "common-services"; /** + * Prefix used for extension services parent path string + */ + public static final String EXTENSIONS = "extensions"; + + public static final String METAINFO_FILE_NAME = "metainfo.xml"; + + /** * Provides access to non-stack server functionality */ private StackContext stackContext; + private File stackRoot; + /** * Logger */ @@ -87,12 +102,19 @@ public class StackManager { private Map<String, StackInfo> stackMap = new HashMap<String, StackInfo>(); /** + * Map of extension id to extension info + */ + private Map<String, ExtensionInfo> extensionMap = new HashMap<String, ExtensionInfo>(); + + /** * Constructor. Initialize stack manager. * * @param stackRoot * stack root directory * @param commonServicesRoot * common services root directory + * @param extensionRoot + * extensions root directory * @param osFamily * the OS family read from resources * @param metaInfoDAO @@ -101,6 +123,10 @@ public class StackManager { * action meta data automatically injected * @param stackDao * stack DAO automatically injected + * @param extensionDao + * extension DAO automatically injected + * @param linkDao + * extension link DAO automatically injected * * @throws AmbariException * if an exception occurs while processing the stacks @@ -108,9 +134,10 @@ public class StackManager { @Inject public StackManager(@Assisted("stackRoot") File stackRoot, @Assisted("commonServicesRoot") @Nullable File commonServicesRoot, + @Assisted("extensionRoot") @Nullable File extensionRoot, @Assisted OsFamily osFamily, @Assisted boolean validate, - MetainfoDAO metaInfoDAO, - ActionMetadata actionMetadata, StackDAO stackDao) + MetainfoDAO metaInfoDAO, ActionMetadata actionMetadata, StackDAO stackDao, + ExtensionDAO extensionDao, ExtensionLinkDAO linkDao) throws AmbariException { LOG.info("Initializing the stack manager..."); @@ -118,22 +145,50 @@ public class StackManager { if (validate) { validateStackDirectory(stackRoot); validateCommonServicesDirectory(commonServicesRoot); + validateExtensionDirectory(extensionRoot); } stackMap = new HashMap<String, StackInfo>(); stackContext = new StackContext(metaInfoDAO, actionMetadata, osFamily); + extensionMap = new HashMap<String, ExtensionInfo>(); Map<String, ServiceModule> commonServiceModules = parseCommonServicesDirectory(commonServicesRoot); Map<String, StackModule> stackModules = parseStackDirectory(stackRoot); + LOG.info("About to parse extension directories"); + Map<String, ExtensionModule> extensionModules = null; + extensionModules = parseExtensionDirectory(extensionRoot); + + //Read the extension links from the DB + for (StackModule module : stackModules.values()) { + StackInfo stack = module.getModuleInfo(); + List<ExtensionLinkEntity> entities = linkDao.findByStack(stack.getName(), stack.getVersion()); + for (ExtensionLinkEntity entity : entities) { + String name = entity.getExtension().getExtensionName(); + String version = entity.getExtension().getExtensionVersion(); + String key = name + StackManager.PATH_DELIMITER + version; + ExtensionModule extensionModule = extensionModules.get(key); + if (extensionModule != null) { + LOG.info("Adding extension to stack/version: " + stack.getName() + "/" + stack.getVersion() + + " extension/version: " + name + "/" + version); + //Add the extension to the stack + module.getExtensionModules().put(key, extensionModule); + } + } + } - fullyResolveCommonServices(stackModules, commonServiceModules); - fullyResolveStacks(stackModules, commonServiceModules); + fullyResolveCommonServices(stackModules, commonServiceModules, extensionModules); + fullyResolveExtensions(stackModules, commonServiceModules, extensionModules); + fullyResolveStacks(stackModules, commonServiceModules, extensionModules); + populateDB(stackDao, extensionDao); + } + + private void populateDB(StackDAO stackDao, ExtensionDAO extensionDao) throws AmbariException { // for every stack read in, ensure that we have a database entry for it; // don't put try/catch logic around this since a failure here will // cause other things to break down the road Collection<StackInfo> stacks = getStacks(); - for( StackInfo stack : stacks ){ + for(StackInfo stack : stacks){ String stackName = stack.getName(); String stackVersion = stack.getVersion(); @@ -147,6 +202,25 @@ public class StackManager { stackDao.create(stackEntity); } } + + // for every extension read in, ensure that we have a database entry for it; + // don't put try/catch logic around this since a failure here will + // cause other things to break down the road + Collection<ExtensionInfo> extensions = getExtensions(); + for(ExtensionInfo extension : extensions){ + String extensionName = extension.getName(); + String extensionVersion = extension.getVersion(); + + if (extensionDao.find(extensionName, extensionVersion) == null) { + LOG.info("Adding extension {}-{} to the database", extensionName, extensionVersion); + + ExtensionEntity extensionEntity = new ExtensionEntity(); + extensionEntity.setExtensionName(extensionName); + extensionEntity.setExtensionVersion(extensionVersion); + + extensionDao.create(extensionEntity); + } + } } /** @@ -188,6 +262,44 @@ public class StackManager { } /** + * Obtain the extension info specified by name and version. + * + * @param name name of the extension + * @param version version of the extension + * @return The extension corresponding to the specified name and version. + * If no matching stack exists, null is returned. + */ + public ExtensionInfo getExtension(String name, String version) { + return extensionMap.get(name + StackManager.PATH_DELIMITER + version); + } + + /** + * Obtain all extensions for the given name. + * + * @param name extension name + * @return A collection of all extensions with the given name. + * If no extensions match the specified name, an empty collection is returned. + */ + public Collection<ExtensionInfo> getExtensions(String name) { + Collection<ExtensionInfo> extensions = new HashSet<ExtensionInfo>(); + for (ExtensionInfo extension: extensionMap.values()) { + if (extension.getName().equals(name)) { + extensions.add(extension); + } + } + return extensions; + } + + /** + * Obtain all extensions. + * + * @return collection of all extensions + */ + public Collection<ExtensionInfo> getExtensions() { + return extensionMap.values(); + } + + /** * Determine if all tasks which update stack repo urls have completed. * * @return true if all of the repo update tasks have completed; false otherwise @@ -204,12 +316,12 @@ public class StackManager { * @throws AmbariException if unable to resolve all stacks */ private void fullyResolveStacks( - Map<String, StackModule> stackModules, Map<String, ServiceModule> commonServiceModules) + Map<String, StackModule> stackModules, Map<String, ServiceModule> commonServiceModules, Map<String, ExtensionModule> extensions) throws AmbariException { // Resolve all stacks without finalizing the stacks. for (StackModule stack : stackModules.values()) { if (stack.getModuleState() == ModuleState.INIT) { - stack.resolve(null, stackModules, commonServiceModules); + stack.resolve(null, stackModules, commonServiceModules, extensions); } } // Finalize the common services and stacks to remove sub-modules marked for deletion. @@ -219,6 +331,9 @@ public class StackManager { for(ServiceModule commonService : commonServiceModules.values()) { commonService.finalizeModule(); } + for (ExtensionModule extension : extensions.values()) { + extension.finalizeModule(); + } for (StackModule stack : stackModules.values()) { stack.finalizeModule(); } @@ -234,11 +349,29 @@ public class StackManager { * @throws AmbariException if unable to resolve all common services */ private void fullyResolveCommonServices( - Map<String, StackModule> stackModules, Map<String, ServiceModule> commonServiceModules) + Map<String, StackModule> stackModules, Map<String, ServiceModule> commonServiceModules, Map<String, ExtensionModule> extensions) throws AmbariException { for(ServiceModule commonService : commonServiceModules.values()) { if (commonService.getModuleState() == ModuleState.INIT) { - commonService.resolveCommonService(stackModules, commonServiceModules); + commonService.resolveCommonService(stackModules, commonServiceModules, extensions); + } + } + } + + /** + * Fully resolve extensions. + * + * @param extensionModules map of extension id which contains name and version to extension module. + * @param stackModules map of stack id which contains name and version to stack module. + * @param commonServiceModules map of common service id which contains name and version to common service module. + * @throws AmbariException if unable to resolve all extensions + */ + private void fullyResolveExtensions(Map<String, StackModule> stackModules, Map<String, ServiceModule> commonServiceModules, + Map<String, ExtensionModule> extensionModules) + throws AmbariException { + for(ExtensionModule extensionModule : extensionModules.values()) { + if (extensionModule.getModuleState() == ModuleState.INIT) { + extensionModule.resolve(null, stackModules, commonServiceModules, extensionModules); } } } @@ -321,6 +454,34 @@ public class StackManager { } } + + + /** + * Validate that the specified extension root is a valid directory. + * + * @param extensionRoot the extension root directory to validate + * @throws AmbariException if the specified extension root directory is invalid + */ + private void validateExtensionDirectory(File extensionRoot) throws AmbariException { + LOG.info("Validating extension directory {} ...", extensionRoot); + + if (extensionRoot == null) + return; + + String extensionRootAbsPath = extensionRoot.getAbsolutePath(); + if (LOG.isDebugEnabled()) { + LOG.debug("Loading extension information" + + ", extensionRoot = " + extensionRootAbsPath); + } + + //For backwards compatibility extension directory may not exist + if (extensionRoot.exists() && !extensionRoot.isDirectory()) { + throw new AmbariException("" + Configuration.METADATA_DIR_PATH + + " should be a directory" + + ", extensionRoot = " + extensionRootAbsPath); + } + } + /** * Parse the specified common services root directory * @@ -399,4 +560,48 @@ public class StackManager { } return stackModules; } + + public void linkStackToExtension(StackInfo stack, ExtensionInfo extension) throws AmbariException { + } + + public void unlinkStackAndExtension(StackInfo stack, ExtensionInfo extension) throws AmbariException { + } + + /** + * Parse the specified extension root directory + * + * @param extensionRoot the extension root directory to parse + * @return map of extension id which contains name and version to extension module. + * @throws AmbariException if unable to parse all extensions + */ + private Map<String, ExtensionModule> parseExtensionDirectory(File extensionRoot) throws AmbariException { + Map<String, ExtensionModule> extensionModules = new HashMap<String, ExtensionModule>(); + if (extensionRoot == null || !extensionRoot.exists()) + return extensionModules; + + File[] extensionFiles = extensionRoot.listFiles(AmbariMetaInfo.FILENAME_FILTER); + for (File extensionNameFolder : extensionFiles) { + if (extensionNameFolder.isFile()) { + continue; + } + for (File extensionVersionFolder : extensionNameFolder.listFiles(AmbariMetaInfo.FILENAME_FILTER)) { + if (extensionVersionFolder.isFile()) { + continue; + } + String extensionName = extensionNameFolder.getName(); + String extensionVersion = extensionVersionFolder.getName(); + + ExtensionModule extensionModule = new ExtensionModule(new ExtensionDirectory(extensionVersionFolder.getPath()), stackContext); + String extensionKey = extensionName + StackManager.PATH_DELIMITER + extensionVersion; + extensionModules.put(extensionKey, extensionModule); + extensionMap.put(extensionKey, extensionModule.getModuleInfo()); + } + } + + if (stackMap.isEmpty()) { + throw new AmbariException("Unable to find extension definitions under " + + "extensionRoot = " + extensionRoot.getAbsolutePath()); + } + return extensionModules; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManagerFactory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManagerFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManagerFactory.java index 105b715..84e7e0b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManagerFactory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManagerFactory.java @@ -38,11 +38,14 @@ public interface StackManagerFactory { * @param commonServicesRoot * the root of the common services from which other stack services * are extended (not {@code null}). + * @param extensionRoot + * the root of the extensions (not {@code null}). * @param osFamily * the list of all parsed OS families (not {@code null}). * @return a stack manager instance which contains all parsed stacks. */ StackManager create(@Assisted("stackRoot") File stackRoot, @Nullable @Assisted("commonServicesRoot") File commonServicesRoot, + @Assisted("extensionRoot") @Nullable File extensionRoot, OsFamily osFamily, boolean validate); } http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java index d819a52..0606f2a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java @@ -36,6 +36,7 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.stack.StackDefinitionDirectory; import org.apache.ambari.server.state.ConfigHelper; +import org.apache.ambari.server.state.ExtensionInfo; import org.apache.ambari.server.state.PropertyDependencyInfo; import org.apache.ambari.server.state.PropertyInfo; import org.apache.ambari.server.state.RepositoryInfo; @@ -107,6 +108,11 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V private Map<String, ServiceModule> serviceModules = new HashMap<String, ServiceModule>(); /** + * Map of linked extension modules keyed by extension name + version + */ + private Map<String, ExtensionModule> extensionModules = new HashMap<String, ExtensionModule>(); + + /** * Corresponding StackInfo instance */ private StackInfo stackInfo; @@ -148,6 +154,14 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V populateStackInfo(); } + public Map<String, ServiceModule> getServiceModules() { + return serviceModules; + } + + public Map<String, ExtensionModule> getExtensionModules() { + return extensionModules; + } + /** * Fully resolve the stack. See stack resolution description in the class documentation. * If the stack has a parent, this stack will be merged against its fully resolved parent @@ -160,20 +174,34 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * have containing modules * @param allStacks all stacks modules contained in the stack definition * @param commonServices all common services specified in the stack definition + * @param extensions all extension modules contained in the stack definition * * @throws AmbariException if an exception occurs during stack resolution */ @Override public void resolve( - StackModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + StackModule parentModule, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { moduleState = ModuleState.VISITED; + LOG.info("Resolve: " + stackInfo.getName() + ":" + stackInfo.getVersion()); String parentVersion = stackInfo.getParentStackVersion(); - mergeServicesWithExplicitParent(allStacks, commonServices); + mergeServicesWithExplicitParent(allStacks, commonServices, extensions); + addExtensionServices(); + // merge with parent version of same stack definition if (parentVersion != null) { - mergeStackWithParent(parentVersion, allStacks, commonServices); + mergeStackWithParent(parentVersion, allStacks, commonServices, extensions); } + for (ExtensionInfo extension : stackInfo.getExtensions()) { + String extensionKey = extension.getName() + StackManager.PATH_DELIMITER + extension.getVersion(); + ExtensionModule extensionModule = extensions.get(extensionKey); + if (extensionModule == null) { + throw new AmbariException("Extension '" + stackInfo.getName() + ":" + stackInfo.getVersion() + + "' specifies an extension " + extensionKey + " that doesn't exist"); + } + mergeStackWithExtension(extensionModule, allStacks, commonServices, extensions); + } + processUpgradePacks(); processRepositories(); processPropertyDependencies(); @@ -199,6 +227,12 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V public void finalizeModule() { finalizeChildModules(serviceModules.values()); finalizeChildModules(configurationModules.values()); + + // This needs to be merged during the finalize to avoid the RCO from services being inherited by the children stacks + // The RCOs from a service should only be inherited through the service. + for (ServiceModule module : serviceModules.values()) { + mergeRoleCommandOrder(module); + } } /** @@ -220,7 +254,7 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * @throws AmbariException if an exception occurs merging with the parent */ private void mergeStackWithParent( - String parentVersion, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + String parentVersion, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { String parentStackKey = stackInfo.getName() + StackManager.PATH_DELIMITER + parentVersion; @@ -231,8 +265,8 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V "' specifies a parent that doesn't exist"); } - resolveStack(parentStack, allStacks, commonServices); - mergeConfigurations(parentStack, allStacks, commonServices); + resolveStack(parentStack, allStacks, commonServices, extensions); + mergeConfigurations(parentStack, allStacks, commonServices, extensions); mergeRoleCommandOrder(parentStack); if (stackInfo.getStackHooksFolder() == null) { @@ -248,7 +282,22 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V stackInfo.setWidgetsDescriptorFileLocation(parentStack.getModuleInfo().getWidgetsDescriptorFileLocation()); } - mergeServicesWithParent(parentStack, allStacks, commonServices); + mergeServicesWithParent(parentStack, allStacks, commonServices, extensions); + } + + /** + * Merge the stack with one of its linked extensions. + * + * @param allStacks all stacks in stack definition + * @param commonServices all common services specified in the stack definition + * @param parentVersion version of the stacks parent + * + * @throws AmbariException if an exception occurs merging with the parent + */ + private void mergeStackWithExtension( + ExtensionModule extension, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + } /** @@ -261,11 +310,11 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * @throws AmbariException if an exception occurs merging the child services with the parent stack */ private void mergeServicesWithParent( - StackModule parentStack, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + StackModule parentStack, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { stackInfo.getServices().clear(); Collection<ServiceModule> mergedModules = mergeChildModules( - allStacks, commonServices, serviceModules, parentStack.serviceModules); + allStacks, commonServices, extensions, serviceModules, parentStack.serviceModules); for (ServiceModule module : mergedModules) { serviceModules.put(module.getId(), module); stackInfo.getServices().add(module.getModuleInfo()); @@ -280,12 +329,12 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * @throws AmbariException if an exception occurs while merging child services with their explicit parents */ private void mergeServicesWithExplicitParent( - Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) throws AmbariException { + Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { for (ServiceModule service : serviceModules.values()) { ServiceInfo serviceInfo = service.getModuleInfo(); String parent = serviceInfo.getParent(); if (parent != null) { - mergeServiceWithExplicitParent(service, parent, allStacks, commonServices); + mergeServiceWithExplicitParent(service, parent, allStacks, commonServices, extensions); } } } @@ -301,12 +350,16 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V */ private void mergeServiceWithExplicitParent( ServiceModule service, String parent, Map<String, StackModule> allStacks, - Map<String, ServiceModule> commonServices) + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { + + LOG.info("mergeServiceWithExplicitParent" + parent); if(isCommonServiceParent(parent)) { - mergeServiceWithCommonServiceParent(service, parent, allStacks,commonServices); + mergeServiceWithCommonServiceParent(service, parent, allStacks, commonServices, extensions); + } else if(isExtensionServiceParent(parent)) { + mergeServiceWithExtensionServiceParent(service, parent, allStacks, commonServices, extensions); } else { - mergeServiceWithStackServiceParent(service, parent, allStacks, commonServices); + mergeServiceWithStackServiceParent(service, parent, allStacks, commonServices, extensions); } } @@ -322,6 +375,25 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V } /** + * Check if parent is extension service + * @param parent Parent string + * @return true: if parent is extension service, false otherwise + */ + private boolean isExtensionServiceParent(String parent) { + return parent != null + && !parent.isEmpty() + && parent.split(StackManager.PATH_DELIMITER)[0].equalsIgnoreCase(StackManager.EXTENSIONS); + } + + private void addExtensionServices() throws AmbariException { + for (ExtensionModule extension : extensionModules.values()) { + stackInfo.getExtensions().add(extension.getModuleInfo()); + Collection<ServiceModule> services = extension.getServiceModules().values(); + addServices(services); + } + } + + /** * Merge a service with its explicitly specified common service as parent. * Parent: common-services/<serviceName>/<serviceVersion> * Common Services Lookup Key: <serviceName>/<serviceVersion> @@ -337,7 +409,7 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V */ private void mergeServiceWithCommonServiceParent( ServiceModule service, String parent, Map<String, StackModule> allStacks, - Map<String, ServiceModule> commonServices) + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { ServiceInfo serviceInfo = service.getModuleInfo(); String[] parentToks = parent.split(StackManager.PATH_DELIMITER); @@ -357,7 +429,7 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V stackInfo.addError(error); } else { if (baseService.isValid()) { - service.resolveExplicit(baseService, allStacks, commonServices); + service.resolveExplicit(baseService, allStacks, commonServices, extensions); } else { setValid(false); stackInfo.setValid(false); @@ -368,6 +440,50 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V } /** + * Merge a service with its explicitly specified extension service as parent. + * Parent: extensions/<extensionName>/<extensionVersion>/<serviceName> + * Example: + * Parent: extensions/EXT_TEST/1.0/CUSTOM_SERVICE + * + * @param service the service to merge + * @param parent the explicitly specified extension as parent + * @param allStacks all stacks specified in the stack definition + * @param commonServices all common services + * @param extensions all extensions + * @throws AmbariException + */ + private void mergeServiceWithExtensionServiceParent( + ServiceModule service, String parent, Map<String, StackModule> allStacks, + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + ServiceInfo serviceInfo = service.getModuleInfo(); + String[] parentToks = parent.split(StackManager.PATH_DELIMITER); + if(parentToks.length != 4 || !parentToks[0].equalsIgnoreCase(StackManager.EXTENSIONS)) { + throw new AmbariException("The service '" + serviceInfo.getName() + "' in stack '" + stackInfo.getName() + ":" + + stackInfo.getVersion() + "' extends an invalid parent: '" + parent + "'"); + } + + String extensionKey = parentToks[1] + StackManager.PATH_DELIMITER + parentToks[2]; + ExtensionModule extension = extensions.get(extensionKey); + + if (extension == null || !extension.isValid()) { + setValid(false); + addError("The service '" + serviceInfo.getName() + "' in stack '" + stackInfo.getName() + ":" + + stackInfo.getVersion() + "' extends a non-existent service: '" + parent + "'"); + } else { + resolveExtension(extension, allStacks, commonServices, extensions); + ServiceModule parentService = extension.getServiceModules().get(parentToks[3]); + if (parentService == null || !parentService.isValid()) { + setValid(false); + addError("The service '" + serviceInfo.getName() + "' in stack '" + stackInfo.getName() + ":" + + stackInfo.getVersion() + "' extends a non-existent service: '" + parent + "'"); + } + else + service.resolve(parentService, allStacks, commonServices, extensions); + } + } + + /** * Merge a service with its explicitly specified stack service as parent. * Parent: <stackName>/<stackVersion>/<serviceName> * Stack Lookup Key: <stackName>/<stackVersion> @@ -378,16 +494,17 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * @param service the service to merge * @param parent the explicitly specified stack service as parent * @param allStacks all stacks specified in the stack definition - * @param commonServices all common services specified in the stack definition + * @param commonServices all common services + * @param extensions all extensions * @throws AmbariException */ private void mergeServiceWithStackServiceParent( ServiceModule service, String parent, Map<String, StackModule> allStacks, - Map<String, ServiceModule> commonServices) + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { ServiceInfo serviceInfo = service.getModuleInfo(); String[] parentToks = parent.split(StackManager.PATH_DELIMITER); - if(parentToks.length != 3 || parentToks[0].equalsIgnoreCase(StackManager.COMMON_SERVICES)) { + if(parentToks.length != 3 || parentToks[0].equalsIgnoreCase(StackManager.EXTENSIONS) || parentToks[0].equalsIgnoreCase(StackManager.COMMON_SERVICES)) { throw new AmbariException("The service '" + serviceInfo.getName() + "' in stack '" + stackInfo.getName() + ":" + stackInfo.getVersion() + "' extends an invalid parent: '" + parent + "'"); } @@ -399,14 +516,14 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V + stackInfo.getVersion() + "' extends a service in a non-existent stack: '" + baseStackKey + "'"); } - resolveStack(baseStack, allStacks, commonServices); + resolveStack(baseStack, allStacks, commonServices, extensions); ServiceModule baseService = baseStack.serviceModules.get(parentToks[2]); if (baseService == null) { throw new AmbariException("The service '" + serviceInfo.getName() + "' in stack '" + stackInfo.getName() + ":" + stackInfo.getVersion() + "' extends a non-existent service: '" + parent + "'"); } - service.resolveExplicit(baseService, allStacks, commonServices); + service.resolveExplicit(baseService, allStacks, commonServices, extensions); } /** @@ -422,8 +539,7 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V + ", stackName = " + stackInfo.getName() + ", stackVersion = " + stackInfo.getVersion()); - - //odo: give additional thought on handling missing metainfo.xml + //todo: give additional thought on handling missing metainfo.xml StackMetainfoXml smx = stackDirectory.getMetaInfoFile(); if (smx != null) { if (!smx.isValid()) { @@ -542,13 +658,13 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * @param commonServices all common services specified in the stack definition */ private void mergeConfigurations( - StackModule parent, Map<String,StackModule> allStacks, Map<String, ServiceModule> commonServices) + StackModule parent, Map<String,StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { stackInfo.getProperties().clear(); stackInfo.setAllConfigAttributes(new HashMap<String, Map<String, Map<String, String>>>()); Collection<ConfigurationModule> mergedModules = mergeChildModules( - allStacks, commonServices, configurationModules, parent.configurationModules); + allStacks, commonServices, extensions, configurationModules, parent.configurationModules); for (ConfigurationModule module : mergedModules) { configurationModules.put(module.getId(), module); stackInfo.getProperties().addAll(module.getModuleInfo().getProperties()); @@ -565,10 +681,10 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V * @throws AmbariException if unable to resolve the stack */ private void resolveStack( - StackModule stackToBeResolved, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) + StackModule stackToBeResolved, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { if (stackToBeResolved.getModuleState() == ModuleState.INIT) { - stackToBeResolved.resolve(null, allStacks, commonServices); + stackToBeResolved.resolve(null, allStacks, commonServices, extensions); } else if (stackToBeResolved.getModuleState() == ModuleState.VISITED) { //todo: provide more information to user about cycle throw new AmbariException("Cycle detected while parsing stack definition"); @@ -582,6 +698,30 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V } /** + * Resolve an extension module. + * + * @param extension extension module to be resolved + * @param allStacks all stack modules in stack definition + * @param commonServices all common services + * @param extensions all extensions + * @throws AmbariException if unable to resolve the stack + */ + private void resolveExtension( + ExtensionModule extension, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) + throws AmbariException { + if (extension.getModuleState() == ModuleState.INIT) { + extension.resolve(null, allStacks, commonServices, extensions); + } else if (extension.getModuleState() == ModuleState.VISITED) { + //todo: provide more information to user about cycle + throw new AmbariException("Cycle detected while parsing extension definition"); + } + if (!extension.isValid() || (extension.getModuleInfo() != null && !extension.getModuleInfo().isValid())) { + setValid(false); + addError("Stack includes an invalid extension: " + extension.getModuleInfo().getName()); + } + } + + /** * Add a child service module to the stack. * * @param service service module to add @@ -943,6 +1083,23 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V stackInfo.getRoleCommandOrder().merge(parentStack.stackInfo.getRoleCommandOrder()); } + /** + * Merge role command order with the service + * + * @param service service + */ + private void mergeRoleCommandOrder(ServiceModule service) { + if (service.getModuleInfo().getRoleCommandOrder() == null) + return; + + stackInfo.getRoleCommandOrder().merge(service.getModuleInfo().getRoleCommandOrder(), true); + if (LOG.isDebugEnabled()) { + LOG.debug("Role Command Order for " + stackInfo.getName() + "-" + stackInfo.getVersion() + + " service " + service.getModuleInfo().getName()); + stackInfo.getRoleCommandOrder().printRoleCommandOrder(LOG); + } + } + @Override public boolean isValid() { return valid; http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/StackServiceDirectory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackServiceDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackServiceDirectory.java index 68c1dd6..7bcd08b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackServiceDirectory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackServiceDirectory.java @@ -67,14 +67,13 @@ public class StackServiceDirectory extends ServiceDirectory { @Override /** - * Parse stack service directory. + * Calculate the stack service directories. * packageDir Format: stacks/<stackName>/<stackVersion>/services/<serviceName>/package * Example: * directory: "/var/lib/ambari-server/resources/stacks/HDP/2.0.6/services/HDFS" * packageDir: "stacks/HDP/2.0.6/services/HDFS/package" - * @throws AmbariException if unable to parse the service directory */ - protected void parsePath() throws AmbariException { + protected void calculateDirectories() { File serviceDir = new File(getAbsolutePath()); File stackVersionDir = serviceDir.getParentFile().getParentFile(); File stackDir = stackVersionDir.getParentFile(); @@ -116,6 +115,5 @@ public class StackServiceDirectory extends ServiceDirectory { LOG.debug("Service upgrades folder %s for service %s for stack %s does not exist.", absUpgradesDir, serviceDir.getName(), stackId); } - parseMetaInfoFile(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/300a7e21/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java index d8f50c6..30c1f1b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ThemeModule.java @@ -82,7 +82,8 @@ public class ThemeModule extends BaseModule<ThemeModule, ThemeInfo> implements V } @Override - public void resolve(ThemeModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) throws AmbariException { + public void resolve(ThemeModule parent, Map<String, StackModule> allStacks, + Map<String, ServiceModule> commonServices, Map<String, ExtensionModule> extensions) throws AmbariException { ThemeInfo parentModuleInfo = parent.getModuleInfo(); if (parent.getModuleInfo() != null && !moduleInfo.isDeleted()) {
