You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ji...@apache.org on 2016/12/07 21:10:18 UTC
[18/76] [abbrv] hadoop git commit: YARN-5461. Initial code ported
from slider-core module. (jianhe)
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentRoles.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentRoles.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentRoles.java
new file mode 100644
index 0000000..281895a
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentRoles.java
@@ -0,0 +1,38 @@
+/*
+ * 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.slider.providers.agent;
+
+import org.apache.slider.providers.ProviderRole;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AgentRoles {
+
+ /**
+ * List of roles Agent provider does not have any roles by default. All roles are read from the application
+ * specification.
+ */
+ protected static final List<ProviderRole> ROLES =
+ new ArrayList<ProviderRole>();
+
+ public static List<ProviderRole> getRoles() {
+ return ROLES;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentUtils.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentUtils.java
new file mode 100644
index 0000000..cfcfc5d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/AgentUtils.java
@@ -0,0 +1,134 @@
+/*
+ * 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.slider.providers.agent;
+
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.slider.common.tools.SliderFileSystem;
+import org.apache.slider.common.tools.SliderUtils;
+import org.apache.slider.core.exceptions.BadConfigException;
+import org.apache.slider.providers.agent.application.metadata.AbstractMetainfoParser;
+import org.apache.slider.providers.agent.application.metadata.AddonPackageMetainfoParser;
+import org.apache.slider.providers.agent.application.metadata.DefaultConfig;
+import org.apache.slider.providers.agent.application.metadata.DefaultConfigParser;
+import org.apache.slider.providers.agent.application.metadata.Metainfo;
+import org.apache.slider.providers.agent.application.metadata.MetainfoParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ */
+public class AgentUtils {
+ private static final Logger log = LoggerFactory.getLogger(AgentUtils.class);
+
+ public static Metainfo getApplicationMetainfoFromSummaryFile(
+ SliderFileSystem fileSystem, String metainfoPath, boolean metainfoForAddon) {
+ FileSystem fs = fileSystem.getFileSystem();
+ Path appPathXML = new Path(metainfoPath + ".metainfo.xml");
+ Path appPathJson = new Path(metainfoPath + ".metainfo.json");
+ Path appPathUsed = null;
+ try {
+ FSDataInputStream appStream = null;
+ if (fs.exists(appPathXML)) {
+ appPathUsed = appPathXML;
+ appStream = fs.open(appPathXML);
+ return parseMetainfo(appStream, metainfoForAddon, "xml");
+ } else if (fs.exists(appPathJson)) {
+ appPathUsed = appPathJson;
+ appStream = fs.open(appPathJson);
+ return parseMetainfo(appStream, metainfoForAddon, "json");
+ }
+ } catch (IOException e) {
+ log.info("Failed to get metainfo from summary file {} - {}", appPathUsed,
+ e.getMessage());
+ log.debug("Failed to get metainfo", e);
+ }
+ return null;
+ }
+
+ public static Metainfo getApplicationMetainfo(SliderFileSystem fileSystem,
+ String metainfoPath, boolean metainfoForAddon) throws IOException,
+ BadConfigException {
+ log.info("Reading metainfo at {}", metainfoPath);
+ Metainfo metainfo = getApplicationMetainfoFromSummaryFile(fileSystem,
+ metainfoPath, metainfoForAddon);
+ if (metainfo != null) {
+ log.info("Got metainfo from summary file");
+ return metainfo;
+ }
+
+ FileSystem fs = fileSystem.getFileSystem();
+ Path appPath = new Path(metainfoPath);
+
+ InputStream metainfoJsonStream = SliderUtils.getApplicationResourceInputStream(
+ fs, appPath, "metainfo.json");
+ if (metainfoJsonStream == null) {
+ InputStream metainfoXMLStream = SliderUtils.getApplicationResourceInputStream(
+ fs, appPath, "metainfo.xml");
+ if (metainfoXMLStream != null) {
+ metainfo = parseMetainfo(metainfoXMLStream, metainfoForAddon, "xml");
+ }
+ } else {
+ metainfo = parseMetainfo(metainfoJsonStream, metainfoForAddon, "json");
+ }
+
+ if (metainfo == null) {
+ log.error("metainfo is unavailable at {}.", metainfoPath);
+ throw new FileNotFoundException("metainfo.xml/json is required in app package. " +
+ appPath);
+ }
+ return metainfo;
+ }
+
+ private static Metainfo parseMetainfo(InputStream stream,
+ boolean metainfoForAddon, String type) throws IOException {
+ AbstractMetainfoParser metainfoParser = null;
+ if (metainfoForAddon) {
+ metainfoParser = new AddonPackageMetainfoParser();
+ } else {
+ metainfoParser = new MetainfoParser();
+ }
+ if (type.equals("xml")) {
+ return metainfoParser.fromXmlStream(stream);
+ } else if (type.equals("json")) {
+ return metainfoParser.fromJsonStream(stream);
+ }
+ return null;
+ }
+
+ static DefaultConfig getDefaultConfig(SliderFileSystem fileSystem,
+ String appDef, String configFileName)
+ throws IOException {
+ // this is the path inside the zip file
+ String fileToRead = "configuration/" + configFileName;
+ log.info("Reading default config file {} at {}", fileToRead, appDef);
+ InputStream configStream = SliderUtils.getApplicationResourceInputStream(
+ fileSystem.getFileSystem(), new Path(appDef), fileToRead);
+ if (configStream == null) {
+ log.error("{} is unavailable at {}.", fileToRead, appDef);
+ throw new IOException("Expected config file " + fileToRead + " is not available.");
+ }
+
+ return new DefaultConfigParser().parse(configStream);
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/Command.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/Command.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/Command.java
new file mode 100644
index 0000000..647cb86
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/Command.java
@@ -0,0 +1,59 @@
+/*
+ * 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.slider.providers.agent;
+
+/** The states a component instance can be. */
+public enum Command {
+ NOP, // do nothing
+ INSTALL, // Install the component
+ INSTALL_ADDON, // Install add on packages if any
+ START, // Start the component
+ STOP, // Stop the component
+ UPGRADE, // The component will undergo upgrade
+ TERMINATE; // Send terminate signal to agent
+
+ public static Command getCommand(String commandVal) {
+ if (commandVal.equals(Command.START.toString())) {
+ return Command.START;
+ }
+ if (commandVal.equals(Command.INSTALL.toString())) {
+ return Command.INSTALL;
+ }
+ if (commandVal.equals(Command.STOP.toString())) {
+ return Command.STOP;
+ }
+ if (commandVal.equals(Command.UPGRADE.toString())) {
+ return Command.UPGRADE;
+ }
+ if (commandVal.equals(Command.TERMINATE.toString())) {
+ return Command.TERMINATE;
+ }
+
+ return Command.NOP;
+ }
+
+ public static String transform(Command command, boolean isUpgrade) {
+ switch (command) {
+ case STOP:
+ return isUpgrade ? "UPGRADE_STOP" : command.name();
+ default:
+ return command.name();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/CommandResult.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/CommandResult.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/CommandResult.java
new file mode 100644
index 0000000..35d9116
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/CommandResult.java
@@ -0,0 +1,40 @@
+/*
+ * 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.slider.providers.agent;
+
+/** Command results. */
+public enum CommandResult {
+ IN_PROGRESS, // Command is in progress
+ COMPLETED, // Command has successfully completed
+ FAILED; // Command has failed
+
+ public static CommandResult getCommandResult(String commandResVal) {
+ if (commandResVal.equals(CommandResult.COMPLETED.toString())) {
+ return CommandResult.COMPLETED;
+ }
+ if (commandResVal.equals(CommandResult.FAILED.toString())) {
+ return CommandResult.FAILED;
+ }
+ if (commandResVal.equals(CommandResult.IN_PROGRESS.toString())) {
+ return CommandResult.IN_PROGRESS;
+ }
+
+ throw new IllegalArgumentException("Unrecognized value " + commandResVal);
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentCommandOrder.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentCommandOrder.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentCommandOrder.java
new file mode 100644
index 0000000..91f1259
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentCommandOrder.java
@@ -0,0 +1,181 @@
+/*
+ * 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.slider.providers.agent;
+
+import org.apache.slider.providers.agent.application.metadata.CommandOrder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores the command dependency order for all components in a service. <commandOrder>
+ * <command>SUPERVISOR-START</command> <requires>NIMBUS-STARTED</requires> </commandOrder> Means, SUPERVISOR START
+ * requires NIMBUS to be STARTED
+ */
+public class ComponentCommandOrder {
+ public static final Logger log =
+ LoggerFactory.getLogger(ComponentCommandOrder.class);
+ private static char SPLIT_CHAR = '-';
+ Map<Command, Map<String, List<ComponentState>>> dependencies =
+ new HashMap<Command, Map<String, List<ComponentState>>>();
+
+ public ComponentCommandOrder(List<CommandOrder> commandOrders) {
+ if (commandOrders != null && commandOrders.size() > 0) {
+ for (CommandOrder commandOrder : commandOrders) {
+ ComponentCommand componentCmd = getComponentCommand(commandOrder.getCommand());
+ String requires = commandOrder.getRequires();
+ List<ComponentState> requiredStates = parseRequiredStates(requires);
+ if (requiredStates.size() > 0) {
+ Map<String, List<ComponentState>> compDep = dependencies.get(componentCmd.command);
+ if (compDep == null) {
+ compDep = new HashMap<>();
+ dependencies.put(componentCmd.command, compDep);
+ }
+
+ List<ComponentState> requirements = compDep.get(componentCmd.componentName);
+ if (requirements == null) {
+ requirements = new ArrayList<>();
+ compDep.put(componentCmd.componentName, requirements);
+ }
+
+ requirements.addAll(requiredStates);
+ }
+ }
+ }
+ }
+
+ private List<ComponentState> parseRequiredStates(String requires) {
+ if (requires == null || requires.length() < 2) {
+ throw new IllegalArgumentException("Input cannot be null and must contain component and state.");
+ }
+
+ String[] componentStates = requires.split(",");
+ List<ComponentState> retList = new ArrayList<ComponentState>();
+ for (String componentStateStr : componentStates) {
+ retList.add(getComponentState(componentStateStr));
+ }
+
+ return retList;
+ }
+
+ private ComponentCommand getComponentCommand(String compCmdStr) {
+ if (compCmdStr == null || compCmdStr.trim().length() < 2) {
+ throw new IllegalArgumentException("Input cannot be null and must contain component and command.");
+ }
+
+ compCmdStr = compCmdStr.trim();
+ int splitIndex = compCmdStr.lastIndexOf(SPLIT_CHAR);
+ if (splitIndex == -1 || splitIndex == 0 || splitIndex == compCmdStr.length() - 1) {
+ throw new IllegalArgumentException("Input does not appear to be well-formed.");
+ }
+ String compStr = compCmdStr.substring(0, splitIndex);
+ String cmdStr = compCmdStr.substring(splitIndex + 1);
+
+ Command cmd = Command.valueOf(cmdStr);
+
+ if (cmd != Command.START) {
+ throw new IllegalArgumentException("Dependency order can only be specified for START.");
+ }
+ return new ComponentCommand(compStr, cmd);
+ }
+
+ private ComponentState getComponentState(String compStStr) {
+ if (compStStr == null || compStStr.trim().length() < 2) {
+ throw new IllegalArgumentException("Input cannot be null.");
+ }
+
+ compStStr = compStStr.trim();
+ int splitIndex = compStStr.lastIndexOf(SPLIT_CHAR);
+ if (splitIndex == -1 || splitIndex == 0 || splitIndex == compStStr.length() - 1) {
+ throw new IllegalArgumentException("Input does not appear to be well-formed.");
+ }
+ String compStr = compStStr.substring(0, splitIndex);
+ String stateStr = compStStr.substring(splitIndex + 1);
+
+ State state = State.valueOf(stateStr);
+ if (state != State.STARTED && state != State.INSTALLED) {
+ throw new IllegalArgumentException("Dependency order can only be specified against STARTED/INSTALLED.");
+ }
+ return new ComponentState(compStr, state);
+ }
+
+ // dependency is still on component level, but not package level
+ // so use component name to check dependency, not component-package
+ public boolean canExecute(String component, Command command, Collection<ComponentInstanceState> currentStates) {
+ boolean canExecute = true;
+ if (dependencies.containsKey(command) && dependencies.get(command).containsKey(component)) {
+ List<ComponentState> required = dependencies.get(command).get(component);
+ for (ComponentState stateToMatch : required) {
+ for (ComponentInstanceState currState : currentStates) {
+ log.debug("Checking schedule {} {} against dependency {} is {}",
+ component, command, currState.getComponentName(), currState.getState());
+ if (currState.getComponentName().equals(stateToMatch.componentName)) {
+ if (currState.getState() != stateToMatch.state) {
+ if (stateToMatch.state == State.STARTED) {
+ log.info("Cannot schedule {} {} as dependency {} is {}",
+ component, command, currState.getComponentName(), currState.getState());
+ canExecute = false;
+ } else {
+ //state is INSTALLED
+ if (currState.getState() != State.STARTING && currState.getState() != State.STARTED) {
+ log.info("Cannot schedule {} {} as dependency {} is {}",
+ component, command, currState.getComponentName(), currState.getState());
+ canExecute = false;
+ }
+ }
+ }
+ }
+ if (!canExecute) {
+ break;
+ }
+ }
+ if (!canExecute) {
+ break;
+ }
+ }
+ }
+
+ return canExecute;
+ }
+
+ static class ComponentState {
+ public String componentName;
+ public State state;
+
+ public ComponentState(String componentName, State state) {
+ this.componentName = componentName;
+ this.state = state;
+ }
+ }
+
+ static class ComponentCommand {
+ public String componentName;
+ public Command command;
+
+ public ComponentCommand(String componentName, Command command) {
+ this.componentName = componentName;
+ this.command = command;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentInstanceState.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentInstanceState.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentInstanceState.java
new file mode 100644
index 0000000..6ee0ebb
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentInstanceState.java
@@ -0,0 +1,340 @@
+/*
+ * 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.slider.providers.agent;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.yarn.api.records.ContainerId;
+import org.apache.slider.providers.agent.application.metadata.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** This class implements a simple state machine for component instances. */
+public class ComponentInstanceState {
+ public static final Logger log =
+ LoggerFactory.getLogger(ComponentInstanceState.class);
+ private static int MAX_FAILURE_TOLERATED = 3;
+ private static String INVALID_TRANSITION_ERROR =
+ "Result %s for command %s is not expected for component %s in state %s.";
+
+ private final String componentName;
+ private final ContainerId containerId;
+ private final String containerIdAsString;
+ private final String applicationId;
+ private State state = State.INIT;
+ private State targetState = State.STARTED;
+ private int failuresSeen = 0;
+ private Boolean configReported = false;
+ private long lastHeartbeat = 0;
+ private String ip;
+ private String hostname;
+ private ContainerState containerState;
+
+ private Map<String, State> pkgStatuses;
+ private String nextPkgToInstall;
+
+ private boolean stopInitiated;
+
+ public ComponentInstanceState(String componentName,
+ ContainerId containerId,
+ String applicationId) {
+ this(componentName, containerId, applicationId,
+ new TreeMap<String, State>());
+ }
+
+ public ComponentInstanceState(String componentName,
+ ContainerId containerId,
+ String applicationId, Map<String, State> pkgStatuses) {
+ this.componentName = componentName;
+ this.containerId = containerId;
+ this.containerIdAsString = containerId.toString();
+ this.applicationId = applicationId;
+ this.containerState = ContainerState.INIT;
+ this.lastHeartbeat = System.currentTimeMillis();
+ this.pkgStatuses = pkgStatuses;
+ }
+
+ public String getComponentName() {
+ return componentName;
+ }
+
+ public Boolean getConfigReported() {
+ return configReported;
+ }
+
+ public void setConfigReported(Boolean configReported) {
+ this.configReported = configReported;
+ }
+
+ public ContainerState getContainerState() {
+ return containerState;
+ }
+
+ public void setContainerState(ContainerState containerState) {
+ this.containerState = containerState;
+ }
+
+ public long getLastHeartbeat() {
+ return lastHeartbeat;
+ }
+
+ /**
+ * Update the heartbeat, and change container state
+ * to mark as healthy if appropriate
+ * @param heartbeatTime last time the heartbeat was seen
+ * @return the current container state
+ */
+ public ContainerState heartbeat(long heartbeatTime) {
+ this.lastHeartbeat = heartbeatTime;
+ if(containerState == ContainerState.UNHEALTHY ||
+ containerState == ContainerState.INIT) {
+ containerState = ContainerState.HEALTHY;
+ }
+ return containerState;
+ }
+
+
+ public ContainerId getContainerId() {
+ return containerId;
+ }
+
+ public void commandIssued(Command command) {
+ commandIssued(command, false);
+ }
+
+ public void commandIssued(Command command, boolean isInUpgradeMode) {
+ Command expected = getNextCommand(isInUpgradeMode);
+ if (expected != command) {
+ throw new IllegalArgumentException("Command " + command + " is not allowed in state " + state);
+ }
+ if (expected == Command.INSTALL_ADDON) {
+ // for add on packages, the pkg must be nextPkgToInstall
+ State currentState = pkgStatuses.get(nextPkgToInstall);
+ log.debug("Command issued: component: {} is in {}", componentName,
+ currentState);
+ State nextState = currentState.getNextState(command);
+ pkgStatuses.put(nextPkgToInstall, nextState);
+ log.debug("Command issued: component: {} is now in {}", componentName,
+ nextState);
+ } else {
+ // for master package
+ state = state.getNextState(command);
+ }
+ }
+
+ public void applyCommandResult(CommandResult result, Command command,
+ String pkg) {
+ // if the heartbeat is for a package
+ // update that package's state in the component status
+ // and don't bother with the master pkg
+ if (StringUtils.isNotEmpty(pkg)
+ && !Component.MASTER_PACKAGE_NAME.equals(pkg)) {
+ log.debug("This result is for component: {} pkg: {}", componentName, pkg);
+ State previousPkgState = pkgStatuses.get(pkg);
+ log.debug("Currently component: {} pkg: {} is in state: {}",
+ componentName, pkg, previousPkgState.toString());
+ State nextPkgState = previousPkgState.getNextState(result);
+ pkgStatuses.put(pkg, nextPkgState);
+ log.debug("Component: {} pkg: {} next state: {}", componentName, pkg,
+ nextPkgState);
+ } else {
+ log.debug("This result is for component: {} master package",
+ componentName);
+ applyCommandResult(result, command);
+ }
+ }
+
+ public void applyCommandResult(CommandResult result, Command command) {
+ if (!this.state.couldHaveIssued(command)) {
+ throw new IllegalStateException("Invalid command " + command + " for state " + this.state);
+ }
+
+ try {
+ if (result == CommandResult.FAILED) {
+ failuresSeen++;
+ } else if (result == CommandResult.COMPLETED) {
+ failuresSeen = 0;
+ }
+ state = state.getNextState(result);
+ } catch (IllegalArgumentException e) {
+ String message = String.format(INVALID_TRANSITION_ERROR,
+ result.toString(),
+ command.toString(),
+ componentName,
+ state.toString());
+ log.warn(message);
+ throw new IllegalStateException(message);
+ }
+ }
+
+ public boolean hasPendingCommand() {
+ if (state.canIssueCommands() &&
+ state != targetState &&
+ failuresSeen < MAX_FAILURE_TOLERATED) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public Command getNextCommand() {
+ return getNextCommand(false);
+ }
+
+ public Command getNextCommand(boolean isInUpgradeMode) {
+ if (!hasPendingCommand()) {
+ nextPkgToInstall = null;
+ return Command.NOP;
+ }
+
+ log.debug("In getNextCommand, checking for component: {} ", componentName);
+ // if the master pkg is just installed, check if any add on pkg need to be
+ // installed
+ nextPkgToInstall = null;
+ if (state == State.INSTALLED) {
+ for (Map.Entry<String, State> pkgStatus : pkgStatuses.entrySet()) {
+ String pkg = pkgStatus.getKey();
+ State pkgState = pkgStatus.getValue();
+ log.debug("In getNextCommand, pkg: {} is in {}", pkg, pkgState);
+ if (pkgState == State.INSTALLING) {
+ // first check if any pkg is install in progress, if so, wait
+ // so we don't need to do anything, just return NOP
+ log.debug("In getNextCommand, pkg: {} we are issuing NOP", pkg);
+ nextPkgToInstall = pkg;
+ return Command.NOP;
+ } else if (pkgState == State.INIT) {
+ // temporarily storing pkg here
+ // in case no pkg in 'installing' state
+ // will return the package to install
+ nextPkgToInstall = pkg;
+ }
+ }
+ // when we reach here, no pkg is in 'installing' state
+ if (nextPkgToInstall != null) {
+ // nextPkgToInstall != null means some pkg is in INIT state
+ // issue 'install' to the pkg we have stored in nextPkgToInstall
+ log.debug("In getNextCommand, pkg: {} we are issuing install addon",
+ nextPkgToInstall);
+ return Command.INSTALL_ADDON;
+ }
+ }
+ return this.state.getSupportedCommand(isInUpgradeMode, stopInitiated);
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ @VisibleForTesting
+ protected void setState(State state) {
+ this.state = state;
+ }
+
+ public State getTargetState() {
+ return targetState;
+ }
+
+ public void setTargetState(State targetState) {
+ this.targetState = targetState;
+ }
+
+ public String getNextPkgToInstall() {
+ return nextPkgToInstall;
+ }
+
+ public boolean isStopInitiated() {
+ return stopInitiated;
+ }
+
+ public void setStopInitiated(boolean stopInitiated) {
+ this.stopInitiated = stopInitiated;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 1;
+
+ hashCode = hashCode ^ (componentName != null ? componentName.hashCode() : 0);
+ hashCode = hashCode ^ (containerIdAsString != null ? containerIdAsString.hashCode() : 0);
+ hashCode = hashCode ^ (applicationId != null ? applicationId.hashCode() : 0);
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ComponentInstanceState that = (ComponentInstanceState) o;
+
+ if (this.componentName != null ?
+ !this.componentName.equals(that.componentName) : this.componentName != null) {
+ return false;
+ }
+
+ if (this.containerIdAsString != null ?
+ !this.containerIdAsString.equals(that.containerIdAsString) : this.containerIdAsString != null) {
+ return false;
+ }
+
+ if (this.applicationId != null ?
+ !this.applicationId.equals(that.applicationId) : this.applicationId != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb =
+ new StringBuilder("ComponentInstanceState{");
+ sb.append("containerIdAsString='").append(containerIdAsString).append('\'');
+ sb.append(", state=").append(state);
+ sb.append(", failuresSeen=").append(failuresSeen);
+ sb.append(", lastHeartbeat=").append(lastHeartbeat);
+ sb.append(", containerState=").append(containerState);
+ sb.append(", componentName='").append(componentName).append('\'');
+ sb.append(", ip=").append(ip);
+ sb.append(", hostname='").append(hostname).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentTagProvider.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentTagProvider.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentTagProvider.java
new file mode 100644
index 0000000..68f63fa
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ComponentTagProvider.java
@@ -0,0 +1,127 @@
+/*
+ * 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.slider.providers.agent;
+
+import org.apache.slider.common.tools.SliderUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/** A simple tag provider that attempts to associate tags from 1-N to all container of a component */
+public class ComponentTagProvider {
+ private static final Logger log = LoggerFactory.getLogger(ComponentTagProvider.class);
+ private static String FREE = "free";
+ private final ConcurrentHashMap<String, ConcurrentHashMap<String, String>> allTags;
+
+ public ComponentTagProvider() {
+ allTags = new ConcurrentHashMap<String, ConcurrentHashMap<String, String>>();
+ }
+
+ /**
+ * Record an assigned tag to a container
+ *
+ * @param component
+ * @param containerId
+ * @param tag
+ */
+ public void recordAssignedTag(String component, String containerId, String tag) {
+ if (SliderUtils.isSet(component) && SliderUtils.isSet(containerId)) {
+ Integer key = null;
+ try {
+ key = Integer.valueOf(tag);
+ } catch (NumberFormatException nfe) {
+ //ignore
+ }
+ if (key != null && key > 0) {
+ ConcurrentHashMap<String, String> compTags = getComponentSpecificTags(component);
+ synchronized (compTags) {
+ for (int index = 1; index <= key.intValue(); index++) {
+ String tempKey = new Integer(index).toString();
+ if (!compTags.containsKey(tempKey)) {
+ compTags.put(tempKey, FREE);
+ }
+ }
+ compTags.put(key.toString(), containerId);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get a tag for container
+ *
+ * @param component
+ * @param containerId
+ *
+ * @return
+ */
+ public String getTag(String component, String containerId) {
+ if (SliderUtils.isSet(component) && SliderUtils.isSet(containerId)) {
+ ConcurrentHashMap<String, String> compTags = getComponentSpecificTags(component);
+ synchronized (compTags) {
+ for (String key : compTags.keySet()) {
+ if (compTags.get(key).equals(containerId)) {
+ return key;
+ }
+ }
+ for (String key : compTags.keySet()) {
+ if (compTags.get(key).equals(FREE)) {
+ compTags.put(key, containerId);
+ return key;
+ }
+ }
+ String newKey = new Integer(compTags.size() + 1).toString();
+ compTags.put(newKey, containerId);
+ return newKey;
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Release a tag associated with a container
+ *
+ * @param component
+ * @param containerId
+ */
+ public void releaseTag(String component, String containerId) {
+ if (SliderUtils.isSet(component) && SliderUtils.isSet(containerId)) {
+ ConcurrentHashMap<String, String> compTags = allTags.get(component);
+ if (compTags != null) {
+ synchronized (compTags) {
+ for (String key : compTags.keySet()) {
+ if (compTags.get(key).equals(containerId)) {
+ compTags.put(key, FREE);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private ConcurrentHashMap<String, String> getComponentSpecificTags(String component) {
+ if (!allTags.containsKey(component)) {
+ synchronized (allTags) {
+ if (!allTags.containsKey(component)) {
+ allTags.put(component, new ConcurrentHashMap<String, String>());
+ }
+ }
+ }
+ return allTags.get(component);
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ContainerState.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ContainerState.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ContainerState.java
new file mode 100644
index 0000000..0394ba2
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/ContainerState.java
@@ -0,0 +1,41 @@
+/*
+ * 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.slider.providers.agent;
+
+/** The states a component instance can be. */
+public enum ContainerState {
+ INIT, // Container is not net activated
+ HEALTHY, // Agent is heartbeating
+ UNHEALTHY, // Container is unhealthy - no heartbeat for some interval
+ HEARTBEAT_LOST; // Container is lost - request a new instance
+
+ /**
+ * Indicates whether or not it is a valid state to produce a command.
+ *
+ * @return true if command can be issued for this state.
+ */
+ public boolean canIssueCommands() {
+ switch (this) {
+ case HEALTHY:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/HeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/HeartbeatMonitor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/HeartbeatMonitor.java
new file mode 100644
index 0000000..4293916
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/HeartbeatMonitor.java
@@ -0,0 +1,130 @@
+/**
+ * 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.slider.providers.agent;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.apache.hadoop.yarn.api.records.ContainerId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+/** Monitors the container state and heartbeats. */
+public class HeartbeatMonitor implements Runnable {
+ protected static final Logger log =
+ LoggerFactory.getLogger(HeartbeatMonitor.class);
+ private final int threadWakeupInterval; //1 minute
+ private final AgentProviderService provider;
+ private volatile boolean shouldRun = true;
+ private Thread monitorThread = null;
+
+ public HeartbeatMonitor(AgentProviderService provider, int threadWakeupInterval) {
+ this.provider = provider;
+ this.threadWakeupInterval = threadWakeupInterval;
+ }
+
+ public void shutdown() {
+ shouldRun = false;
+ }
+
+ public void start() {
+ log.info("Starting heartbeat monitor with interval {}", threadWakeupInterval);
+ monitorThread = new Thread(this);
+ monitorThread.start();
+ }
+
+ void join(long millis) throws InterruptedException {
+ if (isAlive()) {
+ monitorThread.join(millis);
+ }
+ }
+
+ public boolean isAlive() {
+ return monitorThread != null && monitorThread.isAlive();
+ }
+
+ @Override
+ public void run() {
+ while (shouldRun) {
+ try {
+ log.debug("Putting monitor to sleep for " + threadWakeupInterval + " " +
+ "milliseconds");
+ Thread.sleep(threadWakeupInterval);
+ doWork(System.currentTimeMillis());
+ } catch (InterruptedException ex) {
+ log.warn("Scheduler thread is interrupted going to stop", ex);
+ shouldRun = false;
+ } catch (Exception ex) {
+ log.warn("Exception received", ex);
+ } catch (Throwable t) {
+ log.warn("ERROR", t);
+ }
+ }
+ }
+
+ /**
+ * Every interval the current state of the container are checked. If the state is INIT or HEALTHY and no HB are
+ * received in last check interval they are marked as UNHEALTHY. INIT is when the agent is started but it did not
+ * communicate at all. HEALTHY being the AM has received heartbeats. After an interval as UNHEALTHY the container is
+ * declared unavailable
+ * @param now current time in milliseconds ... tests can set this explicitly
+ */
+ @VisibleForTesting
+ public void doWork(long now) {
+ Map<String, ComponentInstanceState> componentStatuses = provider.getComponentStatuses();
+ if (componentStatuses != null) {
+ for (String containerLabel : componentStatuses.keySet()) {
+ ComponentInstanceState componentInstanceState = componentStatuses.get(containerLabel);
+ long timeSinceLastHeartbeat = now - componentInstanceState.getLastHeartbeat();
+
+ if (timeSinceLastHeartbeat > threadWakeupInterval) {
+ switch (componentInstanceState.getContainerState()) {
+ case INIT:
+ case HEALTHY:
+ componentInstanceState.setContainerState(ContainerState.UNHEALTHY);
+ log.warn(
+ "Component {} marked UNHEALTHY. Last heartbeat received at {} approx. {} ms. back.",
+ componentInstanceState,
+ componentInstanceState.getLastHeartbeat(),
+ timeSinceLastHeartbeat);
+ break;
+ case UNHEALTHY:
+ if (timeSinceLastHeartbeat > threadWakeupInterval * 2) {
+ componentInstanceState.setContainerState(
+ ContainerState.HEARTBEAT_LOST);
+ log.warn(
+ "Component {} marked HEARTBEAT_LOST. Last heartbeat received at {} approx. {} ms. back.",
+ componentInstanceState, componentInstanceState.getLastHeartbeat(),
+ timeSinceLastHeartbeat);
+ ContainerId containerId =
+ componentInstanceState.getContainerId();
+ provider.lostContainer(containerLabel, containerId);
+ }
+ break;
+ case HEARTBEAT_LOST:
+ // unexpected case
+ log.warn("Heartbeat from lost component: {}", componentInstanceState);
+ break;
+ }
+
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/State.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/State.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/State.java
new file mode 100644
index 0000000..5603f8d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/State.java
@@ -0,0 +1,199 @@
+/*
+ * 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.slider.providers.agent;
+
+/** The states a component instance can be. */
+public enum State {
+ INIT, // Not installed
+ INSTALLING, // Being installed
+ INSTALLED, // Installed (or stopped)
+ STARTING, // Starting
+ STARTED, // Started
+ INSTALL_FAILED, // Install failed, start failure in INSTALLED
+ UPGRADING, // Undergoing upgrade, perform necessary pre-upgrade steps
+ UPGRADED, // Pre-upgrade steps completed
+ STOPPING, // Stop has been issued
+ STOPPED, // Agent has stopped
+ TERMINATING; // Terminate signal to ask the agent to kill itself
+ // No need for state TERMINATED (as the agent is dead by then)
+
+ /**
+ * Indicates whether or not it is a valid state to produce a command.
+ *
+ * @return true if command can be issued for this state.
+ */
+ public boolean canIssueCommands() {
+ switch (this) {
+ case INSTALLING:
+ case STARTING:
+ case UPGRADING:
+ case STOPPING:
+ case TERMINATING:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Returns valid command in this state.
+ *
+ * @return command allowed in this state.
+ */
+ public Command getSupportedCommand() {
+ return getSupportedCommand(false);
+ }
+
+ public Command getSupportedCommand(boolean isInUpgradeMode) {
+ return getSupportedCommand(isInUpgradeMode, false);
+ }
+
+ public Command getSupportedCommand(boolean isInUpgradeMode,
+ boolean stopInitiated) {
+ switch (this) {
+ case INIT:
+ case INSTALL_FAILED:
+ return Command.INSTALL;
+ case INSTALLED:
+ return Command.START;
+ case STARTED:
+ return isInUpgradeMode ? Command.UPGRADE : (stopInitiated) ? Command.STOP
+ : Command.NOP;
+ case UPGRADED:
+ return Command.STOP;
+ case STOPPED:
+ return Command.TERMINATE;
+ default:
+ return Command.NOP;
+ }
+ }
+
+ /**
+ * Returns next state based on the command result.
+ *
+ * @return next state.
+ */
+ public State getNextState(CommandResult result) throws IllegalArgumentException {
+ switch (result) {
+ case IN_PROGRESS:
+ if (this == State.INSTALLING || this == State.STARTING
+ || this == State.UPGRADING || this == State.STOPPING
+ || this == State.TERMINATING) {
+ return this;
+ } else {
+ throw new IllegalArgumentException(result + " is not valid for " + this);
+ }
+ case COMPLETED:
+ if (this == State.INSTALLING) {
+ return State.INSTALLED;
+ } else if (this == State.STARTING) {
+ return State.STARTED;
+ } else if (this == State.UPGRADING) {
+ return State.UPGRADED;
+ } else if (this == State.STOPPING) {
+ return State.STOPPED;
+ } else {
+ throw new IllegalArgumentException(result + " is not valid for " + this);
+ }
+ case FAILED:
+ if (this == State.INSTALLING) {
+ return State.INSTALL_FAILED;
+ } else if (this == State.STARTING) {
+ return State.INSTALLED;
+ } else if (this == State.UPGRADING) {
+ // if pre-upgrade failed, force stop now, so mark it upgraded
+ // what other options can be exposed to app owner?
+ return State.UPGRADED;
+ } else if (this == State.STOPPING) {
+ // if stop fails, force mark it stopped (and let container terminate)
+ return State.STOPPED;
+ } else if (this == State.STOPPED) {
+ // if in stopped state, force mark it as terminating
+ return State.TERMINATING;
+ } else {
+ throw new IllegalArgumentException(result + " is not valid for " + this);
+ }
+ default:
+ throw new IllegalArgumentException("Bad command result " + result);
+ }
+ }
+
+ /**
+ * Returns next state based on the command.
+ *
+ * @return next state.
+ */
+ public State getNextState(Command command) throws IllegalArgumentException {
+ switch (command) {
+ case INSTALL:
+ if (this == State.INIT || this == State.INSTALL_FAILED) {
+ return State.INSTALLING;
+ } else {
+ throw new IllegalArgumentException(command + " is not valid for " + this);
+ }
+ case INSTALL_ADDON:
+ if (this == State.INIT || this == State.INSTALL_FAILED) {
+ return State.INSTALLING;
+ } else {
+ throw new IllegalArgumentException(command + " is not valid for " + this);
+ }
+ case START:
+ if (this == State.INSTALLED) {
+ return State.STARTING;
+ } else {
+ throw new IllegalArgumentException(command + " is not valid for " + this);
+ }
+ case UPGRADE:
+ if (this == State.STARTED) {
+ return State.UPGRADING;
+ } else {
+ throw new IllegalArgumentException(command + " is not valid for " + this);
+ }
+ case STOP:
+ if (this == State.STARTED || this == State.UPGRADED) {
+ return State.STOPPING;
+ } else {
+ throw new IllegalArgumentException(command + " is not valid for " + this);
+ }
+ case TERMINATE:
+ if (this == State.STOPPED) {
+ return State.TERMINATING;
+ } else {
+ throw new IllegalArgumentException(command + " is not valid for " + this);
+ }
+ case NOP:
+ return this;
+ default:
+ throw new IllegalArgumentException("Bad command " + command);
+ }
+ }
+
+ public boolean couldHaveIssued(Command command) {
+ if ((this == State.INSTALLING && command == Command.INSTALL)
+ || (this == State.STARTING && command == Command.START)
+ || (this == State.UPGRADING && command == Command.UPGRADE)
+ || (this == State.STOPPING
+ && (command == Command.STOP || command == Command.NOP))
+ || (this == State.TERMINATING && command == Command.TERMINATE)
+ ) {
+ return true;
+ }
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
new file mode 100644
index 0000000..b6ae4de
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
@@ -0,0 +1,80 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * Component defined in master package metainfo.json
+ */
+public abstract class AbstractComponent implements Validate {
+ public static final String TYPE_STANDARD = "STANDARD";
+ public static final String TYPE_DOCKER = "DOCKER";
+ public static final String TYPE_PYTHON = "PYTHON";
+ public static final String CATEGORY_MASTER = "MASTER";
+ public static final String CATEGORY_SLAVE = "SLAVE";
+ public static final String CATEGORY_CLIENT = "CLIENT";
+ public static final String MASTER_PACKAGE_NAME = "MASTER";
+
+ protected String name;
+ protected CommandScript commandScript;
+ protected List<ComponentCommand> commands = new ArrayList<>();
+
+ public AbstractComponent() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public CommandScript getCommandScript() {
+ return commandScript;
+ }
+
+ public void addCommandScript(CommandScript commandScript) {
+ this.commandScript = commandScript;
+ }
+
+ @JsonProperty("commands")
+ public List<ComponentCommand> getCommands() {
+ return commands;
+ }
+
+ public void setCommands(List<ComponentCommand> commands) {
+ this.commands = commands;
+ }
+
+ public void addCommand(ComponentCommand command) {
+ commands.add(command);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("{");
+ sb.append("\n\"name\": ").append(name);
+ sb.append(",\n\"commandScript\" :").append(commandScript);
+ sb.append('}');
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoParser.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoParser.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoParser.java
new file mode 100644
index 0000000..67d1f15
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoParser.java
@@ -0,0 +1,130 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+
+/**
+ * This abstract class provide common functionality to parse metainfo.json for
+ * either master package or add on packages.
+ */
+public abstract class AbstractMetainfoParser {
+ protected final GsonBuilder gsonBuilder = new GsonBuilder();
+ protected final Gson gson;
+ private static final Logger log = LoggerFactory
+ .getLogger(AbstractMetainfoParser.class);
+
+ public AbstractMetainfoParser() {
+ gson = gsonBuilder.create();
+ }
+
+ /**
+ * Convert to a JSON string
+ *
+ * @return a JSON string description
+ *
+ * @throws IOException Problems mapping/writing the object
+ */
+ public String toJsonString(Metainfo metaInfo) throws IOException {
+ return gson.toJson(metaInfo);
+ }
+
+ /**
+ * Convert from JSON
+ *
+ * @param json input
+ *
+ * @return the parsed JSON
+ *
+ * @throws IOException IO
+ */
+ public Metainfo fromJsonString(String json)
+ throws IOException {
+ return gson.fromJson(json, Metainfo.class);
+ }
+
+ /**
+ * Parse metainfo from an IOStream
+ *
+ * @param is
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ public Metainfo fromJsonStream(InputStream is) throws IOException {
+ log.debug("loading from xml stream");
+ StringWriter writer = new StringWriter();
+ IOUtils.copy(is, writer);
+ return fromJsonString(writer.toString());
+ }
+
+ /**
+ * Parse metainfo from an XML formatted IOStream
+ *
+ * @param metainfoStream
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ public Metainfo fromXmlStream(InputStream metainfoStream) throws IOException {
+ log.debug("loading from xml stream");
+ Digester digester = new Digester();
+ digester.setValidating(false);
+
+ composeSchema(digester);
+
+ try {
+ return (Metainfo) digester.parse(metainfoStream);
+ } catch (IOException e) {
+ log.debug("IOException in metainfoparser during fromXmlStream: "
+ + e.getMessage());
+ } catch (SAXException e) {
+ log.debug("SAXException in metainfoparser during fromXmlStream: "
+ + e.getMessage());
+ } finally {
+ if (metainfoStream != null) {
+ metainfoStream.close();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Compose the schema for the metainfo
+ *
+ * @param Digester - The Digester object we passed in to compose the schema
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ abstract protected void composeSchema(Digester digester);
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoSchema.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoSchema.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoSchema.java
new file mode 100644
index 0000000..cfa2895
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractMetainfoSchema.java
@@ -0,0 +1,69 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Application type defined in the metainfo
+ */
+public abstract class AbstractMetainfoSchema implements Validate {
+ protected String name;
+ protected String comment;
+ protected String version;
+ protected List<ConfigFile> configFiles = new ArrayList<>();
+
+ public AbstractMetainfoSchema() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public void addConfigFile(ConfigFile configFile) {
+ this.configFiles.add(configFile);
+ }
+
+ @JsonProperty("configFiles")
+ public List<ConfigFile> getConfigFiles() {
+ return configFiles;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AddonPackageMetainfoParser.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AddonPackageMetainfoParser.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AddonPackageMetainfoParser.java
new file mode 100644
index 0000000..c75837f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AddonPackageMetainfoParser.java
@@ -0,0 +1,53 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.commons.digester.Digester;
+
+/**
+ *
+ */
+public class AddonPackageMetainfoParser extends AbstractMetainfoParser {
+
+ protected void composeSchema(Digester digester) {
+ digester.addObjectCreate("metainfo", Metainfo.class);
+ digester.addBeanPropertySetter("metainfo/schemaVersion");
+
+ digester.addObjectCreate("*/applicationPackage", ApplicationPackage.class);
+ digester.addBeanPropertySetter("*/applicationPackage/name");
+ digester.addBeanPropertySetter("*/applicationPackage/comment");
+ digester.addBeanPropertySetter("*/applicationPackage/version");
+
+ digester.addObjectCreate("*/component", ComponentsInAddonPackage.class);
+ digester.addBeanPropertySetter("*/component/name");
+ digester.addSetNext("*/component", "addComponent");
+
+ digester.addObjectCreate("*/commandScript", CommandScript.class);
+ digester.addBeanPropertySetter("*/commandScript/script");
+ digester.addBeanPropertySetter("*/commandScript/scriptType");
+ digester.addBeanPropertySetter("*/commandScript/timeout");
+ digester.addSetNext("*/commandScript", "addCommandScript");
+
+ digester.addObjectCreate("*/configFile", ConfigFile.class);
+ digester.addBeanPropertySetter("*/configFile/type");
+ digester.addBeanPropertySetter("*/configFile/fileName");
+ digester.addBeanPropertySetter("*/configFile/dictionaryName");
+ digester.addSetNext("*/configFile", "addConfigFile");
+
+ digester.addSetRoot("*/applicationPackage", "setApplicationPackage");
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Application.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Application.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Application.java
new file mode 100644
index 0000000..5556c7f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Application.java
@@ -0,0 +1,193 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.slider.common.tools.SliderUtils;
+import org.apache.slider.core.exceptions.BadCommandArgumentsException;
+import org.apache.slider.core.exceptions.SliderException;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Application type defined in the metainfo
+ */
+public class Application extends AbstractMetainfoSchema {
+ String exportedConfigs;
+ List<ExportGroup> exportGroups = new ArrayList<>();
+ List<OSSpecific> osSpecifics = new ArrayList<>();
+ List<CommandOrder> commandOrders = new ArrayList<>();
+ List<Package> packages = new ArrayList<>();
+ private List<Component> components = new ArrayList<>();
+
+ public Application() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getExportedConfigs() {
+ return exportedConfigs;
+ }
+
+ public void setExportedConfigs(String exportedConfigs) {
+ this.exportedConfigs = exportedConfigs;
+ }
+
+ public void addConfigFile(ConfigFile configFile) {
+ this.configFiles.add(configFile);
+ }
+
+ @JsonProperty("configFiles")
+ public List<ConfigFile> getConfigFiles() {
+ return configFiles;
+ }
+
+ public void addComponent(Component component) {
+ components.add(component);
+ }
+
+ @JsonProperty("components")
+ public List<Component> getComponents() {
+ return components;
+ }
+
+ public void addExportGroup(ExportGroup exportGroup) {
+ exportGroups.add(exportGroup);
+ }
+
+ @JsonProperty("exportGroups")
+ public List<ExportGroup> getExportGroups() {
+ return exportGroups;
+ }
+
+ public void addOSSpecific(OSSpecific osSpecific) {
+ osSpecifics.add(osSpecific);
+ }
+
+ @JsonIgnore
+ public List<OSSpecific> getOSSpecifics() {
+ return osSpecifics;
+ }
+
+ public void addCommandOrder(CommandOrder commandOrder) {
+ commandOrders.add(commandOrder);
+ }
+
+ @JsonProperty("commandOrders")
+ public List<CommandOrder> getCommandOrders() {
+ return commandOrders;
+ }
+
+ public void addPackage(Package pkg) {
+ packages.add(pkg);
+ }
+
+ @JsonProperty("packages")
+ public List<Package> getPackages() {
+ return packages;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb =
+ new StringBuilder("{");
+ sb.append(",\n\"name\": ").append(name);
+ sb.append(",\n\"comment\": ").append(comment);
+ sb.append(",\n\"version\" :").append(version);
+ sb.append(",\n\"components\" : {");
+ for (Component component : components) {
+ sb.append("\n").append(component.toString());
+ }
+ sb.append("\n},");
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public void validate(String version) throws SliderException {
+ if(SliderUtils.isUnset(version)) {
+ throw new BadCommandArgumentsException("schema version cannot be null");
+ }
+
+ Metainfo.checkNonNull(getName(), "name", "application");
+
+ Metainfo.checkNonNull(getVersion(), "version", "application");
+
+ if(getComponents().size() == 0) {
+ throw new SliderException("application must contain at least one component");
+ }
+
+ if(version.equals(Metainfo.VERSION_TWO_ZERO)) {
+ if(getPackages().size() > 0) {
+ throw new SliderException("packages is not supported in version " + version);
+ }
+ }
+
+ if(version.equals(Metainfo.VERSION_TWO_ONE)) {
+ if(getOSSpecifics().size() > 0) {
+ throw new SliderException("osSpecifics is not supported in version " + version);
+ }
+ }
+
+ for(CommandOrder co : getCommandOrders()) {
+ co.validate(version);
+ }
+
+ for(Component comp : getComponents()) {
+ comp.validate(version);
+ }
+
+ for(ConfigFile cf : getConfigFiles()) {
+ cf.validate(version);
+ }
+
+ for(ExportGroup eg : getExportGroups()) {
+ eg.validate(version);
+ }
+
+ for(Package pkg : getPackages()) {
+ pkg.validate(version);
+ }
+
+ for(OSSpecific os : getOSSpecifics()) {
+ os.validate(version);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/ApplicationPackage.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/ApplicationPackage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/ApplicationPackage.java
new file mode 100644
index 0000000..a94a213
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/ApplicationPackage.java
@@ -0,0 +1,69 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.slider.core.exceptions.SliderException;
+
+public class ApplicationPackage extends AbstractMetainfoSchema{
+ private List<ComponentsInAddonPackage> components = new ArrayList<ComponentsInAddonPackage>();
+
+ public void addComponent(ComponentsInAddonPackage component) {
+ components.add(component);
+ }
+
+ // we must override getcomponent() as well. otherwise it is pointing to the
+ // overriden components of type List<Component>
+ public List<ComponentsInAddonPackage> getComponents(){
+ return this.components;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("{");
+ sb.append("\n\"name\": ").append(name);
+ sb.append(",\n\"comment\": ").append(comment);
+ sb.append(",\n\"version\" :").append(version);
+ sb.append(",\n\"components\" : {");
+ for (ComponentsInAddonPackage component : components) {
+ sb.append("\n").append(component);
+ }
+ sb.append("\n},");
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public void validate(String version) throws SliderException {
+ if (name == null || name.isEmpty()) {
+ throw new SliderException(
+ "Missing name in metainfo.json for add on packages");
+ }
+ if (components.isEmpty()) {
+ throw new SliderException(
+ "Missing components in metainfo.json for add on packages");
+ }
+ for (ComponentsInAddonPackage component : components) {
+ if (component.name == null || component.name.isEmpty()) {
+ throw new SliderException(
+ "Missing name of components in metainfo.json for add on packages");
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandOrder.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandOrder.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandOrder.java
new file mode 100644
index 0000000..40d8cc6
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandOrder.java
@@ -0,0 +1,61 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.slider.core.exceptions.SliderException;
+
+/**
+ *
+ */
+public class CommandOrder implements Validate {
+ String command;
+ String requires;
+
+ public CommandOrder() {
+ }
+
+ public String getCommand() {
+ return command;
+ }
+
+ public void setCommand(String command) {
+ this.command = command;
+ }
+
+ public String getRequires() {
+ return requires;
+ }
+
+ public void setRequires(String requires) {
+ this.requires = requires;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb =
+ new StringBuilder("{");
+ sb.append(",\n\"command\": ").append(command);
+ sb.append(",\n\"requires\": ").append(requires);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public void validate(String version) throws SliderException {
+ Metainfo.checkNonNull(getCommand(), "command", "package");
+ Metainfo.checkNonNull(getRequires(), "requires", "package");
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandScript.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandScript.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandScript.java
new file mode 100644
index 0000000..9915ba1
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/CommandScript.java
@@ -0,0 +1,72 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.slider.core.exceptions.SliderException;
+
+/**
+ * CommandScript that implements all component commands
+ */
+public class CommandScript implements Validate {
+ String script;
+ String scriptType;
+ long timeout;
+
+ public CommandScript() {
+
+ }
+
+ public String getScript() {
+ return script;
+ }
+
+ public void setScript(String script) {
+ this.script = script;
+ }
+
+ public String getScriptType() {
+ return scriptType;
+ }
+
+ public void setScriptType(String scriptType) {
+ this.scriptType = scriptType;
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb =
+ new StringBuilder("{");
+ sb.append(",\n\"script\": ").append(script);
+ sb.append(",\n\"scriptType\": ").append(scriptType);
+ sb.append(",\n\"timeout\" :").append(timeout);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public void validate(String version) throws SliderException {
+ Metainfo.checkNonNull(getScript(), "script", "commandScript");
+ Metainfo.checkNonNull(getScriptType(), "scriptType", "commandScript");
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org