This is an automated email from the ASF dual-hosted git repository.
jluniya pushed a commit to branch branch-2.7
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/branch-2.7 by this push:
new cd98499 AMBARI-24764: StackMerger utility tool for flattening stack
definitons (#2444)
cd98499 is described below
commit cd9849914accd4b696df028df18238cb66d4c93f
Author: jayush <[email protected]>
AuthorDate: Fri Oct 26 10:32:30 2018 -0700
AMBARI-24764: StackMerger utility tool for flattening stack definitons
(#2444)
* AMBARI-24764: StackMerger utility tool for flattening stack definitions
(jluniya)
* AMBARI-24764: StackMerger utility tool - update usage and address CR
feedback (jluniya)
* AMBARI-24764: StackMerger utility tool - Update MSFT-R service advisor
(jluniya)
* AMBARI-24764: StackMerger utility tool - console logging (jluniya)
---
ambari-server/conf/unix/log4j.properties | 11 +
ambari-server/conf/windows/log4j.properties | 11 +
ambari-server/src/main/conf/log4j.properties | 11 +
.../ambari/server/api/services/AmbariMetaInfo.java | 4 +
.../server/stack/CommonServiceDirectory.java | 3 +-
.../ambari/server/stack/ServiceDirectory.java | 4 +-
.../apache/ambari/server/stack/StackDirectory.java | 2 +-
.../apache/ambari/server/stack/StackManager.java | 2 +-
.../apache/ambari/server/stack/StackMerger.java | 606 +++++++++++++++++++++
.../apache/ambari/server/state/AutoDeployInfo.java | 2 +-
.../apache/ambari/server/state/ComponentInfo.java | 2 +
.../server/state/DependencyConditionInfo.java | 1 +
.../apache/ambari/server/state/DependencyInfo.java | 2 +-
.../apache/ambari/server/state/PropertyInfo.java | 3 +
.../apache/ambari/server/state/ServiceInfo.java | 54 +-
.../server/state/stack/ConfigurationXml.java | 11 +
.../server/state/stack/StackMetainfoXml.java | 31 +-
.../AMBARI_INFRA_SOLR/0.1.0/service_advisor.py | 2 +
.../AMBARI_METRICS/0.1.0/service_advisor.py | 2 +
.../common-services/HAWQ/2.0.0/service_advisor.py | 2 +
.../LOGSEARCH/0.5.0/service_advisor.py | 2 +
.../common-services/PXF/3.0.0/service_advisor.py | 2 +
.../ZEPPELIN/0.7.0/service_advisor.py | 2 +
.../ZOOKEEPER/3.4.9/service_advisor.py | 2 +
.../src/main/resources/scripts/stack_advisor.py | 6 +
.../stacks/HDP/2.1/services/stack_advisor.py | 5 +
.../stacks/HDP/2.2/services/stack_advisor.py | 5 +
.../stacks/HDP/2.3/services/stack_advisor.py | 5 +
.../stacks/HDP/2.4/services/stack_advisor.py | 5 +
.../stacks/HDP/2.5/services/stack_advisor.py | 5 +
.../src/main/resources/stacks/HDP/2.6/metainfo.xml | 2 +
.../stacks/HDP/2.6/services/stack_advisor.py | 5 +
.../MICROSOFT_R_SERVER/8.0.5/service_advisor.py | 2 +
33 files changed, 803 insertions(+), 11 deletions(-)
diff --git a/ambari-server/conf/unix/log4j.properties
b/ambari-server/conf/unix/log4j.properties
index 06968e4..78d4171 100644
--- a/ambari-server/conf/unix/log4j.properties
+++ b/ambari-server/conf/unix/log4j.properties
@@ -26,6 +26,7 @@ ambari.alerts.file=ambari-alerts.log
ambari.eclipselink.file=ambari-eclipselink.log
ambari.audit.file=ambari-audit.log
ambari.dbcheck.file=ambari-server-check-database.log
+ambari.stackmerger.file=ambari-stack-merger.log
log4j.rootLogger=INFO,file
@@ -68,6 +69,16 @@
log4j.appender.dbcheckhelper.File=${ambari.log.dir}/${ambari.dbcheck.file}
log4j.appender.dbcheckhelper.layout=org.apache.log4j.PatternLayout
log4j.appender.dbcheckhelper.layout.ConversionPattern=%d{ISO8601} %5p - %m%n
+# Log stack merger
+log4j.logger.org.apache.ambari.server.stack.StackMerger=INFO,stackmerger,console-stackmerger
+log4j.additivity.org.apache.ambari.server.stack.StackMerger=false
+log4j.appender.console-stackmerger=org.apache.log4j.ConsoleAppender
+log4j.appender.console-stackmerger.layout=org.apache.log4j.PatternLayout
+log4j.appender.stackmerger=org.apache.log4j.FileAppender
+log4j.appender.stackmerger.File=${ambari.log.dir}/${ambari.stackmerger.file}
+log4j.appender.stackmerger.layout=org.apache.log4j.PatternLayout
+log4j.appender.stackmerger.layout.ConversionPattern=%d{ISO8601} %5p - %m%n
+
# EclipsLink -> slf4j bridge
log4j.logger.eclipselink=TRACE,eclipselink
log4j.additivity.eclipselink=false
diff --git a/ambari-server/conf/windows/log4j.properties
b/ambari-server/conf/windows/log4j.properties
index 4b768f3..13a3180 100644
--- a/ambari-server/conf/windows/log4j.properties
+++ b/ambari-server/conf/windows/log4j.properties
@@ -25,6 +25,7 @@ ambari.alerts.file=ambari-alerts.log
ambari.eclipselink.file=ambari-eclipselink.log
ambari.audit.file=ambari-audit.log
ambari.dbcheck.file=ambari-server-check-database.log
+ambari.stackmerger.file=ambari-stack-merger.log
# Define the root logger to the system property "ambari.root.logger".
log4j.rootLogger=${ambari.root.logger}
@@ -93,6 +94,16 @@
log4j.appender.dbcheckhelper.File=${ambari.log.dir}/${ambari.dbcheck.file}
log4j.appender.dbcheckhelper.layout=org.apache.log4j.PatternLayout
log4j.appender.dbcheckhelper.layout.ConversionPattern=%d{ISO8601} %5p - %m%n
+# Log stack merger
+log4j.logger.org.apache.ambari.server.stack.StackMerger=INFO,stackmerger,console-stackmerger
+log4j.additivity.org.apache.ambari.server.stack.StackMerger=false
+log4j.appender.console-stackmerger=org.apache.log4j.ConsoleAppender
+log4j.appender.console-stackmerger.layout=org.apache.log4j.PatternLayout
+log4j.appender.stackmerger=org.apache.log4j.FileAppender
+log4j.appender.stackmerger.File=${ambari.log.dir}/${ambari.stackmerger.file}
+log4j.appender.stackmerger.layout=org.apache.log4j.PatternLayout
+log4j.appender.stackmerger.layout.ConversionPattern=%d{ISO8601} %5p - %m%n
+
# EclipsLink -> slf4j bridge
log4j.logger.eclipselink=TRACE,eclipselink
log4j.additivity.eclipselink=false
diff --git a/ambari-server/src/main/conf/log4j.properties
b/ambari-server/src/main/conf/log4j.properties
index 680b4c4..73fc92f 100644
--- a/ambari-server/src/main/conf/log4j.properties
+++ b/ambari-server/src/main/conf/log4j.properties
@@ -25,6 +25,7 @@ ambari.alerts.file=ambari-alerts.log
ambari.eclipselink.file=ambari-eclipselink.log
ambari.audit.file=ambari-audit.log
ambari.dbcheck.file=ambari-server-check-database.log
+ambari.stackmerger.file=ambari-stack-merger.log
# Define the root logger to the system property "ambari.root.logger".
log4j.rootLogger=${ambari.root.logger}
@@ -93,6 +94,16 @@
log4j.appender.dbcheckhelper.File=${ambari.log.dir}/${ambari.dbcheck.file}
log4j.appender.dbcheckhelper.layout=org.apache.log4j.PatternLayout
log4j.appender.dbcheckhelper.layout.ConversionPattern=%d{ISO8601} %5p - %m%n
+# Log stack merger
+log4j.logger.org.apache.ambari.server.stack.StackMerger=INFO,stackmerger,console-stackmerger
+log4j.additivity.org.apache.ambari.server.stack.StackMerger=false
+log4j.appender.console-stackmerger=org.apache.log4j.ConsoleAppender
+log4j.appender.console-stackmerger.layout=org.apache.log4j.PatternLayout
+log4j.appender.stackmerger=org.apache.log4j.FileAppender
+log4j.appender.stackmerger.File=${ambari.log.dir}/${ambari.stackmerger.file}
+log4j.appender.stackmerger.layout=org.apache.log4j.PatternLayout
+log4j.appender.stackmerger.layout.ConversionPattern=%d{ISO8601} %5p - %m%n
+
# EclipsLink -> slf4j bridge
log4j.logger.eclipselink=TRACE,eclipselink
log4j.additivity.eclipselink=false
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index 9f0a43b..85e25f6 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -860,6 +860,10 @@ public class AmbariMetaInfo {
return stackRoot;
}
+ public File getCommonServicesRoot() {
+ return commonServicesRoot;
+ }
+
public File getExtensionsRoot() {
return extensionsRoot;
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/stack/CommonServiceDirectory.java
b/ambari-server/src/main/java/org/apache/ambari/server/stack/CommonServiceDirectory.java
index 80b0b7f..da06de3 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/stack/CommonServiceDirectory.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/stack/CommonServiceDirectory.java
@@ -44,8 +44,9 @@ public class CommonServiceDirectory extends ServiceDirectory {
*/
@Override
public String getAdvisorName(String serviceName) {
- if (getAdvisorFile() == null || serviceName == null)
+ if (getAdvisorFile() == null || serviceName == null) {
return null;
+ }
File serviceVersionDir = new File(getAbsolutePath());
String serviceVersion = serviceVersionDir.getName().replaceAll("\\.", "");
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 7464e61..a303170 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
@@ -110,12 +110,12 @@ public abstract class ServiceDirectory extends
StackDefinitionDirectory {
/**
* package directory name
*/
- protected static final String PACKAGE_FOLDER_NAME = "package";
+ public static final String PACKAGE_FOLDER_NAME = "package";
/**
* upgrades directory name
*/
- protected static final String UPGRADES_FOLDER_NAME = "upgrades";
+ public static final String UPGRADES_FOLDER_NAME = "upgrades";
/**
* checks directory name
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 daf8e7c..4ad9be2 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
@@ -145,7 +145,7 @@ public class StackDirectory extends
StackDefinitionDirectory {
/**
* upgrades directory name
*/
- private static final String UPGRADE_PACK_FOLDER_NAME = "upgrades";
+ public static final String UPGRADE_PACK_FOLDER_NAME = "upgrades";
/**
* role command order file name
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 3473fe8..6ff04d4 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
@@ -563,7 +563,7 @@ public class StackManager {
private Map<String, ServiceModule> parseCommonServicesDirectory(File
commonServicesRoot) throws AmbariException {
Map<String, ServiceModule> commonServiceModules = new HashMap<>();
- if(commonServicesRoot != null) {
+ if(commonServicesRoot != null && commonServicesRoot.exists()) {
File[] commonServiceFiles =
commonServicesRoot.listFiles(StackDirectory.FILENAME_FILTER);
for (File commonService : commonServiceFiles) {
if (commonService.isFile()) {
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackMerger.java
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackMerger.java
new file mode 100644
index 0000000..96f211d
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackMerger.java
@@ -0,0 +1,606 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.audit.AuditLoggerModule;
+import org.apache.ambari.server.controller.ControllerModule;
+import org.apache.ambari.server.ldap.LdapModule;
+import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.QuickLinksConfigurationInfo;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.ThemeInfo;
+import org.apache.ambari.server.state.quicklinks.QuickLinks;
+import org.apache.ambari.server.state.stack.ConfigurationXml;
+import org.apache.ambari.server.state.stack.RepositoryXml;
+import org.apache.ambari.server.state.stack.ServiceMetainfoXml;
+import org.apache.ambari.server.state.stack.StackMetainfoXml;
+import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
+import org.apache.ambari.server.state.theme.Theme;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
+
+/**
+ * Utility tool for merging stack hierarchy and generate flattened stack
definitions for legal stacks
+ */
+public class StackMerger {
+
+ private static final String MERGED_STACKS_ROOT = "mergedStacksRoot";
+ private static final String STACKS_ARG = "stacks";
+
+ private static final Logger LOG = LoggerFactory.getLogger
+ (StackMerger.class);
+
+ private PersistService persistService;
+ private DBAccessor dbAccessor;
+ private Injector injector;
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+ private File commonServicesRoot;
+ private File stackRoot;
+ private StackManager stackManager;
+ private Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+ @Inject
+ public StackMerger(Injector injector) throws Exception {
+ this.injector = injector;
+ AmbariMetaInfo metaInfo = injector.getInstance(AmbariMetaInfo.class);
+ metaInfo.init();
+ this.stackRoot = metaInfo.getStackRoot();
+ this.commonServicesRoot = metaInfo.getCommonServicesRoot();
+ this.stackManager = metaInfo.getStackManager();
+ }
+
+ /**
+ * Extension of audit logger module
+ */
+ public static class StackMergerAuditModule extends AuditLoggerModule {
+
+ public StackMergerAuditModule() throws Exception {
+ }
+
+ @Override
+ protected void configure() {
+ super.configure();
+ }
+ }
+
+ /**
+ * Context object that encapsulates values passed in as arguments to the
{@link StackMerger} class.
+ */
+ private static class StackMergerContext {
+ private String mergedStacksRoot;
+ private HashSet<StackId> stackIds;
+
+ public StackMergerContext(String mergedStacksRoot, HashSet<StackId>
stackIds) {
+ this.stackIds = stackIds;
+ this.mergedStacksRoot = mergedStacksRoot;
+ }
+
+ public HashSet<StackId> getStackIds() {
+ return stackIds;
+ }
+
+ public String getMergedStacksRoot() {
+ return mergedStacksRoot;
+ }
+ }
+
+ private static Options getOptions() {
+ Options options = new Options();
+ options.addOption(Option.builder().longOpt(STACKS_ARG).desc(
+ "Comma-separated list of stacks to be merged and
exported").required().type(String.class).hasArg().valueSeparator(' ').build());
+ options.addOption(Option.builder().longOpt(MERGED_STACKS_ROOT).desc(
+ "Root directory where the merged stacks should be
exported").required().type(String.class).hasArg().valueSeparator(' ').build());
+ return options;
+ }
+
+ private static StackMergerContext processArguments(String... args) throws
Exception {
+ CommandLineParser cmdLineParser = new DefaultParser();
+ HelpFormatter formatter = new HelpFormatter();
+
+ CommandLine line = cmdLineParser.parse(getOptions(), args);
+ String mergedStacksRoot = (String)
line.getParsedOptionValue(MERGED_STACKS_ROOT);
+ String stacksStr = (String) line.getParsedOptionValue(STACKS_ARG);
+ HashSet<StackId> stackIds = new HashSet<>();
+ for (String s : stacksStr.split(",")) {
+ stackIds.add(new StackId(s));
+ }
+ return new StackMergerContext(mergedStacksRoot, stackIds);
+ }
+
+ public void mergeStacks(StackMergerContext ctx) throws Exception {
+ File mergeRoot = new File(ctx.mergedStacksRoot);
+ for(StackId stackId : ctx.stackIds) {
+ mergeStack(mergeRoot, stackId);
+ }
+ }
+
+ /**
+ * Merge stack hierarchy to create flattened stack definition
+ * @throws Exception
+ */
+ public void mergeStack(File mergeRoot, StackId srcStackId) throws Exception {
+ StackId destStackId = srcStackId;
+ String stackName = destStackId.getStackName();
+ String stackVersion = destStackId.getStackVersion();
+ File mergedStackDir = new File(mergeRoot.getAbsolutePath()
+ + File.separator + stackName + File.separator + stackVersion);
+
+ LOG.info("===========================================================");
+ LOG.info("Source Stacks Root: " + stackRoot);
+ LOG.info("Common Services Root: " + commonServicesRoot);
+ LOG.info("Merged Stacks Root: " + mergeRoot);
+ LOG.info("Source Stack Id: " + srcStackId);
+ LOG.info("Destination Stack Id: " + destStackId);
+ LOG.info("Merged Stack Path " + mergedStackDir);
+ LOG.info("===========================================================");
+
+ // Create merged stack directory
+ if (!mergeRoot.exists()) {
+ mergeRoot.mkdirs();
+ }
+ if (mergedStackDir.exists()) {
+ FileUtils.deleteDirectory(mergedStackDir);
+ }
+ mergedStackDir.mkdirs();
+
+ // Create services directory
+ File servicesDir = new File(mergedStackDir.getAbsolutePath() +
File.separator + "services");
+ if (servicesDir.exists()) {
+ servicesDir.delete();
+ }
+ servicesDir.mkdir();
+
+ // Export role command order
+ StackInfo srcStackInfo = stackManager.getStack(srcStackId.getStackName(),
srcStackId.getStackVersion());
+ StackRoleCommandOrder stackRoleCommandOrder =
srcStackInfo.getRoleCommandOrder();
+ FileWriter stackRCOFile = new FileWriter(
+ mergedStackDir.getAbsolutePath() + File.separator +
StackDirectory.RCO_FILE_NAME);
+ mapper.writerWithDefaultPrettyPrinter().writeValue(stackRCOFile,
stackRoleCommandOrder.getContent());
+
+ // Export stack-level configs (example: cluster-env)
+ File stackConfigDir = new File(
+ mergedStackDir.getAbsolutePath() + File.separator +
StackDirectory.SERVICE_CONFIG_FOLDER_NAME);
+ exportConfigs(srcStackInfo.getProperties(), stackConfigDir);
+
+ // Export stack metainfo.xml
+ StackMetainfoXml stackMetainfoXml = new StackMetainfoXml();
+ stackMetainfoXml.setMinJdk(srcStackInfo.getMinJdk());
+ stackMetainfoXml.setMaxJdk(srcStackInfo.getMaxJdk());
+ // Flattened stack, so set extends to null
+ stackMetainfoXml.setExtendsVersion(null);
+ StackMetainfoXml.Version version = new StackMetainfoXml.Version();
+ version.setActive(srcStackInfo.isActive());
+ version.setUpgrade(srcStackInfo.getMinUpgradeVersion());
+ stackMetainfoXml.setVersion(version);
+
+ JAXBContext ctx = JAXBContext.newInstance(StackMetainfoXml.class);
+ Marshaller marshaller = ctx.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ FileOutputStream stackMetainfoFileStream = new FileOutputStream(
+ mergedStackDir.getAbsolutePath() + File.separator +
"metainfo.xml");
+ marshaller.marshal(stackMetainfoXml, stackMetainfoFileStream);
+ stackMetainfoFileStream.flush();
+ stackMetainfoFileStream.close();
+
+ // Export repoinfo.xml
+ RepositoryXml repositoryXml = srcStackInfo.getRepositoryXml();
+ ctx = JAXBContext.newInstance(RepositoryXml.class);
+ marshaller = ctx.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ File reposDir = new File(mergedStackDir.getAbsolutePath() + File.separator
+ "repos");
+ if (!reposDir.exists()) {
+ reposDir.mkdir();
+ }
+ FileOutputStream repoXmlFileStream = new FileOutputStream(
+ reposDir.getAbsolutePath() + File.separator + "repoinfo.xml");
+ marshaller.marshal(repositoryXml, repoXmlFileStream);
+ repoXmlFileStream.flush();
+ repoXmlFileStream.close();
+
+ // Copy cluster property files (example:
stacks/HDP/2.0.6/properties/stack_tools.json)
+ File destPropertiesDir = new File(mergedStackDir.getAbsoluteFile() +
File.separator + "properties");
+ if(!destPropertiesDir.exists()) {
+ destPropertiesDir.mkdir();
+ }
+
+ String srcStackName = srcStackId.getStackName();
+ String currentStackVersion = srcStackId.getStackVersion();
+ while (!StringUtils.isEmpty(currentStackVersion)) {
+ StackInfo currentStackInfo = stackManager.getStack(srcStackName,
currentStackVersion);
+ File srcPropertiesDir = new File(stackRoot.getAbsolutePath()
+ + File.separator + srcStackName + File.separator +
currentStackVersion + File.separator + "properties");
+ if (srcPropertiesDir.exists() && srcPropertiesDir.isDirectory()) {
+ for (File srcPropertiesFile : srcPropertiesDir.listFiles()) {
+ File destPropertiesFile = new
File(destPropertiesDir.getAbsolutePath()
+ + File.separator + srcPropertiesFile.getName());
+ if (!destPropertiesFile.exists()) {
+ FileUtils.copyFile(srcPropertiesFile, destPropertiesFile);
+ }
+ }
+ }
+ currentStackVersion = currentStackInfo.getParentStackVersion();
+ }
+
+ // Copy Kerberos pre-configuration file (example:
stacks/HDP/2.6/kerberos_preconfigure.json
+ if(srcStackInfo.getKerberosDescriptorPreConfigurationFileLocation() !=
null) {
+ File srcKerberosPreConfigFile = new
File(srcStackInfo.getKerberosDescriptorPreConfigurationFileLocation());
+ File destKerberosPreConfigFile = new
File(mergedStackDir.getAbsoluteFile()
+ + File.separator +
StackDirectory.KERBEROS_DESCRIPTOR_PRECONFIGURE_FILE_NAME);
+ if (!destKerberosPreConfigFile.exists()) {
+ FileUtils.copyFile(srcKerberosPreConfigFile,
destKerberosPreConfigFile);
+ }
+ }
+
+ // Copy upgrade packs
+ if(srcStackInfo.getUpgradesFolder() != null) {
+ File srcUpgradesFile = new File(srcStackInfo.getUpgradesFolder());
+ File destUpgradesFile = new File(mergedStackDir.getAbsoluteFile()
+ + File.separator + StackDirectory.UPGRADE_PACK_FOLDER_NAME);
+ FileUtils.copyDirectory(srcUpgradesFile, destUpgradesFile);
+ }
+
+ // Export all stack advisors in the stack hierarchy
+ File stackAdvisorsDir = new File(mergedStackDir.getAbsolutePath() +
File.separator + "stack-advisors");
+ if(!stackAdvisorsDir.exists()) {
+ stackAdvisorsDir.mkdir();
+ }
+
+ currentStackVersion = srcStackId.getStackVersion();
+ String baseStackAdvisor = null;
+ String baseStackAdvisorModule = null;
+ while (!StringUtils.isEmpty(currentStackVersion)) {
+ // Copy all inherited stack advisors from source stack to
"stack-advisors" folder
+ StackInfo currentStackInfo = stackManager.getStack(srcStackName,
currentStackVersion);
+ File srcStackAdvisor = new File(stackRoot.getAbsolutePath() +
File.separator
+ + srcStackName + File.separator + currentStackVersion +
File.separator + "services" + File.separator
+ + "stack_advisor.py");
+ if(srcStackAdvisor.exists()) {
+ if(baseStackAdvisor == null) {
+ baseStackAdvisor = srcStackName.toUpperCase() +
currentStackVersion.replace(".", "") + "StackAdvisor";
+ baseStackAdvisorModule = "stack_advisor_" +
srcStackName.toLowerCase() + currentStackVersion.replace(".", "");
+ }
+ File destStackAdvisor = new File(
+ stackAdvisorsDir.getAbsolutePath() + File.separator +
"stack_advisor_" + srcStackName.toLowerCase()
+ + currentStackVersion.replace(".", "") + ".py");
+ FileUtils.copyFile(srcStackAdvisor, destStackAdvisor);
+ }
+ currentStackVersion = currentStackInfo.getParentStackVersion();
+ }
+
+ // Define top-level stack advisor for merged stack
+ if(baseStackAdvisor != null) {
+ String topLevelStackAdvisorName =
destStackId.getStackName().toUpperCase() +
destStackId.getStackVersion().replace(".", "") + "StackAdvisor";
+ if(baseStackAdvisor.equalsIgnoreCase(topLevelStackAdvisorName)) {
+ // Use top level stack advisor from source stack as top level stack
advisor for merged stack
+ String srcPath = stackAdvisorsDir.getAbsolutePath() + File.separator +
baseStackAdvisorModule + ".py";
+ String destPath = servicesDir.getAbsolutePath() + File.separator +
"stack_advisor.py";
+ Files.move(Paths.get(srcPath), Paths.get(destPath));
+ } else {
+ // Create top level stack advisor for merged stack
+ FileWriter fileWriter = new FileWriter(
+ servicesDir.getAbsolutePath() + File.separator + "stack_advisor.py");
+ BufferedWriter bw = new BufferedWriter(fileWriter);
+ bw.write("from " + baseStackAdvisorModule + " import *");
+ bw.newLine();
+ bw.write("class " + topLevelStackAdvisorName + "(" + baseStackAdvisor
+ ")");
+ bw.newLine();
+ bw.write(" pass");
+ bw.newLine();
+ bw.flush();
+ fileWriter.flush();
+ bw.close();
+ fileWriter.close();
+ }
+ }
+
+ // Export all service definitions
+ for (String serviceName : srcStackInfo.getServiceNames()) {
+
+ ServiceInfo serviceInfo = srcStackInfo.getService(serviceName);
+ ServiceInfo clonedServiceInfo = (ServiceInfo) serviceInfo.clone();
+ // Flattening the stack, so set cloned service's parent to null
+ clonedServiceInfo.setParent(null);
+
+ // Create service root directory
+ File serviceDir = new File(
+ servicesDir.getAbsolutePath() + File.separator + serviceName);
+ if (!serviceDir.exists()) {
+ serviceDir.mkdir();
+ }
+
+ // Export service metainfo.xml
+ ServiceMetainfoXml serviceMetainfoXml = new ServiceMetainfoXml();
+
serviceMetainfoXml.setSchemaVersion(clonedServiceInfo.getSchemaVersion());
+ List<ServiceInfo> serviceInfos =
Collections.singletonList(clonedServiceInfo);
+ serviceMetainfoXml.setServices(serviceInfos);
+ ctx = JAXBContext.newInstance(ServiceMetainfoXml.class);
+ marshaller = ctx.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ FileOutputStream serviceMetainfoFileStream = new FileOutputStream(
+ serviceDir.getAbsolutePath() + File.separator + "metainfo.xml");
+ StringWriter sw = new StringWriter();
+ marshaller.marshal(serviceMetainfoXml, serviceMetainfoFileStream);
+ marshaller.marshal(serviceMetainfoXml, sw);
+ serviceMetainfoFileStream.flush();
+ serviceMetainfoFileStream.close();
+
+ // Export mertrics.json
+ File srcMetricsFile = serviceInfo.getMetricsFile();
+ exportFile(srcMetricsFile, serviceDir);
+
+ // Export widgets.json
+ File srcWidgetsFile = serviceInfo.getWidgetsDescriptorFile();
+ exportFile(srcWidgetsFile, serviceDir);
+
+ // Export alerts.json
+ File srcAlertsFile = serviceInfo.getAlertsFile();
+ exportFile(srcAlertsFile, serviceDir);
+
+ // Export kerberos.json
+ File srcKerberosFile = serviceInfo.getKerberosDescriptorFile();
+ exportFile(srcKerberosFile, serviceDir);
+
+ // Export quicklinks
+ for (Map.Entry<String, QuickLinksConfigurationInfo> entry :
serviceInfo.getQuickLinksConfigurationsMap()
+ .entrySet()) {
+ QuickLinksConfigurationInfo quickLinksConfigurationInfo =
entry.getValue();
+ String quickLinksFileName = quickLinksConfigurationInfo.getFileName();
+ for (Map.Entry<String, QuickLinks> quickLinksEntry :
quickLinksConfigurationInfo
+ .getQuickLinksConfigurationMap().entrySet()) {
+ File quickLinksDir = new File(
+ serviceDir.getAbsolutePath() + File.separator + serviceInfo
+ .getQuickLinksConfigurationsDir());
+ if (!quickLinksDir.exists()) {
+ quickLinksDir.mkdir();
+ }
+ FileWriter quickLinksFileWriter = new FileWriter(
+ quickLinksDir.getAbsolutePath() + File.separator +
quickLinksFileName, true);
+ mapper.writerWithDefaultPrettyPrinter()
+ .writeValue(quickLinksFileWriter, quickLinksEntry.getValue());
+ }
+ }
+
+ // Export themes
+ for (Map.Entry<String, ThemeInfo> entry :
serviceInfo.getThemesMap().entrySet()) {
+ ThemeInfo themeInfo = entry.getValue();
+ String themeFileName = themeInfo.getFileName();
+ for (Map.Entry<String, Theme> themeEntry :
themeInfo.getThemeMap().entrySet()) {
+ File themesDir = new File(
+ serviceDir.getAbsolutePath() + File.separator +
serviceInfo.getThemesDir());
+ if (!themesDir.exists()) {
+ themesDir.mkdir();
+ }
+ FileWriter themesFileWriter = new FileWriter(
+ themesDir.getAbsolutePath() + File.separator + themeFileName,
true);
+ mapper.writerWithDefaultPrettyPrinter().writeValue(themesFileWriter,
themeEntry.getValue());
+ }
+ }
+
+ // Export package folder (python scripts)
+ String srcPackageFolder = serviceInfo.getServicePackageFolder();
+ if (srcPackageFolder.startsWith("common-services")) {
+ srcPackageFolder = srcPackageFolder
+ .replace("common-services", commonServicesRoot.getAbsolutePath());
+ } else {
+ srcPackageFolder = srcPackageFolder.replace("stacks",
stackRoot.getAbsolutePath());
+ }
+ File srcPackageFile = new File(srcPackageFolder);
+ if (srcPackageFile != null && srcPackageFile.exists()) {
+ File destPackageFile = new File(
+ serviceDir.getAbsolutePath() + File.separator
+ + ServiceDirectory.PACKAGE_FOLDER_NAME);
+ FileUtils.copyDirectory(srcPackageFile, destPackageFile);
+ }
+
+ // Export merged service-level configs
+ File configDir = new File(
+ serviceDir.getAbsolutePath() + File.separator +
serviceInfo.getConfigDir());
+ exportConfigs(serviceInfo.getProperties(), configDir);
+
+ // Copy service property files (example:
common-services/KERBEROS/1.10.3-10/properties/krb5_conf.j2)
+ File destServicePropertiesDir = new File(serviceDir.getAbsolutePath() +
File.separator + "properties");
+ if(!destServicePropertiesDir.exists()) {
+ destServicePropertiesDir.mkdir();
+ }
+
+ srcStackName = srcStackId.getStackName();
+ currentStackVersion = srcStackId.getStackVersion();
+ boolean foundExplicitParent = false;
+ while (!StringUtils.isEmpty(currentStackVersion)) {
+ StackInfo currentStackInfo = stackManager.getStack(srcStackName,
currentStackVersion);
+ ServiceInfo currentServiceInfo =
currentStackInfo.getService(serviceName);
+ if(currentServiceInfo != null) {
+ File srcServicePropertiesDir = new File(stackRoot.getAbsolutePath()
+ File.separator
+ + srcStackName + File.separator + currentStackVersion +
File.separator
+ + "services" + File.separator + serviceName + File.separator
+ "properties");
+ if (srcServicePropertiesDir.exists() &&
srcServicePropertiesDir.isDirectory()) {
+ for (File srcServicePropertiesFile :
srcServicePropertiesDir.listFiles()) {
+ File destServicePropertiesFile = new
File(destServicePropertiesDir.getAbsolutePath()
+ + File.separator + srcServicePropertiesFile.getName());
+ if (!destServicePropertiesFile.exists()) {
+ FileUtils.copyFile(srcServicePropertiesFile,
destServicePropertiesFile);
+ }
+ }
+ }
+ String currentServiceParent = currentServiceInfo.getParent();
+ // Check for explicit service inheritance
+ if (StringUtils.isNotEmpty(currentServiceParent)) {
+ foundExplicitParent = true;
+ }
+ }
+ if(foundExplicitParent) {
+ // Stop traversing the stack hierarchy if explicit parent defined
+ break;
+ } else {
+ currentStackVersion = currentStackInfo.getParentStackVersion();
+ }
+ }
+
+ if(foundExplicitParent) {
+ StackInfo currentStackInfo = stackManager.getStack(srcStackName,
currentStackVersion);
+ ServiceInfo currentServiceInfo =
currentStackInfo.getService(serviceName);
+ String currentServiceParent = currentServiceInfo.getParent();
+
if(currentServiceParent.split(StackManager.PATH_DELIMITER)[0].equalsIgnoreCase(StackManager.COMMON_SERVICES))
{
+ String[] parentToks =
currentServiceParent.split(StackManager.PATH_DELIMITER);
+ File srcServicePropertiesDir = new
File(commonServicesRoot.getAbsolutePath() + File.separator
+ + parentToks[1] + File.separator + parentToks[2] +
File.separator + "properties");
+ if (srcServicePropertiesDir.exists() &&
srcServicePropertiesDir.isDirectory()) {
+ for (File srcServicePropertiesFile :
srcServicePropertiesDir.listFiles()) {
+ File destServicePropertiesFile = new
File(destServicePropertiesDir.getAbsolutePath()
+ + File.separator + srcServicePropertiesFile.getName());
+ if (!destServicePropertiesFile.exists()) {
+ FileUtils.copyFile(srcServicePropertiesFile,
destServicePropertiesFile);
+ }
+ }
+ }
+ // TODO : Not traversing common-services hierarchy for now
+ } else {
+ // TODO : Not handling explicit inheritance outside of
common-services for now
+ }
+ }
+
+ // Copy service advisor
+ File srcServiceAdvisor = serviceInfo.getAdvisorFile();
+ File destServiceAdvisor = new File(serviceDir.getAbsolutePath() +
File.separator + "service_advisor.py");
+ if(srcServiceAdvisor != null && srcServiceAdvisor.exists()) {
+ FileUtils.copyFile(srcServiceAdvisor, destServiceAdvisor);
+ }
+ }
+
+ // Delete *.pyc, *.pyo, archive.zip
+ FileUtils.listFiles(mergedStackDir, new String[]{"pyc", "pyo", "zip"},
true).forEach(File::delete);
+ LOG.info("Merged Stack " + destStackId + " has been successfully exported
at " + mergedStackDir);
+ }
+
+ /**
+ * Export file
+ * @param srcFile Source File Path
+ * @param destRootDir Target root directory
+ * @throws Exception
+ */
+ public static void exportFile(File srcFile, File destRootDir) throws
Exception {
+ if (srcFile != null && srcFile.exists()) {
+ Path srcPath = Paths.get(srcFile.getAbsolutePath());
+ Path destPath = Paths.get(
+ destRootDir.getAbsolutePath() + File.separator + srcFile.getName());
+ Files.copy(srcPath, destPath, StandardCopyOption.COPY_ATTRIBUTES,
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+
+ /**
+ * Export configs
+ * @param properties List of config properties
+ * @param configDir Configuration directory
+ * @throws Exception
+ */
+ public static void exportConfigs(List<PropertyInfo> properties, File
configDir) throws Exception {
+ if (!configDir.exists()) {
+ configDir.mkdir();
+ }
+
+ Map<String, List<PropertyInfo>> configFilesMap = new HashMap<>();
+ for (PropertyInfo propertyInfo : properties) {
+ String fileName = propertyInfo.getFilename();
+ if (!configFilesMap.containsKey(fileName)) {
+ configFilesMap.put(fileName, new ArrayList<PropertyInfo>());
+ }
+ configFilesMap.get(fileName).add(propertyInfo);
+ }
+
+ for (Map.Entry<String, List<PropertyInfo>> entry :
configFilesMap.entrySet()) {
+ String fileName = entry.getKey();
+ ConfigurationXml configXml = new ConfigurationXml();
+ configXml.setProperties(entry.getValue());
+ JAXBContext ctx = JAXBContext.newInstance(ConfigurationXml.class);
+ Marshaller marshaller = ctx.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ FileOutputStream configFileStream = new FileOutputStream(
+ configDir.getAbsolutePath() + File.separator + fileName);
+ marshaller.marshal(configXml, configFileStream);
+ configFileStream.flush();
+ configFileStream.close();
+ }
+ }
+
+ /**
+ * Main method for merging stack definitions
+ *
+ * Usage:
+ * java -cp
/etc/ambari-server/conf:/usr/lib/ambari-server/*:/usr/share/java/postgresql-jdbc.jar
+ * org.apache.ambari.server.stack.StackMerger
--mergedStacksRoot=/tmp/merged-root --stacks=HDP-2.5,HDP-2.6
+ * @param args
+ * @throws Exception
+ */
+ public static void main(String[] args) throws Exception {
+ StackMergerContext ctx = processArguments(args);
+
+ LOG.info("********* Initializing Stack Merger *********");
+ Injector injector = Guice.createInjector(new ControllerModule(), new
StackMergerAuditModule(), new LdapModule());
+ GuiceJpaInitializer jpaInitializer =
injector.getInstance(GuiceJpaInitializer.class);
+ jpaInitializer.setInitialized();
+ StackMerger stackMerger = injector.getInstance(StackMerger.class);
+ LOG.info("********* Stack Merger Initialized *********");
+ stackMerger.mergeStacks(ctx);
+ LOG.info("********* Stack Merger Finished *********");
+
+ System.exit(0);
+ }
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/AutoDeployInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/AutoDeployInfo.java
index c2d4d8b..74bc0b3 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/AutoDeployInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/AutoDeployInfo.java
@@ -34,7 +34,6 @@ public class AutoDeployInfo {
* Optional component name to co-locate with.
* Specified in the form serviceName/componentName.
*/
- @XmlElement(name="co-locate")
private String m_coLocate;
/**
@@ -69,6 +68,7 @@ public class AutoDeployInfo {
*
* @return a component name in the form serviceName/componentName
*/
+ @XmlElement(name="co-locate")
public String getCoLocate() {
return m_coLocate;
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
index a4bac56..351f865 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlTransient;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
@@ -53,6 +54,7 @@ public class ComponentInfo {
* This is the translation of the xml element ["true", "false", null] (note
that if a value is not specified,
* it will inherit from the parent) into a boolean after actually resolving
it.
*/
+ @XmlTransient
private boolean versionAdvertisedInternal = false;
/**
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyConditionInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyConditionInfo.java
index 392dec6..de39af4 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyConditionInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyConditionInfo.java
@@ -60,6 +60,7 @@ class PropertyExists implements DependencyConditionInfo {
*/
protected String type = this.getClass().getSimpleName();
+ @XmlTransient
public String getType() {
return type;
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
index 2c4ddcc..56c90b7 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
@@ -58,7 +58,6 @@ public class DependencyInfo {
* If auto-deployment is enabled for the dependency, the dependency is
* automatically deployed if it is not specified in the provided topology.
*/
- @XmlElement(name="auto-deploy")
private AutoDeployInfo m_autoDeploy;
/**
@@ -124,6 +123,7 @@ public class DependencyInfo {
*
* @return auto-deploy information
*/
+ @XmlElement(name="auto-deploy")
public AutoDeployInfo getAutoDeploy() {
return m_autoDeploy;
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
index 31fcb9d..5d5db52 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
@@ -34,6 +34,7 @@ import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlList;
+import javax.xml.bind.annotation.XmlTransient;
import org.apache.ambari.server.controller.StackConfigurationResponse;
import org.w3c.dom.Element;
@@ -47,7 +48,9 @@ public class PropertyInfo {
@XmlElement(name = "display-name")
private String displayName;
+ @XmlTransient
private String filename;
+
private boolean deleted;
@XmlElement(name="on-ambari-upgrade", required = true)
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
index 59cee41..674637f 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
@@ -59,7 +59,7 @@ import com.google.common.collect.Multimaps;
@XmlAccessorType(XmlAccessType.FIELD)
@JsonFilter("propertiesfilter")
-public class ServiceInfo implements Validable {
+public class ServiceInfo implements Validable, Cloneable {
public static final AbstractMap.SimpleEntry<String, String>
DEFAULT_SERVICE_INSTALLABLE_PROPERTY = new
AbstractMap.SimpleEntry<>("installable", "true");
public static final AbstractMap.SimpleEntry<String, String>
DEFAULT_SERVICE_MANAGED_PROPERTY = new AbstractMap.SimpleEntry<>("managed",
"true");
@@ -195,6 +195,7 @@ public class ServiceInfo implements Validable {
@XmlTransient
private File widgetsDescriptorFile = null;
+ @XmlTransient
private StackRoleCommandOrder roleCommandOrder;
@XmlTransient
@@ -282,6 +283,7 @@ public class ServiceInfo implements Validable {
* at getter.
* Added at schema ver 2
*/
+ @XmlTransient
private volatile Map<String, ServiceOsSpecific> serviceOsSpecificsMap;
/**
@@ -469,6 +471,56 @@ public class ServiceInfo implements Validable {
this.properties = properties;
}
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ ServiceInfo clone = (ServiceInfo) super.clone();
+ clone.setSchemaVersion(schemaVersion);
+ clone.setName(name);
+ clone.setDisplayName(displayName);
+ clone.setVersion(version);
+ clone.setComment(comment);
+ clone.setServiceType(serviceType);
+ clone.setSelection(selection);
+ clone.components = components;
+ clone.setDeleted(isDeleted);
+ clone.setConfigDependencies(configDependencies);
+ clone.setExcludedConfigTypes(excludedConfigTypes);
+ clone.setMonitoringService(monitoringService);
+ clone.setRestartRequiredAfterChange(restartRequiredAfterChange);
+ clone.setRestartRequiredAfterRackChange(restartRequiredAfterRackChange);
+ clone.setParent(parent);
+ if(metricsFile != null) {
+ clone.metricsFileName = metricsFile.getName();
+ }
+ if(widgetsDescriptorFile != null) {
+ clone.widgetsFileName = widgetsDescriptorFile.getName();
+ }
+ clone.setCredentialStoreInfo(credentialStoreInfo);
+ clone.setServicePropertyList(servicePropertyList);
+ clone.configDir = configDir;
+
+ clone.themesDir = themesDir;
+ clone.setThemesMap(themesMap);
+ if(this.themesMap != null) {
+ clone.themes = new ArrayList(this.themesMap.values());
+ }
+
+ clone.quickLinksConfigurationsDir = quickLinksConfigurationsDir;
+ clone.setQuickLinksConfigurationsMap(quickLinksConfigurationsMap);
+ if(this.quickLinksConfigurationsMap != null) {
+ clone.quickLinksConfigurations = new
ArrayList(this.quickLinksConfigurationsMap.values());
+ }
+
+ clone.serviceOsSpecificsMap = serviceOsSpecificsMap;
+ if(this.serviceOsSpecificsMap != null) {
+ clone.serviceOsSpecifics = new
ArrayList<>(serviceOsSpecificsMap.values());
+ }
+
+ clone.setCommandScript(commandScript);
+ clone.setRequiredServices(requiredServices);
+ return clone;
+ }
+
public List<ComponentInfo> getComponents() {
if (components == null) {
components = new ArrayList<>();
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigurationXml.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigurationXml.java
index 0f471fe..8df3b46 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigurationXml.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigurationXml.java
@@ -25,6 +25,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@@ -38,6 +40,7 @@ import org.apache.ambari.server.state.PropertyInfo;
* The elements within a service's configuration file.
*/
@XmlRootElement(name="configuration")
+@XmlAccessorType(XmlAccessType.FIELD)
public class ConfigurationXml implements Validable{
@XmlAnyAttribute
@@ -92,6 +95,14 @@ public class ConfigurationXml implements Validable{
return properties;
}
+ /***
+ *
+ * @param listProperties
+ */
+ public void setProperties(List<PropertyInfo> listProperties) {
+ this.properties = listProperties;
+ }
+
public Map<QName, String> getAttributes() {
return attributes;
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/StackMetainfoXml.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/StackMetainfoXml.java
index 753c2b8..a4d3fe5 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/StackMetainfoXml.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/StackMetainfoXml.java
@@ -40,10 +40,18 @@ public class StackMetainfoXml implements Validable{
return minJdk;
}
+ public void setMinJdk(String minJdk) {
+ this.minJdk = minJdk;
+ }
+
public String getMaxJdk() {
return maxJdk;
}
+ public void setMaxJdk(String maxJdk) {
+ this.maxJdk = maxJdk;
+ }
+
@XmlElement(name="minJdk")
private String minJdk = null;
@@ -52,6 +60,10 @@ public class StackMetainfoXml implements Validable{
@XmlElement(name="extends")
private String extendsVersion = null;
+
+ public void setExtendsVersion(String extendsVersion) {
+ this.extendsVersion = extendsVersion;
+ }
@XmlElement(name="versions")
private Version version = new Version();
@@ -108,10 +120,14 @@ public class StackMetainfoXml implements Validable{
public Version getVersion() {
return version;
}
+
+ public void setVersion(Version version) {
+ this.version = version;
+ }
@XmlAccessorType(XmlAccessType.FIELD)
public static class Version {
- private Version() {
+ public Version() {
}
private boolean active = false;
private String upgrade = null;
@@ -122,6 +138,10 @@ public class StackMetainfoXml implements Validable{
public boolean isActive() {
return active;
}
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
/**
* @return the upgrade version number, if set
@@ -129,8 +149,13 @@ public class StackMetainfoXml implements Validable{
public String getUpgrade() {
return upgrade;
}
-
-
+
+ /**
+ * Sets the upgrade version number
+ */
+ public void setUpgrade(String upgradeVersion) {
+ upgrade = upgradeVersion;
+ }
}
}
diff --git
a/ambari-server/src/main/resources/common-services/AMBARI_INFRA_SOLR/0.1.0/service_advisor.py
b/ambari-server/src/main/resources/common-services/AMBARI_INFRA_SOLR/0.1.0/service_advisor.py
index 581cbcd..5e25431 100644
---
a/ambari-server/src/main/resources/common-services/AMBARI_INFRA_SOLR/0.1.0/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/AMBARI_INFRA_SOLR/0.1.0/service_advisor.py
@@ -25,6 +25,8 @@ import traceback
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/service_advisor.py
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/service_advisor.py
index a7b125b..ebfe973 100644
---
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/service_advisor.py
@@ -32,6 +32,8 @@ from resource_management.core.logger import Logger
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git
a/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/service_advisor.py
b/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/service_advisor.py
index 434228d..544ff19 100644
---
a/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/service_advisor.py
@@ -26,6 +26,8 @@ import traceback
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git
a/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/service_advisor.py
b/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/service_advisor.py
index ed303df..b9244df 100644
---
a/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/service_advisor.py
@@ -25,6 +25,8 @@ import traceback
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git
a/ambari-server/src/main/resources/common-services/PXF/3.0.0/service_advisor.py
b/ambari-server/src/main/resources/common-services/PXF/3.0.0/service_advisor.py
index d2a80a9..55899b1 100644
---
a/ambari-server/src/main/resources/common-services/PXF/3.0.0/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/PXF/3.0.0/service_advisor.py
@@ -23,6 +23,8 @@ import traceback
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git
a/ambari-server/src/main/resources/common-services/ZEPPELIN/0.7.0/service_advisor.py
b/ambari-server/src/main/resources/common-services/ZEPPELIN/0.7.0/service_advisor.py
index 4efb629..85e98ce 100644
---
a/ambari-server/src/main/resources/common-services/ZEPPELIN/0.7.0/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/ZEPPELIN/0.7.0/service_advisor.py
@@ -31,6 +31,8 @@ from resource_management.core.logger import Logger
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git
a/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.9/service_advisor.py
b/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.9/service_advisor.py
index fbc868d..bb93a78 100644
---
a/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.9/service_advisor.py
+++
b/ambari-server/src/main/resources/common-services/ZOOKEEPER/3.4.9/service_advisor.py
@@ -29,6 +29,8 @@ import inspect
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp:
diff --git a/ambari-server/src/main/resources/scripts/stack_advisor.py
b/ambari-server/src/main/resources/scripts/stack_advisor.py
index b39a6e8..b7a2ff7 100755
--- a/ambari-server/src/main/resources/scripts/stack_advisor.py
+++ b/ambari-server/src/main/resources/scripts/stack_advisor.py
@@ -48,6 +48,10 @@ STACK_ADVISOR_DEFAULT_IMPL_CLASS = 'DefaultStackAdvisor'
STACK_ADVISOR_IMPL_PATH_TEMPLATE = os.path.join(STACKS_DIRECTORY,
'{0}/{1}/services/stack_advisor.py')
STACK_ADVISOR_IMPL_CLASS_TEMPLATE = '{0}{1}StackAdvisor'
+# After merging stack definitions, stack advisor may have deeper inheritance
than the merged stack,
+# The extra classes are defined in this directory
+STACK_ADVISOR_BASE_MODULES = os.path.join(SCRIPT_DIRECTORY,
'../stacks/{0}/{1}/stack-advisors')
+
ADVISOR_CONTEXT = "advisor_context"
CALL_TYPE = "call_type"
@@ -156,6 +160,8 @@ def instantiateStackAdvisor(stackName, stackVersion,
parentVersions):
versions = [stackVersion]
versions.extend(parentVersions)
+ sys.path.append(STACK_ADVISOR_BASE_MODULES.format(stackName, versions[-1]))
+
for version in reversed(versions):
try:
path = STACK_ADVISOR_IMPL_PATH_TEMPLATE.format(stackName, version)
diff --git
a/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
b/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
index aefb603..53f0b4d 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.1/services/stack_advisor.py
@@ -22,6 +22,11 @@ import socket
# Local Imports
+try:
+ from stack_advisor_hdp206 import *
+except ImportError:
+ #Ignore ImportError
+ print("stack_advisor_hdp206 not found")
class HDP21StackAdvisor(HDP206StackAdvisor):
diff --git
a/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
b/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
index 4cb0d9e..4af9764 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/stack_advisor.py
@@ -29,6 +29,11 @@ import xml.etree.ElementTree as ET
# Local Imports
+try:
+ from stack_advisor_hdp21 import *
+except ImportError:
+ #Ignore ImportError
+ print("stack_advisor_hdp21 not found")
class HDP22StackAdvisor(HDP21StackAdvisor):
diff --git
a/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
b/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
index ac4632b..8dc6877 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
@@ -26,6 +26,11 @@ import socket
# Local Imports
+try:
+ from stack_advisor_hdp22 import *
+except ImportError:
+ #Ignore ImportError
+ print("stack_advisor_hdp22 not found")
DB_TYPE_DEFAULT_PORT_MAP = {"MYSQL":"3306", "ORACLE":"1521",
"POSTGRES":"5432", "MSSQL":"1433", "SQLA":"2638"}
diff --git
a/ambari-server/src/main/resources/stacks/HDP/2.4/services/stack_advisor.py
b/ambari-server/src/main/resources/stacks/HDP/2.4/services/stack_advisor.py
index 985c101..bcfb908 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.4/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.4/services/stack_advisor.py
@@ -17,6 +17,11 @@ See the License for the specific language governing
permissions and
limitations under the License.
"""
+try:
+ from stack_advisor_hdp23 import *
+except ImportError:
+ #Ignore ImportError
+ print("stack_advisor_hdp23 not found")
class HDP24StackAdvisor(HDP23StackAdvisor):
pass
diff --git
a/ambari-server/src/main/resources/stacks/HDP/2.5/services/stack_advisor.py
b/ambari-server/src/main/resources/stacks/HDP/2.5/services/stack_advisor.py
index 40c583c..c23a067 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.5/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.5/services/stack_advisor.py
@@ -24,6 +24,11 @@ from ambari_commons.str_utils import string_set_equals
from resource_management.core.exceptions import Fail
from resource_management.libraries.functions.get_bare_principal import
get_bare_principal
+try:
+ from stack_advisor_hdp24 import *
+except ImportError:
+ #Ignore ImportError
+ print("stack_advisor_hdp24 not found")
class HDP25StackAdvisor(HDP24StackAdvisor):
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/metainfo.xml
b/ambari-server/src/main/resources/stacks/HDP/2.6/metainfo.xml
index a3c3d8b..b74369f 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/metainfo.xml
@@ -20,4 +20,6 @@
<active>false</active>
</versions>
<extends>2.5</extends>
+ <minJdk>1.7</minJdk>
+ <maxJdk>1.8</maxJdk>
</metainfo>
diff --git
a/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
b/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
index b3acd5e..88cd7ac 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/stack_advisor.py
@@ -22,6 +22,11 @@ import re
from resource_management.libraries.functions import format
from resource_management.libraries.functions.version import compare_versions
+try:
+ from stack_advisor_hdp25 import *
+except ImportError:
+ #Ignore ImportError
+ print("stack_advisor_hdp25 not found")
class HDP26StackAdvisor(HDP25StackAdvisor):
def __init__(self):
diff --git
a/contrib/management-packs/microsoft-r_mpack/src/main/resources/common-services/MICROSOFT_R_SERVER/8.0.5/service_advisor.py
b/contrib/management-packs/microsoft-r_mpack/src/main/resources/common-services/MICROSOFT_R_SERVER/8.0.5/service_advisor.py
index 0ecc310..b60157c 100644
---
a/contrib/management-packs/microsoft-r_mpack/src/main/resources/common-services/MICROSOFT_R_SERVER/8.0.5/service_advisor.py
+++
b/contrib/management-packs/microsoft-r_mpack/src/main/resources/common-services/MICROSOFT_R_SERVER/8.0.5/service_advisor.py
@@ -26,6 +26,8 @@ import traceback
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STACKS_DIR = os.path.join(SCRIPT_DIR, '../../../../../stacks/')
PARENT_FILE = os.path.join(STACKS_DIR, 'service_advisor.py')
+if "BASE_SERVICE_ADVISOR" in os.environ:
+ PARENT_FILE = os.environ["BASE_SERVICE_ADVISOR"]
try:
with open(PARENT_FILE, 'rb') as fp: