Repository: ambari Updated Branches: refs/heads/trunk acc12fb72 -> f1ca09c03
http://git-wip-us.apache.org/repos/asf/ambari/blob/f1ca09c0/serviceadvisor/pom.xml ---------------------------------------------------------------------- diff --git a/serviceadvisor/pom.xml b/serviceadvisor/pom.xml new file mode 100644 index 0000000..ecf6d8b --- /dev/null +++ b/serviceadvisor/pom.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <!-- Can compile this project independently, cd serviceadvisor ; mvn clean package install + + To test independently without needing the rest of Ambari, simply compile and run as, + java -jar serviceadvisor-$VERSION.jar [ACTION] [HOSTS_FILE.json] [SERVICES_FILE.json] + --> + <groupId>serviceadvisor</groupId> + <artifactId>serviceadvisor</artifactId> + <name>Service Advisor</name> + <version>1.0.0.0-SNAPSHOT</version> + <description>Service Advisor</description> + + <dependencies> + <dependency> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.6</version> + </dependency> + + <!-- Log Factory logging + The main class is expected to write to stdout and stderr appropriately. + --> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.20</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.0</version> + </dependency> + + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.4</version> + </dependency> + </dependencies> + + <pluginRepositories> + <pluginRepository> + <id>oss.sonatype.org</id> + <name>OSS Sonatype Staging</name> + <url>https://oss.sonatype.org/content/groups/staging</url> + </pluginRepository> + </pluginRepositories> + + <packaging>jar</packaging> + <!-- Run with mvn clean package . + Execute as, java -jar serviceadvisor-$VERSION.jar + --> + <build> + <plugins> + <!-- + The next 2 plugins are to include the main class in the Jar and to create a single jar with all of the dependencies. + It conflicts with the maven-compiler-plugin since the jar created is different. + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <mainClass>org.apache.ambari.stackadvisor.StackAdvisor</mainClass> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>1.6</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + </execution> + </executions> + </plugin> + --> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.2</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/ambari/blob/f1ca09c0/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisor.java ---------------------------------------------------------------------- diff --git a/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisor.java b/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisor.java new file mode 100644 index 0000000..77c482a --- /dev/null +++ b/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisor.java @@ -0,0 +1,147 @@ +/** + * 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.serviceadvisor; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang.StringUtils; + +/** + * Class that can be called either through its jar or using its run method. + * The goal is to invoke a Service Advisor. + * Right now, it is backward compatible by invoking the python script and does not know which service is affected. + */ +public class ServiceAdvisor { + protected static Log LOG = LogFactory.getLog(ServiceAdvisor.class); + + private static String USAGE = "Usage: java -jar serviceadvisor.jar [ACTION] [HOSTS_FILE.json] [SERVICES_FILE.json] [OUTPUT.txt] [ERRORS.txt]"; + private static String PYTHON_STACK_ADVISOR_SCRIPT = "/var/lib/ambari-server/resources/scripts/stack_advisor.py"; + + /** + * Entry point for calling this class through its jar. + * @param args + */ + public static void main(String[] args) { + if (args.length != 5) { + System.err.println(String.format("Wrong number of arguments. %s", USAGE)); + System.exit(1); + } + + String action = args[0]; + String hostsFile = args[1]; + String servicesFile = args[2]; + String outputFile = args[3]; + String errorFile = args[4]; + + int exitCode = run(action, hostsFile, servicesFile, outputFile, errorFile); + System.exit(exitCode); + } + + public static int run(String action, String hostsFile, String servicesFile, String outputFile, String errorFile) { + LOG.info(String.format("ServiceAdvisor. Received arguments. Action: %s, Hosts File: %s, Services File: %s", action, hostsFile, servicesFile)); + int returnCode = -1; + + try { + ServiceAdvisorCommandType commandType = ServiceAdvisorCommandType.getEnum(action); + + // TODO, load each Service's Service Advisor at Start Time and call it instead of Python command below. + + ProcessBuilder builder = preparePythonShellCommand(commandType, hostsFile, servicesFile, outputFile, errorFile); + returnCode = launchProcess(builder); + } catch (IllegalArgumentException e) { + List<ServiceAdvisorCommandType> values = EnumUtils.getEnumList(ServiceAdvisorCommandType.class); + List<String> stringValues = new ArrayList<String>(); + for (ServiceAdvisorCommandType value : values) { + stringValues.add(value.toString()); + } + LOG.error("ServiceAdvisor. Illegal Argument. Action must be one of " + StringUtils.join(stringValues.toArray(), ", ")); + return -1; + } catch (Exception e) { + LOG.error("ServiceAdvisor. Failed with " + e.getMessage()); + return -1; + } + return returnCode; + } + + /** + * Generate a process to invoke a Python command for the old-style Stack Advisor. + * @param commandType Command Type + * @param hostsFile hosts.json file + * @param servicesFile services.json file + * @param outputFile output.txt + * @param errorFile error.txt + * @return Process that can launch. + */ + private static ProcessBuilder preparePythonShellCommand(ServiceAdvisorCommandType commandType, String hostsFile, String servicesFile, String outputFile, String errorFile) { + List<String> builderParameters = new ArrayList<String>(); + + if (System.getProperty("os.name").contains("Windows")) { + builderParameters.add("cmd"); + builderParameters.add("/c"); + } else { + builderParameters.add("sh"); + builderParameters.add("-c"); + } + + StringBuilder commandString = new StringBuilder(); + commandString.append(PYTHON_STACK_ADVISOR_SCRIPT + " "); + + commandString.append(commandType.toString()).append(" "); + commandString.append(hostsFile).append(" "); + commandString.append(servicesFile).append(" "); + commandString.append("1> "); + commandString.append(outputFile).append(" "); + commandString.append("2>"); + commandString.append(errorFile).append(" "); + + builderParameters.add(commandString.toString()); + + LOG.info("ServiceAdvisor. Python command is: " + builderParameters.toString()); + + return new ProcessBuilder(builderParameters); + } + + /** + * Launch a process, wait for it to finish, and return its exit code. + * @param builder Process Builder + * @return Exit Code + * @throws Exception + */ + private static int launchProcess(ProcessBuilder builder) throws Exception { + int exitCode = -1; + Process process = null; + try { + process = builder.start(); + exitCode = process.waitFor(); + } catch (Exception ioe) { + String message = "Error executing Service Advisor: "; + LOG.error(message, ioe); + throw new Exception(message + ioe.getMessage()); + } finally { + if (process != null) { + process.destroy(); + } + } + return exitCode; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/f1ca09c0/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java ---------------------------------------------------------------------- diff --git a/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java b/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java new file mode 100644 index 0000000..f067668 --- /dev/null +++ b/serviceadvisor/src/main/java/org/apache/ambari/serviceadvisor/ServiceAdvisorCommandType.java @@ -0,0 +1,63 @@ +/** + * 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.serviceadvisor; + + +// TODO, use this class instead of org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommandType +public enum ServiceAdvisorCommandType { + + RECOMMEND_COMPONENT_LAYOUT("recommend-component-layout"), + + VALIDATE_COMPONENT_LAYOUT("validate-component-layout"), + + RECOMMEND_CONFIGURATIONS("recommend-configurations"), + + RECOMMEND_CONFIGURATION_DEPENDENCIES("recommend-configuration-dependencies"), + + VALIDATE_CONFIGURATIONS("validate-configurations"); + private final String name; + + private ServiceAdvisorCommandType(String name) { + this.name = name; + } + + public String getValue() { + return this.name.toLowerCase(); + } + + @Override + public String toString() { + return this.name; + } + + /** + * Instead of Enum.valueOf("value"), use this method instead to map the string to the correct Enum. + * @param name Name with lowercase and dashes. + * @return Enum that matches the string. + */ + public static ServiceAdvisorCommandType getEnum(String name) { + for (ServiceAdvisorCommandType v : values()) { + if (v.getValue().equalsIgnoreCase(name.replace("_", "-"))) { + return v; + } + } + throw new IllegalArgumentException(); + } +} \ No newline at end of file