package com.linkedin.thirdeye.autoload.pinot.metrics;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.linkedin.pinot.common.data.Schema;
import com.linkedin.thirdeye.client.pinot.PinotThirdEyeClientConfig;
import com.linkedin.thirdeye.common.ThirdEyeConfiguration;
public class AutoLoadPinotMetricsUtils {
private static final String PINOT_TABLES_ENDPOINT = "tables/";
private static final String PINOT_SCHEMA_ENDPOINT = "schemas/%s";
private static final String PINOT_SCHEMA_ENDPOINT_TEMPLATE = "tables/%s/schema";
private static final String UTF_8 = "UTF-8";
private CloseableHttpClient pinotControllerClient;
private HttpHost pinotControllerHost;
private static final Logger LOG = LoggerFactory.getLogger(AutoLoadPinotMetricsUtils.class);
public AutoLoadPinotMetricsUtils(ThirdEyeConfiguration config) {
try {
PinotThirdEyeClientConfig pinotThirdeyeClientConfig = PinotThirdEyeClientConfig.createThirdEyeClientConfig(config);
this.pinotControllerClient = HttpClients.createDefault();
this.pinotControllerHost = new HttpHost(pinotThirdeyeClientConfig.getControllerHost(),
pinotThirdeyeClientConfig.getControllerPort());
} catch (Exception e) {
LOG.error("Exception in creating pinot controller http host", e);
}
}
public JsonNode getAllTablesFromPinot() throws IOException {
HttpGet tablesReq = new HttpGet(PINOT_TABLES_ENDPOINT);
LOG.info("Retrieving datasets: {}", tablesReq);
CloseableHttpResponse tablesRes = pinotControllerClient.execute(pinotControllerHost, tablesReq);
JsonNode tables = null;
try {
if (tablesRes.getStatusLine().getStatusCode() != 200) {
throw new IllegalStateException(tablesRes.getStatusLine().toString());
}
InputStream tablesContent = tablesRes.getEntity().getContent();
tables = new ObjectMapper().readTree(tablesContent).get("tables");
} catch (Exception e) {
LOG.error("Exception in loading collections", e);
} finally {
if (tablesRes.getEntity() != null) {
EntityUtils.consume(tablesRes.getEntity());
}
tablesRes.close();
}
return tables;
}
/**
* Fetches schema from pinot, from the tables endpoint or schema endpoint
* @param dataset
* @return
* @throws IOException
*/
public Schema getSchemaFromPinot(String dataset) throws IOException {
Schema schema = null;
schema = getSchemaFromTableConfig(dataset);
if (schema == null) {
schema = getSchemaFromSchemaEndpoint(dataset);
}
if (schema == null) {
schema = getSchemaFromSchemaEndpoint(dataset + "_OFFLINE");
}
return schema;
}
private Schema getSchemaFromTableConfig(String dataset) throws IOException {
Schema schema = null;
HttpGet schemaReq = new HttpGet(String.format(PINOT_SCHEMA_ENDPOINT_TEMPLATE, URLEncoder.encode(dataset, UTF_8)));
LOG.info("Retrieving schema: {}", schemaReq);
CloseableHttpResponse schemaRes = pinotControllerClient.execute(pinotControllerHost, schemaReq);
try {
if (schemaRes.getStatusLine().getStatusCode() != 200) {
LOG.error("Schema {} not found, {}", dataset, schemaRes.getStatusLine().toString());
} else {
InputStream schemaContent = schemaRes.getEntity().getContent();
schema = new org.codehaus.jackson.map.ObjectMapper().readValue(schemaContent, Schema.class);
}
} catch (Exception e) {
LOG.error("Exception in retrieving schema collections, skipping {}", dataset);
} finally {
if (schemaRes.getEntity() != null) {
EntityUtils.consume(schemaRes.getEntity());
}
schemaRes.close();
}
return schema;
}
private Schema getSchemaFromSchemaEndpoint(String dataset) throws IOException {
Schema schema = null;
HttpGet schemaReq = new HttpGet(String.format(PINOT_SCHEMA_ENDPOINT, URLEncoder.encode(dataset, UTF_8)));
LOG.info("Retrieving schema: {}", schemaReq);
CloseableHttpResponse schemaRes = pinotControllerClient.execute(pinotControllerHost, schemaReq);
try {
if (schemaRes.getStatusLine().getStatusCode() != 200) {
LOG.error("Schema {} not found, {}", dataset, schemaRes.getStatusLine().toString());
} else {
InputStream schemaContent = schemaRes.getEntity().getContent();
schema = new org.codehaus.jackson.map.ObjectMapper().readValue(schemaContent, Schema.class);
}
} catch (Exception e) {
LOG.error("Exception in retrieving schema collections, skipping {}", dataset);
} finally {
if (schemaRes.getEntity() != null) {
EntityUtils.consume(schemaRes.getEntity());
}
schemaRes.close();
}
return schema;
}
public boolean verifySchemaCorrectness(Schema schema) {
boolean isSchemaCorrect = true;
if (StringUtils.isBlank(schema.getSchemaName()) || schema.getTimeFieldSpec() == null
|| schema.getTimeFieldSpec().getOutgoingGranularitySpec() == null) {
isSchemaCorrect = false;
}
return isSchemaCorrect;
}
}