http://git-wip-us.apache.org/repos/asf/hadoop/blob/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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/31c4a419/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-unsubscr...@hadoop.apache.org For additional commands, e-mail: common-commits-h...@hadoop.apache.org