blob: 4a51272fdc162765882f7b29215164d419d612f3 [file] [log] [blame]
/*
*
* * Copyright (c) 2018, EPAM SYSTEMS INC
* *
* * 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 com.epam.dlab.backendapi.dao.gcp;
import com.epam.dlab.auth.UserInfo;
import com.epam.dlab.backendapi.dao.BaseBillingDAO;
import com.epam.dlab.backendapi.resources.dto.gcp.GcpBillingFilter;
import com.epam.dlab.backendapi.roles.RoleType;
import com.epam.dlab.backendapi.roles.UserRoles;
import com.epam.dlab.billing.BillingCalculationUtils;
import com.epam.dlab.billing.DlabResourceType;
import com.epam.dlab.dto.UserInstanceStatus;
import com.mongodb.client.AggregateIterable;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.conversions.Bson;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static com.epam.dlab.MongoKeyWords.*;
import static com.epam.dlab.backendapi.dao.MongoCollections.BILLING;
import static com.epam.dlab.backendapi.dao.aws.AwsBillingDAO.DLAB_RESOURCE_TYPE;
import static com.epam.dlab.backendapi.dao.aws.AwsBillingDAO.TAG_RESOURCE_ID;
import static com.epam.dlab.model.aws.ReportLine.*;
import static com.mongodb.client.model.Accumulators.*;
import static com.mongodb.client.model.Aggregates.*;
import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.in;
public class GcpBillingDao extends BaseBillingDAO<GcpBillingFilter> {
@Override
public Double getTotalCost() {
return null;
}
@Override
public Double getUserCost(String user) {
return null;
}
@Override
public int getBillingQuoteUsed() {
return 0;
}
@Override
public int getBillingUserQuoteUsed(String user) {
return 0;
}
@Override
public boolean isBillingQuoteReached() {
return false;
}
@Override
public boolean isUserQuoteReached(String user) {
return false;
}
@Override
protected void appendSsnAndEdgeNodeType(List<String> shapeNames, Map<String, ShapeInfo> shapes) {
}
public Document getReport(UserInfo userInfo, GcpBillingFilter filter) {
// Create filter
List<Bson> conditions = new ArrayList<>();
boolean isFullReport = UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing");
setUserFilter(userInfo, filter, isFullReport);
addCondition(conditions, USER, filter.getUser());
addCondition(conditions, FIELD_PRODUCT, filter.getProduct());
// Create aggregation conditions
List<Bson> pipeline = new ArrayList<>();
if (!conditions.isEmpty()) {
pipeline.add(match(and(conditions)));
}
pipeline.add(
group(getGroupingFields(USER, FIELD_DLAB_ID, DLAB_RESOURCE_TYPE, FIELD_PRODUCT, FIELD_RESOURCE_TYPE,
FIELD_CURRENCY_CODE),
sum(FIELD_COST, "$" + FIELD_COST),
min(USAGE_FROM, "$" + FIELD_USAGE_DATE),
max(USAGE_TO, "$" + FIELD_USAGE_DATE)
));
pipeline.add(
sort(new Document(ID + "." + USER, 1)
.append(ID + "." + FIELD_DLAB_ID, 1)
.append(ID + "." + RESOURCE_TYPE, 1)
.append(ID + "." + FIELD_PRODUCT, 1))
);
// Get billing report and the list of shape info
AggregateIterable<Document> agg = getCollection(BILLING).aggregate(pipeline);
Map<String, ShapeInfo> shapes = getShapes(filter.getShape());
// Build billing report lines
List<Document> reportItems = new ArrayList<>();
boolean filterByShape = !(filter.getShape() == null || filter.getShape().isEmpty());
String usageDateStart = null;
String usageDateEnd = null;
double costTotal = 0;
for (Document d : agg) {
Document id = (Document) d.get(ID);
String resourceId = id.getString(FIELD_DLAB_ID);
ShapeInfo shape = shapes.get(resourceId);
final UserInstanceStatus status = Optional.ofNullable(shape).map(ShapeInfo::getStatus).orElse(null);
if ((filterByShape && shape == null) || (!filter.getStatuses().isEmpty() && filter.getStatuses().stream()
.noneMatch(s -> s.equals(status)))) {
continue;
}
String resourceTypeId = DlabResourceType.getResourceTypeName(id.getString(DLAB_RESOURCE_TYPE));
String shapeName = generateShapeName(shape);
String dateStart = d.getString(USAGE_FROM);
if (StringUtils.compare(usageDateStart, dateStart, false) > 0) {
usageDateStart = dateStart;
}
String dateEnd = d.getString(USAGE_TO);
if (StringUtils.compare(usageDateEnd, dateEnd) < 0) {
usageDateEnd = dateEnd;
}
double cost = BillingCalculationUtils.round(d.getDouble(FIELD_COST), 2);
costTotal += cost;
Document item = new Document()
.append(FIELD_USER_ID, getUserOrDefault(id.getString(USER)))
.append(FIELD_DLAB_ID, resourceId)
.append(DLAB_RESOURCE_TYPE, resourceTypeId)
.append(SHAPE, shapeName)
.append(STATUS,
Optional.ofNullable(status).map(UserInstanceStatus::toString).orElse(StringUtils.EMPTY))
.append(FIELD_PRODUCT, id.getString(FIELD_PRODUCT))
.append(FIELD_RESOURCE_TYPE, id.getString(FIELD_RESOURCE_TYPE))
.append(FIELD_COST, BillingCalculationUtils.formatDouble(cost))
.append(FIELD_CURRENCY_CODE, id.getString(FIELD_CURRENCY_CODE))
.append(USAGE_FROM, dateStart)
.append(USAGE_TO, dateEnd);
reportItems.add(item);
}
return new Document()
.append(SERVICE_BASE_NAME, settings.getServiceBaseName())
.append(TAG_RESOURCE_ID, settings.getConfTagResourceId())
.append(USAGE_FROM, usageDateStart)
.append(USAGE_TO, usageDateEnd)
.append(ITEMS, reportItems)
.append(COST_TOTAL, BillingCalculationUtils.formatDouble(BillingCalculationUtils.round(costTotal, 2)))
.append(FIELD_CURRENCY_CODE, (reportItems.isEmpty() ? null :
reportItems.get(0).getString(FIELD_CURRENCY_CODE)))
.append(FULL_REPORT, isFullReport);
}
private void addCondition(List<Bson> conditions, String fieldName, List<String> values) {
if (values != null && !values.isEmpty()) {
conditions.add(in(fieldName, values));
}
}
}