/*
* Copyright 2014 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.app;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.yarn.boot.SpringApplicationCallback;
import org.springframework.yarn.boot.SpringApplicationTemplate;
import org.springframework.yarn.boot.properties.SpringYarnProperties;
import org.springframework.yarn.boot.support.SpringYarnBootUtils;
import org.springframework.yarn.client.YarnClient;
import org.springframework.yarn.support.console.ApplicationsReport;
import org.springframework.yarn.support.console.ApplicationsReport.InstalledField;
import org.springframework.yarn.support.console.ApplicationsReport.SubmittedField;
import org.springframework.yarn.support.console.ApplicationsReport.SubmittedReportBuilder;
/**
* Generic Spring Yarn Boot application handling reporting.
*
* @author Janne Valkealahti
*
*/
@Configuration
@EnableAutoConfiguration(exclude = { EmbeddedServletContainerAutoConfiguration.class, WebMvcAutoConfiguration.class,
JmxAutoConfiguration.class, BatchAutoConfiguration.class, JmxAutoConfiguration.class,
EndpointMBeanExportAutoConfiguration.class, EndpointAutoConfiguration.class })
public class YarnInfoApplication extends AbstractClientApplication<YarnInfoApplication> {
/**
* Run a {@link SpringApplication} build by a
* {@link SpringApplicationBuilder} using an empty args.
*
* @see #run(String...)
*
* @return report
*/
public String run() {
return run(new String[0]);
}
/**
* Run a {@link SpringApplication} build by a {@link SpringApplicationBuilder}.
*
* @param args the Spring Application args
* @return report
*/
public String run(String... args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder();
builder.web(false);
builder.sources(YarnInfoApplication.class, OperationProperties.class);
SpringYarnBootUtils.addSources(builder, sources.toArray(new Object[0]));
SpringYarnBootUtils.addProfiles(builder, profiles.toArray(new String[0]));
if (StringUtils.hasText(applicationBaseDir)) {
appProperties.setProperty("spring.yarn.applicationDir", applicationBaseDir + applicationVersion + "/");
}
SpringYarnBootUtils.addApplicationListener(builder, appProperties);
SpringApplicationTemplate template = new SpringApplicationTemplate(builder);
return template.execute(new SpringApplicationCallback<String>() {
@Override
public String runWithSpringApplication(ApplicationContext context) throws Exception {
OperationProperties operationProperties = context.getBean(OperationProperties.class);
if (Operation.PUSHED == operationProperties.getOperation()) {
return getInstalledReport(context);
} else if (Operation.SUBMITTED == operationProperties.getOperation()) {
YarnClient client = context.getBean(YarnClient.class);
return getSubmittedReport(client, operationProperties.isVerbose(), operationProperties.getType(),
operationProperties.getHeaders());
}
return null;
}
}, args);
}
/**
* Build the report for installed applications.
*
* @param context the application context
* @return the installed report
* @throws Exception the exception
*/
protected String getInstalledReport(ApplicationContext context) throws Exception {
YarnConfiguration yarnConfiguration = context.getBean(YarnConfiguration.class);
SpringYarnProperties springYarnProperties = context.getBean(SpringYarnProperties.class);
String applicationBaseDir = springYarnProperties.getApplicationBaseDir();
Path path = new Path(applicationBaseDir);
FileSystem fs = path.getFileSystem(yarnConfiguration);
FileStatus[] listStatus = new FileStatus[0];
if (fs.exists(path)) {
listStatus = fs.listStatus(path);
}
return ApplicationsReport.installedReportBuilder()
.add(InstalledField.NAME)
.add(InstalledField.PATH)
.from(listStatus)
.build().toString();
}
/**
* Build the report for submitted applications.
*
* @param client the client
* @param verbose the verbose
* @param type the type
* @param headers the headers
* @return the submitted report
*/
protected String getSubmittedReport(YarnClient client, boolean verbose, String type, Map<String,String> headers) {
SubmittedReportBuilder builder = ApplicationsReport.submittedReportBuilder();
builder.add(SubmittedField.ID, SubmittedField.USER, SubmittedField.NAME, SubmittedField.QUEUE,
SubmittedField.TYPE, SubmittedField.STARTTIME, SubmittedField.FINISHTIME, SubmittedField.STATE,
SubmittedField.FINALSTATUS, SubmittedField.ORIGTRACKURL)
.sort(SubmittedField.ID);
if (verbose) {
builder.from(client.listApplications(type));
} else {
builder.from(client.listRunningApplications(type));
}
if (headers != null) {
for (Entry<String, String> entry : headers.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
}
return builder.build().toString();
}
@Override
protected YarnInfoApplication getThis() {
return this;
}
@ConfigurationProperties(value = "spring.yarn.internal.YarnInfoApplication")
public static class OperationProperties {
private Operation operation;
private boolean verbose;
private String type;
private Map<String, String> headers;
public void setOperation(Operation operation) {
this.operation = operation;
}
public Operation getOperation() {
return operation;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public boolean isVerbose() {
return verbose;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public Map<String, String> getHeaders() {
return headers;
}
}
public static enum Operation {
PUSHED,
SUBMITTED
}
}