/*
* Copyright 2013 the original author or authors.
*
* Licensed 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.springframework.yarn.boot.support;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.util.StringUtils;
import org.springframework.yarn.container.LongRunningYarnContainer;
import org.springframework.yarn.container.YarnContainer;
import org.springframework.yarn.launch.ExitCodeMapper;
import org.springframework.yarn.launch.JvmSystemExiter;
import org.springframework.yarn.launch.SimpleJvmExitCodeMapper;
import org.springframework.yarn.launch.SystemExiter;
import org.springframework.yarn.listener.ContainerStateListener;
import org.springframework.yarn.listener.ContainerStateListener.ContainerState;
/**
* {@link CommandLineRunner} to {@link YarnContainer run} Spring Yarn container.
*
* @author Janne Valkealahti
*
*/
public class ContainerLauncherRunner implements CommandLineRunner {
private static final Log log = LogFactory.getLog(ContainerLauncherRunner.class);
private static SystemExiter systemExiter = new JvmSystemExiter();
private ExitCodeMapper exitCodeMapper = new SimpleJvmExitCodeMapper();
/** Latch used for long running container wait */
private CountDownLatch latch;
private boolean waitLatch = true;
@Autowired(required = false)
private YarnContainer yarnContainer;
private final StateWrapper stateWrapper = new StateWrapper();
@Override
public void run(String... args) throws Exception {
if (yarnContainer != null) {
launchContainer(yarnContainer, args);
}
}
public void setWaitLatch(boolean waitLatch) {
this.waitLatch = waitLatch;
}
protected void launchContainer(YarnContainer container, String[] parameters) {
Properties properties = StringUtils.splitArrayElementsIntoProperties(parameters, "=");
container.setParameters(properties != null ? properties : new Properties());
container.setEnvironment(System.getenv());
log.info("Running YarnContainer with parameters [" + StringUtils.arrayToCommaDelimitedString(parameters) + "]");
// use latch if container wants to be long running
if (container instanceof LongRunningYarnContainer && ((LongRunningYarnContainer)container).isWaitCompleteState()) {
log.info("Container requested that we wait state, setting up latch");
latch = new CountDownLatch(1);
((LongRunningYarnContainer)container).addContainerStateListener(new ContainerStateListener() {
@Override
public void state(ContainerState state, Object exit) {
if (log.isDebugEnabled()) {
log.debug("Got state ContainerState=" + state + " and exit=" + exit);
}
stateWrapper.state = state;
stateWrapper.exit = exit;
latch.countDown();
}
});
}
// tell container to do its stuff
container.run();
if (waitLatch) {
if (latch != null) {
try {
// TODO: should we use timeout?
latch.await();
} catch (InterruptedException e) {
log.info("YarnContainer latch wait interrupted");
}
}
log.info("YarnContainer complete");
int exitCode = 0;
if (stateWrapper.state != null) {
if (stateWrapper.exit != null) {
if (stateWrapper.exit instanceof String) {
exitCode = exitCodeMapper.intValue((String)stateWrapper.exit);
} else if (stateWrapper.exit instanceof Boolean) {
exitCode = exitCodeMapper.intValue((Boolean)stateWrapper.exit);
} else if (stateWrapper.exit instanceof Integer) {
exitCode = (Integer) stateWrapper.exit;
}
}
}
log.info("Exiting with exitCode=" + exitCode);
systemExiter.exit(exitCode);
}
}
private static class StateWrapper {
ContainerState state;
Object exit;
}
}