src/cost/cost.controller.ts
cost
Controller responsible for handling requests related to turo cost operations.
Methods |
|
| canRegisterCostEndpoints | |||||||||
canRegisterCostEndpoints(request, projectId: string)
|
|||||||||
Decorators :
@Get('/:projectId/endpoints/hasCreatePermission')
|
|||||||||
|
Defined in src/cost/cost.controller.ts:82
|
|||||||||
|
Check if user token in request has permission to register an cost
Parameters :
Returns :
any
boolean |
| Async deleteCostEndpoint | |||||||||
deleteCostEndpoint(id: number, request)
|
|||||||||
Decorators :
@Delete('/endpoints/:id')
|
|||||||||
|
Defined in src/cost/cost.controller.ts:328
|
|||||||||
|
Delete registered cost endpoint for a project
Parameters :
Returns :
unknown
deleted endpoint or throws error |
| getConfiguredCosts | ||||||
getConfiguredCosts(providerName: string)
|
||||||
Decorators :
@Get('/providers/:providerName/llm/getConfiguredCosts')
|
||||||
|
Defined in src/cost/cost.controller.ts:105
|
||||||
|
Parameters :
Returns :
any
|
| Async getCost | ||||||||||||
getCost(projectID: number, query: QueryCostDto, request)
|
||||||||||||
Decorators :
@Get('/:projectID')
|
||||||||||||
|
Defined in src/cost/cost.controller.ts:373
|
||||||||||||
|
Function to get cost data based on input query params
Parameters :
Returns :
unknown
cost data for window |
| Async getCostEndpointDetails | ||||||
getCostEndpointDetails(id: number)
|
||||||
Decorators :
@Get('/endpoints/:id')
|
||||||
|
Defined in src/cost/cost.controller.ts:284
|
||||||
|
Get endpoint details by endpoint id without credentials
Parameters :
Returns :
unknown
cost endpoint |
| Async getCostEndpoints | |||||||||
getCostEndpoints(projectID: string, request)
|
|||||||||
Decorators :
@Get('/:projectID/endpoints')
|
|||||||||
|
Defined in src/cost/cost.controller.ts:399
|
|||||||||
|
List registered cost endpoints for input project ID
Parameters :
Returns :
unknown
List of cost endpoints with permissions on update/delete |
| Async getCostOverview | ||||
getCostOverview(request)
|
||||
Decorators :
@Get('/overview')
|
||||
|
Defined in src/cost/cost.controller.ts:352
|
||||
|
List projectwise cost incurred till date will only return cost for project user has access to
Parameters :
Returns :
unknown
|
| getResourcesByTags | ||||||
getResourcesByTags(fetchResourceDto: FetchResourcesDto)
|
||||||
Decorators :
@Post('/endpoints/getResourcesByTags')
|
||||||
|
Defined in src/cost/cost.controller.ts:187
|
||||||
|
Get resources based on tagList filter
Parameters :
Returns :
any
Get tags api response |
| Async getResourcesWithTagsForConnection | ||||||||||||
getResourcesWithTagsForConnection(id: number, tag: string)
|
||||||||||||
Decorators :
@Get('/endpoints/:id/getResourcesForTags/:tag')
|
||||||||||||
|
Defined in src/cost/cost.controller.ts:230
|
||||||||||||
|
Get resources from connection based on input connection id and tag. API can only filter one tag at a time due to aws provider limitation
Parameters :
Returns :
unknown
Get resource by tags api response |
| getTagKeys | ||||||
getTagKeys(fetchCostTagsDto: FetchCostTagsDto)
|
||||||
Decorators :
@Post('endpoints/getTagKeys')
|
||||||
|
Defined in src/cost/cost.controller.ts:124
|
||||||
|
Parameters :
Returns :
any
|
| Async getTagKeysForConnection | ||||||
getTagKeysForConnection(id: number)
|
||||||
Decorators :
@Post('endpoints/:id/getTagKeys')
|
||||||
|
Defined in src/cost/cost.controller.ts:142
|
||||||
|
Parameters :
Returns :
unknown
|
| getTagsData | ||||||
getTagsData(fetchCostTagsDto: FetchCostTagsDto)
|
||||||
Decorators :
@Post('/endpoints/getTagsData')
|
||||||
|
Defined in src/cost/cost.controller.ts:173
|
||||||
|
Get tags from connection based on input URL and credentials
Parameters :
Returns :
any
Get tags api response |
| Async getTagsForConnection | ||||||||
getTagsForConnection(id: number)
|
||||||||
Decorators :
@Get('/endpoints/:id/getTags')
|
||||||||
|
Defined in src/cost/cost.controller.ts:203
|
||||||||
|
Get tags from connection based on input connection id
Parameters :
Returns :
unknown
Get tags api response |
| getTagValuesForKey | ||||||
getTagValuesForKey(fetchCostTagsDto: FetchCostTagsDto)
|
||||||
Decorators :
@Post('endpoints/getTagValuesForKey')
|
||||||
|
Defined in src/cost/cost.controller.ts:133
|
||||||
|
Parameters :
Returns :
any
|
| Async getTagValuesForKeyForConnection |
getTagValuesForKeyForConnection(id: number, tag: string)
|
Decorators :
@Post('endpoints/:id/getTagValuesForKey/:tag')
|
|
Defined in src/cost/cost.controller.ts:152
|
|
Returns :
unknown
|
| listModels | ||||||
listModels(providerName: string)
|
||||||
Decorators :
@Get('/providers/:providerName/llm/models')
|
||||||
|
Defined in src/cost/cost.controller.ts:100
|
||||||
|
Parameters :
Returns :
any
|
| listProviders |
listProviders()
|
Decorators :
@Get('/providers')
|
|
Defined in src/cost/cost.controller.ts:95
|
|
Returns :
any
|
| Async pushCostMetrics | ||||||||
pushCostMetrics(metrics, costEndpointId, request)
|
||||||||
Decorators :
@Post('/endpoints/:id/metrics')
|
||||||||
|
Defined in src/cost/cost.controller.ts:249
|
||||||||
|
Parameters :
Returns :
unknown
|
| Async registerCostEndpoint | |||||||||
registerCostEndpoint(registerCostInput: RegisterCostEndpointDto, request)
|
|||||||||
Decorators :
@Post('/endpoints/')
|
|||||||||
|
Defined in src/cost/cost.controller.ts:54
|
|||||||||
|
Register cost endpoints in Turo
Parameters :
Returns :
unknown
registered cost endpoint or throw error |
| testConnection | ||||||
testConnection(testEndpointDto: TestEndpointDto)
|
||||||
Decorators :
@Post('/endpoints/test')
|
||||||
|
Defined in src/cost/cost.controller.ts:116
|
||||||
|
Test connection based on input URL and credentials
Parameters :
Returns :
any
test connection api response |
| Async updateCostEndpoint | ||||||||||||
updateCostEndpoint(id: number, updateCostInput: UpdateCostEndpointDto, request)
|
||||||||||||
Decorators :
@Post('/endpoints/:id')
|
||||||||||||
|
Defined in src/cost/cost.controller.ts:300
|
||||||||||||
|
Update registered cost endpoint for a project
Parameters :
Returns :
unknown
updated cost endpoint or throw error |
import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Post,
Query,
ValidationPipe,
Request,
UnauthorizedException,
UseInterceptors,
NotFoundException,
} from "@nestjs/common";
import { ApiBearerAuth } from "@nestjs/swagger";
import { QueryCostDto } from "./dto/query-cost.dto";
import { RegisterCostEndpointDto } from "./dto/register-cost-endpoint.dto";
import { TestEndpointDto } from "./dto/test-endpoint.dto";
import { CostService } from "./cost.service";
import { PolicyService } from "../iam";
import {
COST_CREATE_ACTION,
COST_DELETE_ACTION,
COST_PUSH_METRICS_ACTION,
COST_READ_ACTION,
COST_RESOURCE_NAME,
COST_UPDATE_ACTION,
} from "./cost.constants";
import { FetchCostTagsDto } from "./dto/fetch-cost-tag.dto";
import { FetchResourcesDto } from "./dto/fetch-resource.dto";
import { UpdateCostEndpointDto } from "./dto/update-cost-endpoint.dto";
import { OpentelemetryProvider } from "../providers/opentelemetry/opentelemetry.provider";
import { ProtobufInterceptor } from "../common/interceptors/protobuf.interceptor";
/**
* Controller responsible for handling requests related to turo cost operations.
*/
@ApiBearerAuth("access-token")
@Controller("cost")
export class CostController {
constructor(
private readonly costService: CostService,
private readonly policyService: PolicyService,
) {}
/**
* Register cost endpoints in Turo
* @param registerCostInput
* @param request
* @returns registered cost endpoint or throw error
*/
@Post("/endpoints/")
async registerCostEndpoint(
@Body(ValidationPipe) registerCostInput: RegisterCostEndpointDto,
@Request() request,
) {
if (
!(await this.policyService.checkPermission(
request.user.permission,
registerCostInput.projectID,
COST_RESOURCE_NAME,
COST_CREATE_ACTION,
))
) {
throw new UnauthorizedException();
}
return this.costService.registerCostEndpoint({
...registerCostInput,
config: registerCostInput.config as any,
});
}
/**
* Check if user token in request
* has permission to register an cost
* @param request
* @param projectId
* @returns boolean
*/
@Get("/:projectId/endpoints/hasCreatePermission")
canRegisterCostEndpoints(
@Request() request,
@Param("projectId") projectId: string,
) {
return this.policyService.checkPermission(
request.user.permission,
projectId,
COST_RESOURCE_NAME,
COST_CREATE_ACTION,
);
}
@Get("/providers")
listProviders() {
return this.costService.getCostProviderCategories();
}
@Get("/providers/:providerName/llm/models")
listModels(@Param("providerName") providerName: string) {
return this.costService.listModels(providerName);
}
@Get("/providers/:providerName/llm/getConfiguredCosts")
getConfiguredCosts(@Param("providerName") providerName: string) {
return this.costService.getConfiguredCosts(providerName);
}
/**
* Test connection based on input URL and
* credentials
* @param testEndpointDto
* @returns test connection api response
*/
@Post("/endpoints/test")
testConnection(@Body(ValidationPipe) testEndpointDto: TestEndpointDto) {
return this.costService.testConnection(
testEndpointDto.config,
testEndpointDto.provider,
);
}
@Post("endpoints/getTagKeys")
getTagKeys(@Body(ValidationPipe) fetchCostTagsDto: FetchCostTagsDto) {
return this.costService.getTagKeys(
fetchCostTagsDto.config,
fetchCostTagsDto.provider,
fetchCostTagsDto.getTagsInput,
);
}
@Post("endpoints/getTagValuesForKey")
getTagValuesForKey(@Body(ValidationPipe) fetchCostTagsDto: FetchCostTagsDto) {
return this.costService.getTagValuesForKey(
fetchCostTagsDto.config,
fetchCostTagsDto.provider,
fetchCostTagsDto.getTagsInput,
);
}
@Post("endpoints/:id/getTagKeys")
async getTagKeysForConnection(@Param("id", new ParseIntPipe()) id: number) {
const endpoint = await this.costService.getCostEndpointDetails(id);
return this.costService.getTagKeys(
endpoint.config,
endpoint.endpointType,
{},
);
}
@Post("endpoints/:id/getTagValuesForKey/:tag")
async getTagValuesForKeyForConnection(
@Param("id", new ParseIntPipe()) id: number,
@Param("tag") tag: string,
) {
const endpoint = await this.costService.getCostEndpointDetails(id);
return this.costService.getTagValuesForKey(
endpoint.config,
endpoint.endpointType,
{
Key: decodeURIComponent(tag),
},
);
}
/**
* Get tags from connection based on input URL and
* credentials
* @param fetchCostTagsDto
* @returns Get tags api response
*/
@Post("/endpoints/getTagsData")
getTagsData(@Body(ValidationPipe) fetchCostTagsDto: FetchCostTagsDto) {
return this.costService.getTagsData(
fetchCostTagsDto.config,
fetchCostTagsDto.provider,
fetchCostTagsDto.getTagsInput,
);
}
/**
* Get resources based on tagList filter
* @param fetchResourceDto
* @returns Get tags api response
*/
@Post("/endpoints/getResourcesByTags")
getResourcesByTags(
@Body(ValidationPipe) fetchResourceDto: FetchResourcesDto,
) {
return this.costService.getResourcesByTags(
fetchResourceDto.config,
fetchResourceDto.provider,
fetchResourceDto.tagList,
);
}
/**
* Get tags from connection based on input connection id
* @param id connection id
* @returns Get tags api response
*/
@Get("/endpoints/:id/getTags")
async getTagsForConnection(@Param("id", new ParseIntPipe()) id: number) {
const endpoint = await this.costService.getCostEndpointDetails(id);
const today = new Date();
const dayBeforeYesterdate = new Date(today);
dayBeforeYesterdate.setDate(today.getDate() - 2);
return this.costService.getTagsData(
endpoint.config,
endpoint.endpointType,
{
TimePeriod: {
End: today.toISOString().split("T")[0], // Today's date in "YYYY-MM-DD" format
Start: dayBeforeYesterdate.toISOString().split("T")[0], // Yesterday's date in "YYYY-MM-DD" format
},
},
);
}
/**
* Get resources from connection based on input connection id and
* tag.
* API can only filter one tag at a time due to aws provider limitation
* @param id connection id
* @param tag tag key value pair eg: key:Value1
* @returns Get resource by tags api response
*/
@Get("/endpoints/:id/getResourcesForTags/:tag")
async getResourcesWithTagsForConnection(
@Param("id", new ParseIntPipe()) id: number,
@Param("tag") tag: string,
) {
const endpoint = await this.costService.getCostEndpointDetails(id);
return this.costService.getResourcesByTags(
endpoint.config,
endpoint.endpointType,
[tag],
);
}
@Post("/endpoints/:id/metrics")
@UseInterceptors(
new ProtobufInterceptor(
OpentelemetryProvider.METRICS_PROTO_PATH,
OpentelemetryProvider.METRICS_PROTO_MESSAGE_NAME,
),
)
async pushCostMetrics(
@Body() metrics,
@Param("id") costEndpointId,
@Request() request,
) {
const costEndpoint =
await this.costService.getCostEndpointDetails(+costEndpointId);
if (!costEndpoint) {
throw new NotFoundException("cost endpoint with ID not found");
}
if (
!(await this.policyService.checkPermission(
request.user.permission,
costEndpoint.projectID,
COST_RESOURCE_NAME,
COST_PUSH_METRICS_ACTION,
))
) {
throw new UnauthorizedException();
}
console.log("Metrics received for cost endpoint: ", costEndpointId);
console.log("Request headers: ", request.headers);
console.log(JSON.stringify(metrics, null, 2));
return this.costService.pushCostMetrics(metrics, costEndpoint);
}
/**
* Get endpoint details by endpoint id without credentials
* @param id
* @returns cost endpoint
*/
@Get("/endpoints/:id")
async getCostEndpointDetails(@Param("id", new ParseIntPipe()) id: number) {
const endpoint = await this.costService.getCostEndpointDetails(id);
const provider = this.costService.getCostProvider(endpoint.endpointType);
endpoint.config = provider.maskConfigSecret(endpoint.config);
return endpoint;
}
/**
* Update registered cost endpoint for
* a project
* @param id
* @param updateCostInput
* @param request
* @returns updated cost endpoint or throw error
*/
@Post("/endpoints/:id")
async updateCostEndpoint(
@Param("id", new ParseIntPipe()) id: number,
@Body(ValidationPipe) updateCostInput: UpdateCostEndpointDto,
@Request() request,
) {
if (
!(await this.policyService.checkPermission(
request.user.permission,
id,
COST_RESOURCE_NAME,
COST_UPDATE_ACTION,
))
) {
throw new UnauthorizedException();
}
return this.costService.updateCostEndpoint(id, {
...updateCostInput,
config: updateCostInput.config as any,
});
}
/**
* Delete registered cost endpoint for a project
* @param id
* @param request
* @returns deleted endpoint or throws error
*/
@Delete("/endpoints/:id")
async deleteCostEndpoint(
@Param("id", new ParseIntPipe()) id: number,
@Request() request,
) {
const costEndpoint = await this.costService.getCostEndpointDetails(id);
if (
!(await this.policyService.checkPermission(
request.user.permission,
costEndpoint.projectID,
COST_RESOURCE_NAME,
COST_DELETE_ACTION,
))
) {
throw new UnauthorizedException();
}
return this.costService.deleteCostEndpoint(id);
}
/**
* List projectwise cost incurred till date
* will only return cost for project user has access to
* @param request
*/
@Get("/overview")
async getCostOverview(@Request() request) {
const costs = await this.costService.getCostOverview();
return costs.filter((cost) => {
return this.policyService.checkPermission(
request.user.permission,
cost.projectId,
COST_RESOURCE_NAME,
COST_READ_ACTION,
);
});
}
/**
* Function to get cost data based on
* input query params
* @param projectID
* @param query
* @param request
* @returns cost data for window
*/
@Get("/:projectID")
async getCost(
@Param("projectID", new ParseIntPipe()) projectID: number,
@Query() query: QueryCostDto,
@Request() request,
) {
if (
!(await this.policyService.checkPermission(
request.user.permission,
projectID,
COST_RESOURCE_NAME,
COST_READ_ACTION,
))
) {
throw new UnauthorizedException();
}
return this.costService.getCost(projectID, query.window);
}
/**
* List registered cost endpoints for
* input project ID
* @param projectID
* @param request
* @returns List of cost endpoints with permissions on update/delete
*/
@Get("/:projectID/endpoints")
async getCostEndpoints(
@Param("projectID", new ParseIntPipe()) projectID: string,
@Request() request,
) {
if (
!(await this.policyService.checkPermission(
request.user.permission,
projectID,
COST_RESOURCE_NAME,
COST_READ_ACTION,
))
) {
throw new UnauthorizedException();
}
const costEndpoints = await this.costService.getCostEndpoint(projectID);
return costEndpoints.map((costEndpoint) => {
const [canUpdate, canDelete] = [
this.policyService.checkPermission(
request.user.permission,
costEndpoint.projectID,
COST_RESOURCE_NAME,
COST_UPDATE_ACTION,
),
this.policyService.checkPermission(
request.user.permission,
costEndpoint.projectID,
COST_RESOURCE_NAME,
COST_DELETE_ACTION,
),
];
return { ...costEndpoint, update: canUpdate, delete: canDelete };
});
}
}