use of com.linkedin.pinot.common.restlet.swagger.Paths in project pinot by linkedin.
the class PinotTableRestletResource method getTable.
@HttpVerb("get")
@Summary("Views a table's configuration")
@Tags({ "table" })
@Paths({ "/tables/{tableName}", "/tables/{tableName}/" })
private Representation getTable(@Parameter(name = "tableName", in = "path", description = "The name of the table for which to toggle its state", required = true) String tableName, @Parameter(name = "type", in = "query", description = "Type of table, Offline or Realtime", required = true) String tableType) throws JSONException, JsonParseException, JsonMappingException, JsonProcessingException, IOException {
JSONObject ret = new JSONObject();
if ((tableType == null || TableType.OFFLINE.name().equalsIgnoreCase(tableType)) && _pinotHelixResourceManager.hasOfflineTable(tableName)) {
AbstractTableConfig config = _pinotHelixResourceManager.getTableConfig(tableName, TableType.OFFLINE);
ret.put(TableType.OFFLINE.name(), config.toJSON());
}
if ((tableType == null || TableType.REALTIME.name().equalsIgnoreCase(tableType)) && _pinotHelixResourceManager.hasRealtimeTable(tableName)) {
AbstractTableConfig config = _pinotHelixResourceManager.getTableConfig(tableName, TableType.REALTIME);
ret.put(TableType.REALTIME.name(), config.toJSON());
}
return new StringRepresentation(ret.toString(2));
}
use of com.linkedin.pinot.common.restlet.swagger.Paths in project pinot by linkedin.
the class PinotTableRestletResource method addTable.
@HttpVerb("post")
@Summary("Adds a table")
@Tags({ "table" })
@Paths({ "/tables", "/tables/" })
private void addTable(AbstractTableConfig config) throws IOException {
// For self-serviced cluster, ensure that the tables are created with atleast
// min replication factor irrespective of table configuratio value.
SegmentsValidationAndRetentionConfig segmentsConfig = config.getValidationConfig();
int requestReplication = segmentsConfig.getReplicationNumber();
int configMinReplication = _controllerConf.getDefaultTableMinReplicas();
if (requestReplication < configMinReplication) {
LOGGER.info("Creating table with minimum replication factor of: {} instead of requested replication: {}", configMinReplication, requestReplication);
segmentsConfig.setReplication(String.valueOf(configMinReplication));
}
if (segmentsConfig.getReplicasPerPartition() != null) {
int replicasPerPartition = Integer.valueOf(segmentsConfig.getReplicasPerPartition());
if (replicasPerPartition < configMinReplication) {
LOGGER.info("Creating table with minimum replicasPerPartition of: {} instead of requested replicasPerPartition: {}", configMinReplication, requestReplication);
segmentsConfig.setReplicasPerPartition(String.valueOf(configMinReplication));
}
}
_pinotHelixResourceManager.addTable(config);
}
use of com.linkedin.pinot.common.restlet.swagger.Paths in project pinot by linkedin.
the class PinotTenantRestletResource method toggleTenantState.
@HttpVerb("get")
@Summary("Enable, disable or drop a tenant")
@Tags({ "tenant" })
@Paths({ "/tenants/{tenantName}", "/tenants/{tenantName}/" })
private StringRepresentation toggleTenantState(@Parameter(name = "tenantName", in = "path", description = "The tenant name") String tenantName, @Parameter(name = "state", in = "query", description = "state to set for the tenant {enable|disable|drop}") String state, @Parameter(name = "type", in = "query", description = "The type of tenant, either SERVER or BROKER or NULL") String type) throws JSONException {
Set<String> serverInstances = new HashSet<String>();
Set<String> brokerInstances = new HashSet<String>();
JSONObject instanceResult = new JSONObject();
if ((type == null) || type.equalsIgnoreCase("server")) {
serverInstances = _pinotHelixResourceManager.getAllInstancesForServerTenant(tenantName);
}
if ((type == null) || type.equalsIgnoreCase("broker")) {
brokerInstances = _pinotHelixResourceManager.getAllInstancesForBrokerTenant(tenantName);
}
Set<String> allInstances = new HashSet<String>(serverInstances);
allInstances.addAll(brokerInstances);
if (StateType.DROP.name().equalsIgnoreCase(state)) {
if (!allInstances.isEmpty()) {
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
return new StringRepresentation("Error: Tenant " + tenantName + " has live instances, cannot be dropped.");
}
_pinotHelixResourceManager.deleteBrokerTenantFor(tenantName);
_pinotHelixResourceManager.deleteOfflineServerTenantFor(tenantName);
_pinotHelixResourceManager.deleteRealtimeServerTenantFor(tenantName);
return new StringRepresentation("Dropped tenant " + tenantName + " successfully.");
}
boolean enable = StateType.ENABLE.name().equalsIgnoreCase(state) ? true : false;
for (String instance : allInstances) {
if (enable) {
instanceResult.put(instance, _pinotHelixResourceManager.enableInstance(instance));
} else {
instanceResult.put(instance, _pinotHelixResourceManager.disableInstance(instance));
}
}
return new StringRepresentation(instanceResult.toString(), MediaType.APPLICATION_JSON);
}
use of com.linkedin.pinot.common.restlet.swagger.Paths in project pinot by linkedin.
the class PinotSegmentUploadRestletResource method uploadSegment.
@HttpVerb("post")
@Summary("Uploads a segment")
@Tags({ "segment" })
@Paths({ "/segments", "/segments/" })
@Responses({ @Response(statusCode = "200", description = "The segment was successfully uploaded"), @Response(statusCode = "403", description = "Forbidden operation typically because it exceeds configured quota"), @Response(statusCode = "500", description = "There was an error when uploading the segment") })
private Representation uploadSegment(File indexDir, File dataFile, String downloadUrl) throws ConfigurationException, IOException, JSONException {
final SegmentMetadata metadata = new SegmentMetadataImpl(indexDir);
final File tableDir = new File(baseDataDir, metadata.getTableName());
String tableName = metadata.getTableName();
File segmentFile = new File(tableDir, dataFile.getName());
OfflineTableConfig offlineTableConfig = (OfflineTableConfig) ZKMetadataProvider.getOfflineTableConfig(_pinotHelixResourceManager.getPropertyStore(), tableName);
if (offlineTableConfig == null) {
LOGGER.info("Missing configuration for table: {} in helix", metadata.getTableName());
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
StringRepresentation repr = new StringRepresentation("{\"error\" : \"Missing table: " + tableName + "\"}");
repr.setMediaType(MediaType.APPLICATION_JSON);
return repr;
}
StorageQuotaChecker.QuotaCheckerResponse quotaResponse = checkStorageQuota(indexDir, metadata, offlineTableConfig);
if (!quotaResponse.isSegmentWithinQuota) {
// this is not an "error" hence we don't increment segment upload errors
LOGGER.info("Rejecting segment upload for table: {}, segment: {}, reason: {}", metadata.getTableName(), metadata.getName(), quotaResponse.reason);
setStatus(Status.CLIENT_ERROR_FORBIDDEN);
StringRepresentation repr = new StringRepresentation("{\"error\" : \"" + quotaResponse.reason + "\"}");
repr.setMediaType(MediaType.APPLICATION_JSON);
return repr;
}
PinotResourceManagerResponse response;
if (!isSegmentTimeValid(metadata)) {
response = new PinotResourceManagerResponse("Invalid segment start/end time", false);
} else {
if (downloadUrl == null) {
// serve the data downloading from Pinot Servers.
if (segmentFile.exists()) {
FileUtils.deleteQuietly(segmentFile);
}
FileUtils.moveFile(dataFile, segmentFile);
downloadUrl = ControllerConf.constructDownloadUrl(tableName, dataFile.getName(), vip);
}
// TODO: this will read table configuration again from ZK. We should optimize that
response = _pinotHelixResourceManager.addSegment(metadata, downloadUrl);
}
if (response.isSuccessful()) {
setStatus(Status.SUCCESS_OK);
} else {
ControllerRestApplication.getControllerMetrics().addMeteredGlobalValue(ControllerMeter.CONTROLLER_SEGMENT_UPLOAD_ERROR, 1L);
setStatus(Status.SERVER_ERROR_INTERNAL);
}
return new StringRepresentation(response.toJSON().toString());
}
use of com.linkedin.pinot.common.restlet.swagger.Paths in project pinot by linkedin.
the class PinotSegmentUploadRestletResource method getAllSegments.
@HttpVerb("get")
@Summary("Lists all segments")
@Tags({ "segment" })
@Paths({ "/segments", "/segments/" })
@Responses({ @Response(statusCode = "200", description = "A list of all segments for the all tables") })
private Representation getAllSegments() {
Representation presentation;
final JSONArray ret = new JSONArray();
for (final File file : baseDataDir.listFiles()) {
final String fileName = file.getName();
if (fileName.equalsIgnoreCase("fileUploadTemp") || fileName.equalsIgnoreCase("schemasTemp")) {
continue;
}
final String url = _controllerConf.generateVipUrl() + "/segments/" + fileName;
ret.put(url);
}
presentation = new StringRepresentation(ret.toString());
return presentation;
}
Aggregations