org.apache.zeppelin.submarine.hadoop.YarnClient Maven / Gradle / Ivy
/*
* 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.apache.zeppelin.submarine.hadoop;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.submarine.commons.SubmarineConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.LoginContext;
public class YarnClient {
private Logger LOGGER = LoggerFactory.getLogger(YarnClient.class);
private Configuration hadoopConf;
private String yarnWebHttpAddr;
private String principal = "";
private String keytab = "";
public static final String YARN_REST_APPATTEMPTS = "appAttempts";
public static final String YARN_REST_CONTAINER = "container";
public static final String YARN_REST_APPATTEMPT = "appAttempt";
public static final String YARN_REST_APPATTEMPTID = "appAttemptId";
public static final String YARN_REST_EXPOSEDPORTS = "EXPOSEDPORTS";
public static final String CONTAINER_IP = "CONTAINER_IP";
public static final String CONTAINER_PORT = "CONTAINER_PORT";
public static final String HOST_IP = "HOST_IP";
public static final String HOST_PORT = "HOST_PORT";
String SERVICE_PATH = "/services/{service_name}";
private boolean hadoopSecurityEnabled = true; // simple or kerberos
public YarnClient(Properties properties) {
this.hadoopConf = new Configuration();
String hadoopAuthType = properties.getProperty(
SubmarineConstants.ZEPPELIN_SUBMARINE_AUTH_TYPE, "kerberos");
if (StringUtils.equals(hadoopAuthType, "simple")) {
hadoopSecurityEnabled = false;
}
yarnWebHttpAddr = properties.getProperty(SubmarineConstants.YARN_WEB_HTTP_ADDRESS, "");
boolean isSecurityEnabled = UserGroupInformation.isSecurityEnabled();
if (isSecurityEnabled || hadoopSecurityEnabled) {
String krb5conf = properties.getProperty(SubmarineConstants.SUBMARINE_HADOOP_KRB5_CONF, "");
if (StringUtils.isEmpty(krb5conf)) {
krb5conf = "/etc/krb5.conf";
System.setProperty("java.security.krb5.conf", krb5conf);
}
String keytab = properties.getProperty(
SubmarineConstants.SUBMARINE_HADOOP_KEYTAB, "");
String principal = properties.getProperty(
SubmarineConstants.SUBMARINE_HADOOP_PRINCIPAL, "");
ZeppelinConfiguration zConf = ZeppelinConfiguration.create();
if (StringUtils.isEmpty(keytab)) {
keytab = zConf.getString(
ZeppelinConfiguration.ConfVars.ZEPPELIN_SERVER_KERBEROS_KEYTAB);
}
if (StringUtils.isEmpty(principal)) {
principal = zConf.getString(
ZeppelinConfiguration.ConfVars.ZEPPELIN_SERVER_KERBEROS_PRINCIPAL);
}
if (StringUtils.isBlank(keytab) || StringUtils.isBlank(principal)) {
throw new RuntimeException("keytab and principal can not be empty, keytab: "
+ keytab + ", principal: " + principal);
}
this.principal = principal;
this.keytab = keytab;
if (LOGGER.isDebugEnabled()) {
System.setProperty("sun.security.spnego.debug", "true");
System.setProperty("sun.security.krb5.debug", "true");
}
}
}
// http://yarn-web-http-address/app/v1/services/{service_name}
public void deleteService(String serviceName) {
String appUrl = this.yarnWebHttpAddr + "/app/v1/services/" + serviceName
+ "?_=" + System.currentTimeMillis();
InputStream inputStream = null;
try {
HttpResponse response = callRestUrl(appUrl, principal, HTTP.DELETE);
inputStream = response.getEntity().getContent();
String result = new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining(System.lineSeparator()));
if (response.getStatusLine().getStatusCode() != 200 /*success*/) {
LOGGER.warn("Status code " + response.getStatusLine().getStatusCode());
LOGGER.warn("message is :" + Arrays.deepToString(response.getAllHeaders()));
LOGGER.warn("result:\n" + result);
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
if (null != inputStream) {
inputStream.close();
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
}
// http://yarn-web-http-address/app/v1/services/{appIdOrName}
// test/resources/app-v1-services-app_name.json
public Map getAppServices(String appIdOrName) {
Map mapStatus = new HashMap<>();
String appUrl = this.yarnWebHttpAddr + "/app/v1/services/" + appIdOrName
+ "?_=" + System.currentTimeMillis();
InputStream inputStream = null;
try {
HttpResponse response = callRestUrl(appUrl, principal, HTTP.GET);
inputStream = response.getEntity().getContent();
String result = new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining(System.lineSeparator()));
if (response.getStatusLine().getStatusCode() != 200 /*success*/
&& response.getStatusLine().getStatusCode() != 404 /*Not found*/) {
LOGGER.warn("Status code " + response.getStatusLine().getStatusCode());
LOGGER.warn("message is :" + Arrays.deepToString(response.getAllHeaders()));
LOGGER.warn("result:\n" + result);
}
// parse app status json
mapStatus = parseAppServices(result);
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
if (null != inputStream) {
inputStream.close();
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
return mapStatus;
}
// http://yarn-web-http-address/ws/v1/cluster/apps/{appId}
// test/resources/ws-v1-cluster-apps-application_id-failed.json
// test/resources/ws-v1-cluster-apps-application_id-finished.json
// test/resources/ws-v1-cluster-apps-application_id-running.json
public Map getClusterApps(String appId) {
Map appAttempts = new HashMap<>();
String appUrl = this.yarnWebHttpAddr + "/ws/v1/cluster/apps/" + appId
+ "?_=" + System.currentTimeMillis();
InputStream inputStream = null;
try {
HttpResponse response = callRestUrl(appUrl, principal, HTTP.GET);
inputStream = response.getEntity().getContent();
String result = new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining(System.lineSeparator()));
if (response.getStatusLine().getStatusCode() != 200 /*success*/) {
LOGGER.warn("Status code " + response.getStatusLine().getStatusCode());
LOGGER.warn("message is :" + Arrays.deepToString(response.getAllHeaders()));
LOGGER.warn("result:\n" + result);
}
// parse app status json
appAttempts = parseClusterApps(result);
return appAttempts;
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
if (null != inputStream) {
inputStream.close();
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
return appAttempts;
}
public Map parseClusterApps(String jsonContent) {
Map appAttempts = new HashMap<>();
try {
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonContent);
JsonObject jsonAppAttempts = jsonObject.get("app").getAsJsonObject();
if (null == jsonAppAttempts) {
return appAttempts;
}
for (Map.Entry entry : jsonAppAttempts.entrySet()) {
String key = entry.getKey();
if (null != entry.getValue() && entry.getValue() instanceof JsonPrimitive) {
Object value = entry.getValue().getAsString();
appAttempts.put(key, value);
}
}
} catch (JsonIOException e) {
LOGGER.error(e.getMessage(), e);
} catch (JsonSyntaxException e) {
LOGGER.error(e.getMessage(), e);
}
return appAttempts;
}
// http://yarn-web-http-address/ws/v1/cluster/apps/{appId}/appattempts
// test/resources/ws-v1-cluster-apps-application_id-appattempts.json
public List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy