This is an automated email from the ASF dual-hosted git repository. ofuks pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
The following commit(s) were added to refs/heads/develop by this push: new 1759f9e [DLAB-1714] BE created notification in case project quota is exceeded 1759f9e is described below commit 1759f9eefbf7868381edece6a3eb265267b77f45 Author: Oleh Fuks <olegfuk...@gmail.com> AuthorDate: Fri Jul 17 18:05:47 2020 +0300 [DLAB-1714] BE created notification in case project quota is exceeded --- .../epam/dlab/backendapi/dao/BaseBillingDAO.java | 28 +------------ .../com/epam/dlab/backendapi/dao/BillingDAO.java | 8 +--- .../interceptor/BudgetLimitInterceptor.java | 5 ++- .../dlab/backendapi/resources/BillingResource.java | 8 ++++ .../resources/dto/HealthStatusPageDTO.java | 4 -- .../dto/QuotaUsageDTO.java} | 22 ++++------ .../schedulers/CheckProjectQuoteScheduler.java | 6 +-- .../dlab/backendapi/service/BillingService.java | 15 +++++-- .../service/impl/BillingServiceImpl.java | 48 +++++++++++++++++++++- .../impl/InfrastructureInfoServiceImpl.java | 11 ++--- 10 files changed, 89 insertions(+), 66 deletions(-) diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java index 0e21bba..7975eeb 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java @@ -20,10 +20,8 @@ package com.epam.dlab.backendapi.dao; import com.epam.dlab.backendapi.domain.BillingReportLine; -import com.epam.dlab.backendapi.domain.BudgetDTO; import com.epam.dlab.backendapi.resources.dto.BillingFilter; import com.epam.dlab.dto.billing.BillingResourceType; -import com.epam.dlab.exceptions.ResourceNotFoundException; import com.google.inject.Inject; import com.mongodb.client.model.Aggregates; import com.mongodb.client.model.Filters; @@ -101,14 +99,14 @@ public class BaseBillingDAO extends BaseDAO implements BillingDAO { } @Override - public Double getProjectCost(String project) { + public Double getOverallProjectCost(String project) { final List<Bson> pipeline = Arrays.asList(match(eq(PROJECT, project)), group(null, sum(TOTAL_FIELD_NAME, COST_FIELD))); return aggregateBillingData(pipeline); } @Override - public Double getProjectCost(String project, LocalDate date) { + public Double getMonthlyProjectCost(String project, LocalDate date) { final List<Bson> pipeline = Arrays.asList(match( and( eq(PROJECT, project), @@ -143,28 +141,10 @@ public class BaseBillingDAO extends BaseDAO implements BillingDAO { } @Override - public boolean isProjectQuoteReached(String project) { - final boolean monthlyBudget = Optional.ofNullable(projectDAO.get(project) - .orElseThrow(projectNotFound()) - .getBudget()) - .map(BudgetDTO::isMonthlyBudget) - .orElse(Boolean.FALSE); - final Double projectCost = monthlyBudget ? getProjectCost(project, LocalDate.now()) : getProjectCost(project); - return projectDAO.getAllowedBudget(project) - .filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost) - .isPresent(); - } - - @Override public List<BillingReportLine> findBillingData(String project, String endpoint, List<String> resourceNames) { return find(BILLING, and(eq(PROJECT, project), eq(ENDPOINT, endpoint), in(RESOURCE_NAME, resourceNames)), BillingReportLine.class); } - @Override - public int getBillingProjectQuoteUsed(String project) { - return toPercentage(() -> projectDAO.getAllowedBudget(project), getProjectCost(project)); - } - public List<BillingReportLine> aggregateBillingData(BillingFilter filter) { List<Bson> pipeline = new ArrayList<>(); List<Bson> matchCriteria = matchCriteria(filter); @@ -262,8 +242,4 @@ public class BaseBillingDAO extends BaseDAO implements BillingDAO { .currency(id.getString(CURRENCY)) .build(); } - - private Supplier<ResourceNotFoundException> projectNotFound() { - return () -> new ResourceNotFoundException("Project with passed name not found"); - } } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java index da1c9a7..088c319 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java @@ -29,22 +29,18 @@ public interface BillingDAO { Double getUserCost(String user); - Double getProjectCost(String project); + Double getOverallProjectCost(String project); - Double getProjectCost(String project, LocalDate date); + Double getMonthlyProjectCost(String project, LocalDate date); int getBillingQuoteUsed(); int getBillingUserQuoteUsed(String user); - int getBillingProjectQuoteUsed(String project); - boolean isBillingQuoteReached(); boolean isUserQuoteReached(String user); - boolean isProjectQuoteReached(String project); - List<BillingReportLine> findBillingData(String project, String endpoint, List<String> resourceNames); List<BillingReportLine> aggregateBillingData(BillingFilter filter); diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java index 43fdaf6..ce32e10 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java @@ -22,6 +22,7 @@ package com.epam.dlab.backendapi.interceptor; import com.epam.dlab.auth.UserInfo; import com.epam.dlab.backendapi.annotation.Project; import com.epam.dlab.backendapi.dao.BillingDAO; +import com.epam.dlab.backendapi.service.BillingService; import com.epam.dlab.exceptions.ResourceQuoteReachedException; import com.google.inject.Inject; import lombok.extern.slf4j.Slf4j; @@ -38,6 +39,8 @@ import java.util.stream.IntStream; public class BudgetLimitInterceptor implements MethodInterceptor { @Inject private BillingDAO billingDAO; + @Inject + private BillingService billingService; @Override public Object invoke(MethodInvocation mi) throws Throwable { @@ -66,7 +69,7 @@ public class BudgetLimitInterceptor implements MethodInterceptor { .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class))) .mapToObj(i -> (String) mi.getArguments()[i]) .findAny() - .map(billingDAO::isProjectQuoteReached) + .map(billingService::isProjectQuoteReached) .orElse(Boolean.FALSE); } } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java index 1916a38..a03edb3 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java @@ -28,6 +28,7 @@ import io.dropwizard.auth.Auth; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; +import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -46,6 +47,13 @@ public class BillingResource { this.billingService = billingService; } + @GET + @Path("/quota") + @Produces(MediaType.APPLICATION_JSON) + public Response getQuota(@Auth UserInfo userInfo) { + return Response.ok(billingService.getQuotas(userInfo)).build(); + } + @POST @Path("/report") @Produces(MediaType.APPLICATION_JSON) diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java index 642dd06..73fd421 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java @@ -44,10 +44,6 @@ public class HealthStatusPageDTO { @JsonProperty private boolean projectAdmin; @JsonProperty - private int billingQuoteUsed; - @JsonProperty - private int billingUserQuoteUsed; - @JsonProperty private boolean projectAssigned; @JsonProperty private BucketBrowser bucketBrowser; diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/QuotaUsageDTO.java similarity index 58% copy from services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java copy to services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/QuotaUsageDTO.java index b76b141..e611091 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/QuotaUsageDTO.java @@ -17,20 +17,16 @@ * under the License. */ -package com.epam.dlab.backendapi.service; +package com.epam.dlab.backendapi.resources.dto; -import com.epam.dlab.auth.UserInfo; -import com.epam.dlab.backendapi.domain.BillingReport; -import com.epam.dlab.backendapi.resources.dto.BillingFilter; +import lombok.Builder; +import lombok.Data; -import java.util.List; +import java.util.Map; -public interface BillingService { - BillingReport getBillingReport(UserInfo userInfo, BillingFilter filter); - - String downloadReport(UserInfo userInfo, BillingFilter filter); - - BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames); - - void updateRemoteBillingData(UserInfo userInfo); +@Data +@Builder +public class QuotaUsageDTO { + private int totalQuotaUsed; + private Map<String, Integer> projectQuotas; } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java index 030c10d..2dc499f 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java @@ -19,9 +19,9 @@ package com.epam.dlab.backendapi.schedulers; -import com.epam.dlab.backendapi.dao.BillingDAO; import com.epam.dlab.backendapi.domain.ProjectDTO; import com.epam.dlab.backendapi.schedulers.internal.Scheduled; +import com.epam.dlab.backendapi.service.BillingService; import com.epam.dlab.backendapi.service.EnvironmentService; import com.epam.dlab.backendapi.service.ProjectService; import com.google.inject.Inject; @@ -34,7 +34,7 @@ import org.quartz.JobExecutionContext; public class CheckProjectQuoteScheduler implements Job { @Inject - private BillingDAO billingDAO; + private BillingService billingService; @Inject private EnvironmentService environmentService; @Inject @@ -45,7 +45,7 @@ public class CheckProjectQuoteScheduler implements Job { projectService.getProjects() .stream() .map(ProjectDTO::getName) - .filter(billingDAO::isProjectQuoteReached) + .filter(billingService::isProjectQuoteReached) .peek(p -> log.debug("Stopping {} project env because of reaching user billing quote", p)) .forEach(environmentService::stopProjectEnvironment); } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java index b76b141..7291cc7 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java @@ -22,15 +22,22 @@ package com.epam.dlab.backendapi.service; import com.epam.dlab.auth.UserInfo; import com.epam.dlab.backendapi.domain.BillingReport; import com.epam.dlab.backendapi.resources.dto.BillingFilter; +import com.epam.dlab.backendapi.resources.dto.QuotaUsageDTO; import java.util.List; public interface BillingService { - BillingReport getBillingReport(UserInfo userInfo, BillingFilter filter); + BillingReport getBillingReport(UserInfo userInfo, BillingFilter filter); - String downloadReport(UserInfo userInfo, BillingFilter filter); + String downloadReport(UserInfo userInfo, BillingFilter filter); - BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames); + BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames); - void updateRemoteBillingData(UserInfo userInfo); + void updateRemoteBillingData(UserInfo userInfo); + + QuotaUsageDTO getQuotas(UserInfo userInfo); + + boolean isProjectQuoteReached(String project); + + int getBillingProjectQuoteUsed(String project); } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java index c0b9aa2..2bcf644 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java @@ -23,12 +23,15 @@ import com.epam.dlab.auth.UserInfo; import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration; import com.epam.dlab.backendapi.dao.BillingDAO; import com.epam.dlab.backendapi.dao.ImageExploratoryDao; +import com.epam.dlab.backendapi.dao.ProjectDAO; import com.epam.dlab.backendapi.domain.BillingReport; import com.epam.dlab.backendapi.domain.BillingReportLine; +import com.epam.dlab.backendapi.domain.BudgetDTO; import com.epam.dlab.backendapi.domain.EndpointDTO; import com.epam.dlab.backendapi.domain.ProjectDTO; import com.epam.dlab.backendapi.domain.ProjectEndpointDTO; import com.epam.dlab.backendapi.resources.dto.BillingFilter; +import com.epam.dlab.backendapi.resources.dto.QuotaUsageDTO; import com.epam.dlab.backendapi.roles.RoleType; import com.epam.dlab.backendapi.roles.UserRoles; import com.epam.dlab.backendapi.service.BillingService; @@ -63,7 +66,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -73,6 +78,7 @@ public class BillingServiceImpl implements BillingService { private static final String USAGE_DATE_FORMAT = "yyyy-MM"; private final ProjectService projectService; + private final ProjectDAO projectDAO; private final EndpointService endpointService; private final ExploratoryService exploratoryService; private final SelfServiceApplicationConfiguration configuration; @@ -82,11 +88,12 @@ public class BillingServiceImpl implements BillingService { private final String sbn; @Inject - public BillingServiceImpl(ProjectService projectService, EndpointService endpointService, + public BillingServiceImpl(ProjectService projectService, ProjectDAO projectDAO, EndpointService endpointService, ExploratoryService exploratoryService, SelfServiceApplicationConfiguration configuration, @Named(ServiceConsts.BILLING_SERVICE_NAME) RESTService provisioningService, ImageExploratoryDao imageExploratoryDao, BillingDAO billingDAO) { this.projectService = projectService; + this.projectDAO = projectDAO; this.endpointService = endpointService; this.exploratoryService = exploratoryService; this.configuration = configuration; @@ -176,6 +183,38 @@ public class BillingServiceImpl implements BillingService { }); } + @Override + public QuotaUsageDTO getQuotas(UserInfo userInfo) { + int totalQuota = billingDAO.getBillingQuoteUsed(); + Map<String, Integer> projectQuotas = projectService.getProjects(userInfo) + .stream() + .collect(Collectors.toMap(ProjectDTO::getName, p -> getBillingProjectQuoteUsed(p.getName()))); + return QuotaUsageDTO.builder() + .totalQuotaUsed(totalQuota) + .projectQuotas(projectQuotas) + .build(); + } + + @Override + public boolean isProjectQuoteReached(String project) { + final Double projectCost = getProjectCost(project); + return projectDAO.getAllowedBudget(project) + .filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost) + .isPresent(); + } + + @Override + public int getBillingProjectQuoteUsed(String project) { + return toPercentage(() -> projectDAO.getAllowedBudget(project), getProjectCost(project)); + } + + private Double getProjectCost(String project) { + final boolean monthlyBudget = Optional.ofNullable(projectService.get(project).getBudget()) + .map(BudgetDTO::isMonthlyBudget) + .orElse(Boolean.FALSE); + return monthlyBudget ? billingDAO.getMonthlyProjectCost(project, LocalDate.now()) : billingDAO.getOverallProjectCost(project); + } + private Map<String, BillingReportLine> getBillableResources() { Set<ProjectDTO> projects = new HashSet<>(projectService.getProjects()); final Stream<BillingReportLine> ssnBillingDataStream = BillingUtils.ssnBillingDataStream(sbn); @@ -341,4 +380,11 @@ public class BillingServiceImpl implements BillingService { .exploratoryName(billingReportLine.getExploratoryName()) .build(); } + + private Integer toPercentage(Supplier<Optional<Integer>> allowedBudget, Double totalCost) { + return allowedBudget.get() + .map(userBudget -> (totalCost * 100) / userBudget) + .map(Double::intValue) + .orElse(BigDecimal.ZERO.intValue()); + } } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java index 475f2db..98c2f6d 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java @@ -21,7 +21,6 @@ package com.epam.dlab.backendapi.service.impl; import com.epam.dlab.auth.UserInfo; import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration; -import com.epam.dlab.backendapi.dao.BillingDAO; import com.epam.dlab.backendapi.dao.ExploratoryDAO; import com.epam.dlab.backendapi.domain.BillingReport; import com.epam.dlab.backendapi.domain.EndpointDTO; @@ -65,18 +64,16 @@ public class InfrastructureInfoServiceImpl implements InfrastructureInfoService private final ExploratoryDAO expDAO; private final SelfServiceApplicationConfiguration configuration; - private final BillingDAO billingDAO; private final ProjectService projectService; private final EndpointService endpointService; private final BillingService billingService; @Inject public InfrastructureInfoServiceImpl(ExploratoryDAO expDAO, SelfServiceApplicationConfiguration configuration, - BillingDAO billingDAO, ProjectService projectService, EndpointService endpointService, - BillingService billingService) { + ProjectService projectService, EndpointService endpointService, + BillingService billingService) { this.expDAO = expDAO; this.configuration = configuration; - this.billingDAO = billingDAO; this.projectService = projectService; this.endpointService = endpointService; this.billingService = billingService; @@ -91,7 +88,7 @@ public class InfrastructureInfoServiceImpl implements InfrastructureInfoService .stream() .map(p -> { List<UserInstanceDTO> exploratories = expDAO.findExploratories(user.getName(), p.getName()); - return new ProjectInfrastructureInfo(p.getName(), billingDAO.getBillingProjectQuoteUsed(p.getName()), + return new ProjectInfrastructureInfo(p.getName(), billingService.getBillingProjectQuoteUsed(p.getName()), getSharedInfo(p.getName()), exploratories, getExploratoryBillingData(exploratories), getEndpoints(allEndpoints, p)); }) @@ -115,8 +112,6 @@ public class InfrastructureInfoServiceImpl implements InfrastructureInfoService .projectAdmin(UserRoles.isProjectAdmin(userInfo)) .admin(UserRoles.isAdmin(userInfo)) .projectAssigned(projectService.isAnyProjectAssigned(userInfo)) - .billingQuoteUsed(billingDAO.getBillingQuoteUsed()) - .billingUserQuoteUsed(billingDAO.getBillingUserQuoteUsed(user)) .bucketBrowser(HealthStatusPageDTO.BucketBrowser.builder() .view(checkAccess(userInfo, PERMISSION_VIEW)) .upload(checkAccess(userInfo, PERMISSION_UPLOAD)) --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@dlab.apache.org For additional commands, e-mail: commits-h...@dlab.apache.org